mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 12:25:20 +00:00
feat: forward upstream OpenAI errors
This commit is contained in:
parent
9af64f0db1
commit
2ae7584686
1 changed files with 59 additions and 57 deletions
|
|
@ -2,17 +2,15 @@ import asyncio
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from typing import Optional
|
||||||
from typing import Literal, Optional, overload
|
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiocache import cached
|
from aiocache import cached
|
||||||
import requests
|
import requests
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
|
|
||||||
from fastapi import Depends, FastAPI, HTTPException, Request, APIRouter
|
from fastapi import Depends, HTTPException, Request, APIRouter
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.responses import FileResponse, StreamingResponse, JSONResponse, PlainTextResponse
|
||||||
from fastapi.responses import FileResponse, StreamingResponse
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from starlette.background import BackgroundTask
|
from starlette.background import BackgroundTask
|
||||||
|
|
||||||
|
|
@ -31,7 +29,7 @@ from open_webui.env import (
|
||||||
from open_webui.models.users import UserModel
|
from open_webui.models.users import UserModel
|
||||||
|
|
||||||
from open_webui.constants import ERROR_MESSAGES
|
from open_webui.constants import ERROR_MESSAGES
|
||||||
from open_webui.env import ENV, SRC_LOG_LEVELS
|
from open_webui.env import SRC_LOG_LEVELS
|
||||||
|
|
||||||
|
|
||||||
from open_webui.utils.payload import (
|
from open_webui.utils.payload import (
|
||||||
|
|
@ -595,15 +593,17 @@ async def verify_connection(
|
||||||
headers=headers,
|
headers=headers,
|
||||||
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as r:
|
) as r:
|
||||||
if r.status != 200:
|
try:
|
||||||
# Extract response error details if available
|
|
||||||
error_detail = f"HTTP Error: {r.status}"
|
|
||||||
res = await r.json()
|
|
||||||
if "error" in res:
|
|
||||||
error_detail = f"External Error: {res['error']}"
|
|
||||||
raise Exception(error_detail)
|
|
||||||
|
|
||||||
response_data = await r.json()
|
response_data = await r.json()
|
||||||
|
except Exception:
|
||||||
|
response_data = await r.text()
|
||||||
|
|
||||||
|
if r.status != 200:
|
||||||
|
if isinstance(response_data, (dict, list)):
|
||||||
|
return JSONResponse(status_code=r.status, content=response_data)
|
||||||
|
else:
|
||||||
|
return PlainTextResponse(status_code=r.status, content=response_data)
|
||||||
|
|
||||||
return response_data
|
return response_data
|
||||||
else:
|
else:
|
||||||
headers["Authorization"] = f"Bearer {key}"
|
headers["Authorization"] = f"Bearer {key}"
|
||||||
|
|
@ -613,15 +613,17 @@ async def verify_connection(
|
||||||
headers=headers,
|
headers=headers,
|
||||||
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
) as r:
|
) as r:
|
||||||
if r.status != 200:
|
try:
|
||||||
# Extract response error details if available
|
|
||||||
error_detail = f"HTTP Error: {r.status}"
|
|
||||||
res = await r.json()
|
|
||||||
if "error" in res:
|
|
||||||
error_detail = f"External Error: {res['error']}"
|
|
||||||
raise Exception(error_detail)
|
|
||||||
|
|
||||||
response_data = await r.json()
|
response_data = await r.json()
|
||||||
|
except Exception:
|
||||||
|
response_data = await r.text()
|
||||||
|
|
||||||
|
if r.status != 200:
|
||||||
|
if isinstance(response_data, (dict, list)):
|
||||||
|
return JSONResponse(status_code=r.status, content=response_data)
|
||||||
|
else:
|
||||||
|
return PlainTextResponse(status_code=r.status, content=response_data)
|
||||||
|
|
||||||
return response_data
|
return response_data
|
||||||
|
|
||||||
except aiohttp.ClientError as e:
|
except aiohttp.ClientError as e:
|
||||||
|
|
@ -632,8 +634,9 @@ async def verify_connection(
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(f"Unexpected error: {e}")
|
log.exception(f"Unexpected error: {e}")
|
||||||
error_detail = f"Unexpected error: {str(e)}"
|
raise HTTPException(
|
||||||
raise HTTPException(status_code=500, detail=error_detail)
|
status_code=500, detail="Open WebUI: Server Connection Error"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_azure_allowed_params(api_version: str) -> set[str]:
|
def get_azure_allowed_params(api_version: str) -> set[str]:
|
||||||
|
|
@ -883,21 +886,19 @@ async def generate_chat_completion(
|
||||||
log.error(e)
|
log.error(e)
|
||||||
response = await r.text()
|
response = await r.text()
|
||||||
|
|
||||||
r.raise_for_status()
|
if r.status >= 400:
|
||||||
|
if isinstance(response, (dict, list)):
|
||||||
|
return JSONResponse(status_code=r.status, content=response)
|
||||||
|
else:
|
||||||
|
return PlainTextResponse(status_code=r.status, content=response)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
|
||||||
detail = None
|
|
||||||
if isinstance(response, dict):
|
|
||||||
if "error" in response:
|
|
||||||
detail = f"{response['error']['message'] if 'message' in response['error'] else response['error']}"
|
|
||||||
elif isinstance(response, str):
|
|
||||||
detail = response
|
|
||||||
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=r.status if r else 500,
|
status_code=r.status if r else 500,
|
||||||
detail=detail if detail else "Open WebUI: Server Connection Error",
|
detail="Open WebUI: Server Connection Error",
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
if not streaming:
|
if not streaming:
|
||||||
|
|
@ -951,7 +952,7 @@ async def embeddings(request: Request, form_data: dict, user):
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
r.raise_for_status()
|
|
||||||
if "text/event-stream" in r.headers.get("Content-Type", ""):
|
if "text/event-stream" in r.headers.get("Content-Type", ""):
|
||||||
streaming = True
|
streaming = True
|
||||||
return StreamingResponse(
|
return StreamingResponse(
|
||||||
|
|
@ -963,21 +964,23 @@ async def embeddings(request: Request, form_data: dict, user):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
response_data = await r.json()
|
response_data = await r.json()
|
||||||
|
except Exception:
|
||||||
|
response_data = await r.text()
|
||||||
|
|
||||||
|
if r.status >= 400:
|
||||||
|
if isinstance(response_data, (dict, list)):
|
||||||
|
return JSONResponse(status_code=r.status, content=response_data)
|
||||||
|
else:
|
||||||
|
return PlainTextResponse(status_code=r.status, content=response_data)
|
||||||
|
|
||||||
return response_data
|
return response_data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
detail = None
|
|
||||||
if r is not None:
|
|
||||||
try:
|
|
||||||
res = await r.json()
|
|
||||||
if "error" in res:
|
|
||||||
detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}"
|
|
||||||
except Exception:
|
|
||||||
detail = f"External: {e}"
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=r.status if r else 500,
|
status_code=r.status if r else 500,
|
||||||
detail=detail if detail else "Open WebUI: Server Connection Error",
|
detail="Open WebUI: Server Connection Error",
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
if not streaming:
|
if not streaming:
|
||||||
|
|
@ -1043,7 +1046,6 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
||||||
headers=headers,
|
headers=headers,
|
||||||
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
ssl=AIOHTTP_CLIENT_SESSION_SSL,
|
||||||
)
|
)
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
# Check if response is SSE
|
# Check if response is SSE
|
||||||
if "text/event-stream" in r.headers.get("Content-Type", ""):
|
if "text/event-stream" in r.headers.get("Content-Type", ""):
|
||||||
|
|
@ -1057,24 +1059,24 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
response_data = await r.json()
|
response_data = await r.json()
|
||||||
|
except Exception:
|
||||||
|
response_data = await r.text()
|
||||||
|
|
||||||
|
if r.status >= 400:
|
||||||
|
if isinstance(response_data, (dict, list)):
|
||||||
|
return JSONResponse(status_code=r.status, content=response_data)
|
||||||
|
else:
|
||||||
|
return PlainTextResponse(status_code=r.status, content=response_data)
|
||||||
|
|
||||||
return response_data
|
return response_data
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.exception(e)
|
log.exception(e)
|
||||||
|
|
||||||
detail = None
|
|
||||||
if r is not None:
|
|
||||||
try:
|
|
||||||
res = await r.json()
|
|
||||||
log.error(res)
|
|
||||||
if "error" in res:
|
|
||||||
detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}"
|
|
||||||
except Exception:
|
|
||||||
detail = f"External: {e}"
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=r.status if r else 500,
|
status_code=r.status if r else 500,
|
||||||
detail=detail if detail else "Open WebUI: Server Connection Error",
|
detail="Open WebUI: Server Connection Error",
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
if not streaming:
|
if not streaming:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue