| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | import asyncio | 
					
						
							| 
									
										
										
										
											2024-08-28 06:10:27 +08:00
										 |  |  | import hashlib | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  | import logging | 
					
						
							| 
									
										
										
										
											2024-08-28 06:10:27 +08:00
										 |  |  | from pathlib import Path | 
					
						
							|  |  |  | from typing import Literal, Optional, overload | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 06:10:27 +08:00
										 |  |  | import aiohttp | 
					
						
							| 
									
										
										
										
											2024-11-22 13:04:35 +08:00
										 |  |  | from aiocache import cached | 
					
						
							| 
									
										
										
										
											2024-08-28 06:10:27 +08:00
										 |  |  | import requests | 
					
						
							| 
									
										
										
										
											2025-06-17 01:33:11 +08:00
										 |  |  | from urllib.parse import quote | 
					
						
							| 
									
										
										
										
											2024-11-22 13:04:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | from fastapi import Depends, FastAPI, HTTPException, Request, APIRouter | 
					
						
							|  |  |  | from fastapi.middleware.cors import CORSMiddleware | 
					
						
							|  |  |  | from fastapi.responses import FileResponse, StreamingResponse | 
					
						
							|  |  |  | from pydantic import BaseModel | 
					
						
							|  |  |  | from starlette.background import BackgroundTask | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-10 16:54:13 +08:00
										 |  |  | from open_webui.models.models import Models | 
					
						
							| 
									
										
										
										
											2024-09-04 22:54:48 +08:00
										 |  |  | from open_webui.config import ( | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     CACHE_DIR, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2024-10-14 13:56:33 +08:00
										 |  |  | from open_webui.env import ( | 
					
						
							| 
									
										
										
										
											2025-06-28 18:44:47 +08:00
										 |  |  |     MODELS_CACHE_TTL, | 
					
						
							| 
									
										
										
										
											2025-04-18 13:11:42 +08:00
										 |  |  |     AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							| 
									
										
										
										
											2024-10-14 13:56:33 +08:00
										 |  |  |     AIOHTTP_CLIENT_TIMEOUT, | 
					
						
							| 
									
										
										
										
											2025-03-04 12:24:10 +08:00
										 |  |  |     AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, | 
					
						
							| 
									
										
										
										
											2024-11-01 23:23:18 +08:00
										 |  |  |     ENABLE_FORWARD_USER_INFO_HEADERS, | 
					
						
							| 
									
										
										
										
											2024-12-02 10:25:44 +08:00
										 |  |  |     BYPASS_MODEL_ACCESS_CONTROL, | 
					
						
							| 
									
										
										
										
											2024-10-14 13:56:33 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  | from open_webui.models.users import UserModel | 
					
						
							| 
									
										
										
										
											2024-09-30 22:32:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-04 22:54:48 +08:00
										 |  |  | from open_webui.constants import ERROR_MESSAGES | 
					
						
							| 
									
										
										
										
											2024-11-10 10:01:23 +08:00
										 |  |  | from open_webui.env import ENV, SRC_LOG_LEVELS | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-07 10:09:57 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | from open_webui.utils.payload import ( | 
					
						
							| 
									
										
										
										
											2024-08-28 06:10:27 +08:00
										 |  |  |     apply_model_params_to_body_openai, | 
					
						
							|  |  |  |     apply_model_system_prompt_to_body, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-03-08 11:54:06 +08:00
										 |  |  | from open_webui.utils.misc import ( | 
					
						
							|  |  |  |     convert_logit_bias_input_to_json, | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2024-09-07 10:09:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-09 08:01:56 +08:00
										 |  |  | from open_webui.utils.auth import get_admin_user, get_verified_user | 
					
						
							| 
									
										
										
										
											2024-11-17 08:51:55 +08:00
										 |  |  | from open_webui.utils.access_control import has_access | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  | log = logging.getLogger(__name__) | 
					
						
							|  |  |  | log.setLevel(SRC_LOG_LEVELS["OPENAI"]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-10 10:01:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | ########################################## | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Utility functions | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | ########################################## | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-14 00:12:46 +08:00
										 |  |  | async def send_get_request(url, key=None, user: UserModel = None): | 
					
						
							| 
									
										
										
										
											2025-03-04 12:24:10 +08:00
										 |  |  |     timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     try: | 
					
						
							|  |  |  |         async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: | 
					
						
							|  |  |  |             async with session.get( | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |                 url, | 
					
						
							|  |  |  |                 headers={ | 
					
						
							|  |  |  |                     **({"Authorization": f"Bearer {key}"} if key else {}), | 
					
						
							|  |  |  |                     **( | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                             "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |                         } | 
					
						
							| 
									
										
										
										
											2025-02-28 03:32:15 +08:00
										 |  |  |                         if ENABLE_FORWARD_USER_INFO_HEADERS and user | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |                         else {} | 
					
						
							|  |  |  |                     ), | 
					
						
							| 
									
										
										
										
											2025-02-14 00:12:46 +08:00
										 |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2025-04-18 13:11:42 +08:00
										 |  |  |                 ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             ) as response: | 
					
						
							|  |  |  |                 return await response.json() | 
					
						
							|  |  |  |     except Exception as e: | 
					
						
							|  |  |  |         # Handle connection error here | 
					
						
							|  |  |  |         log.error(f"Connection error: {e}") | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async def cleanup_response( | 
					
						
							|  |  |  |     response: Optional[aiohttp.ClientResponse], | 
					
						
							|  |  |  |     session: Optional[aiohttp.ClientSession], | 
					
						
							|  |  |  | ): | 
					
						
							|  |  |  |     if response: | 
					
						
							|  |  |  |         response.close() | 
					
						
							|  |  |  |     if session: | 
					
						
							|  |  |  |         await session.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  | def openai_o_series_handler(payload): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  |     Handle "o" series specific parameters | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     if "max_tokens" in payload: | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  |         # Convert "max_tokens" to "max_completion_tokens" for all o-series models | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         payload["max_completion_tokens"] = payload["max_tokens"] | 
					
						
							|  |  |  |         del payload["max_tokens"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  |     # Handle system role conversion based on model type | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     if payload["messages"][0]["role"] == "system": | 
					
						
							| 
									
										
										
										
											2025-02-24 19:04:06 +08:00
										 |  |  |         model_lower = payload["model"].lower() | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  |         # Legacy models use "user" role instead of "system" | 
					
						
							| 
									
										
										
										
											2025-02-24 19:04:06 +08:00
										 |  |  |         if model_lower.startswith("o1-mini") or model_lower.startswith("o1-preview"): | 
					
						
							|  |  |  |             payload["messages"][0]["role"] = "user" | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             payload["messages"][0]["role"] = "developer" | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return payload | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ########################################## | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # API routes | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | ########################################## | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | router = APIRouter() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @router.get("/config") | 
					
						
							|  |  |  | async def get_config(request: Request, user=Depends(get_admin_user)): | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         "ENABLE_OPENAI_API": request.app.state.config.ENABLE_OPENAI_API, | 
					
						
							|  |  |  |         "OPENAI_API_BASE_URLS": request.app.state.config.OPENAI_API_BASE_URLS, | 
					
						
							|  |  |  |         "OPENAI_API_KEYS": request.app.state.config.OPENAI_API_KEYS, | 
					
						
							|  |  |  |         "OPENAI_API_CONFIGS": request.app.state.config.OPENAI_API_CONFIGS, | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-05-18 01:30:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OpenAIConfigForm(BaseModel): | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     ENABLE_OPENAI_API: Optional[bool] = None | 
					
						
							|  |  |  |     OPENAI_API_BASE_URLS: list[str] | 
					
						
							|  |  |  |     OPENAI_API_KEYS: list[str] | 
					
						
							|  |  |  |     OPENAI_API_CONFIGS: dict | 
					
						
							| 
									
										
										
										
											2024-05-18 01:30:22 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.post("/config/update") | 
					
						
							|  |  |  | async def update_config( | 
					
						
							|  |  |  |     request: Request, form_data: OpenAIConfigForm, user=Depends(get_admin_user) | 
					
						
							|  |  |  | ): | 
					
						
							|  |  |  |     request.app.state.config.ENABLE_OPENAI_API = form_data.ENABLE_OPENAI_API | 
					
						
							|  |  |  |     request.app.state.config.OPENAI_API_BASE_URLS = form_data.OPENAI_API_BASE_URLS | 
					
						
							|  |  |  |     request.app.state.config.OPENAI_API_KEYS = form_data.OPENAI_API_KEYS | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     # Check if API KEYS length is same than API URLS length | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     if len(request.app.state.config.OPENAI_API_KEYS) != len( | 
					
						
							|  |  |  |         request.app.state.config.OPENAI_API_BASE_URLS | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     ): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         if len(request.app.state.config.OPENAI_API_KEYS) > len( | 
					
						
							|  |  |  |             request.app.state.config.OPENAI_API_BASE_URLS | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |         ): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             request.app.state.config.OPENAI_API_KEYS = ( | 
					
						
							|  |  |  |                 request.app.state.config.OPENAI_API_KEYS[ | 
					
						
							|  |  |  |                     : len(request.app.state.config.OPENAI_API_BASE_URLS) | 
					
						
							|  |  |  |                 ] | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             request.app.state.config.OPENAI_API_KEYS += [""] * ( | 
					
						
							|  |  |  |                 len(request.app.state.config.OPENAI_API_BASE_URLS) | 
					
						
							|  |  |  |                 - len(request.app.state.config.OPENAI_API_KEYS) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     request.app.state.config.OPENAI_API_CONFIGS = form_data.OPENAI_API_CONFIGS | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |     # Remove the API configs that are not in the API URLS | 
					
						
							|  |  |  |     keys = list(map(str, range(len(request.app.state.config.OPENAI_API_BASE_URLS)))) | 
					
						
							|  |  |  |     request.app.state.config.OPENAI_API_CONFIGS = { | 
					
						
							|  |  |  |         key: value | 
					
						
							|  |  |  |         for key, value in request.app.state.config.OPENAI_API_CONFIGS.items() | 
					
						
							|  |  |  |         if key in keys | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         "ENABLE_OPENAI_API": request.app.state.config.ENABLE_OPENAI_API, | 
					
						
							|  |  |  |         "OPENAI_API_BASE_URLS": request.app.state.config.OPENAI_API_BASE_URLS, | 
					
						
							|  |  |  |         "OPENAI_API_KEYS": request.app.state.config.OPENAI_API_KEYS, | 
					
						
							|  |  |  |         "OPENAI_API_CONFIGS": request.app.state.config.OPENAI_API_CONFIGS, | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.post("/audio/speech") | 
					
						
							| 
									
										
										
										
											2024-02-09 08:05:01 +08:00
										 |  |  | async def speech(request: Request, user=Depends(get_verified_user)): | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |     idx = None | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         idx = request.app.state.config.OPENAI_API_BASE_URLS.index( | 
					
						
							|  |  |  |             "https://api.openai.com/v1" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |         body = await request.body() | 
					
						
							|  |  |  |         name = hashlib.sha256(body).hexdigest() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-05 01:53:52 +08:00
										 |  |  |         SPEECH_CACHE_DIR = CACHE_DIR / "audio" / "speech" | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |         SPEECH_CACHE_DIR.mkdir(parents=True, exist_ok=True) | 
					
						
							|  |  |  |         file_path = SPEECH_CACHE_DIR.joinpath(f"{name}.mp3") | 
					
						
							|  |  |  |         file_body_path = SPEECH_CACHE_DIR.joinpath(f"{name}.json") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Check if the file already exists in the cache | 
					
						
							|  |  |  |         if file_path.is_file(): | 
					
						
							|  |  |  |             return FileResponse(file_path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         url = request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 17:45:24 +08:00
										 |  |  |         r = None | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |         try: | 
					
						
							|  |  |  |             r = requests.post( | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 url=f"{url}/audio/speech", | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |                 data=body, | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 headers={ | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                     "Authorization": f"Bearer {request.app.state.config.OPENAI_API_KEYS[idx]}", | 
					
						
							|  |  |  |                     **( | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             "HTTP-Referer": "https://openwebui.com/", | 
					
						
							|  |  |  |                             "X-Title": "Open WebUI", | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         if "openrouter.ai" in url | 
					
						
							|  |  |  |                         else {} | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                     **( | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                             "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                         } | 
					
						
							|  |  |  |                         if ENABLE_FORWARD_USER_INFO_HEADERS | 
					
						
							|  |  |  |                         else {} | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                 }, | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |                 stream=True, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |             r.raise_for_status() | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |             # Save the streaming content to a file | 
					
						
							|  |  |  |             with open(file_path, "wb") as f: | 
					
						
							|  |  |  |                 for chunk in r.iter_content(chunk_size=8192): | 
					
						
							|  |  |  |                     f.write(chunk) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |             with open(file_body_path, "w") as f: | 
					
						
							|  |  |  |                 json.dump(json.loads(body.decode("utf-8")), f) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:57:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |             # Return the saved file | 
					
						
							|  |  |  |             return FileResponse(file_path) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |         except Exception as e: | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  |             log.exception(e) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             detail = None | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |             if r is not None: | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     res = r.json() | 
					
						
							|  |  |  |                     if "error" in res: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                         detail = f"External: {res['error']}" | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |                 except Exception: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                     detail = f"External: {e}" | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 18:25:20 +08:00
										 |  |  |             raise HTTPException( | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 status_code=r.status_code if r else 500, | 
					
						
							|  |  |  |                 detail=detail if detail else "Open WebUI: Server Connection Error", | 
					
						
							| 
									
										
										
										
											2024-03-16 18:25:20 +08:00
										 |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     except ValueError: | 
					
						
							|  |  |  |         raise HTTPException(status_code=401, detail=ERROR_MESSAGES.OPENAI_NOT_FOUND) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  | async def get_all_models_responses(request: Request, user: UserModel) -> list: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     if not request.app.state.config.ENABLE_OPENAI_API: | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |         return [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check if API KEYS length is same than API URLS length | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     num_urls = len(request.app.state.config.OPENAI_API_BASE_URLS) | 
					
						
							|  |  |  |     num_keys = len(request.app.state.config.OPENAI_API_KEYS) | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if num_keys != num_urls: | 
					
						
							|  |  |  |         # if there are more keys than urls, remove the extra keys | 
					
						
							|  |  |  |         if num_keys > num_urls: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             new_keys = request.app.state.config.OPENAI_API_KEYS[:num_urls] | 
					
						
							|  |  |  |             request.app.state.config.OPENAI_API_KEYS = new_keys | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |         # if there are more urls than keys, add empty keys | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             request.app.state.config.OPENAI_API_KEYS += [""] * (num_urls - num_keys) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     request_tasks = [] | 
					
						
							|  |  |  |     for idx, url in enumerate(request.app.state.config.OPENAI_API_BASE_URLS): | 
					
						
							| 
									
										
										
										
											2025-01-23 11:00:46 +08:00
										 |  |  |         if (str(idx) not in request.app.state.config.OPENAI_API_CONFIGS) and ( | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |             url not in request.app.state.config.OPENAI_API_CONFIGS  # Legacy support | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             request_tasks.append( | 
					
						
							|  |  |  |                 send_get_request( | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |                     f"{url}/models", | 
					
						
							|  |  |  |                     request.app.state.config.OPENAI_API_KEYS[idx], | 
					
						
							|  |  |  |                     user=user, | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |             api_config = request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							| 
									
										
										
										
											2025-01-19 09:22:29 +08:00
										 |  |  |                 str(idx), | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |                 request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |                     url, {} | 
					
						
							|  |  |  |                 ),  # Legacy support | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 14:03:57 +08:00
										 |  |  |             enable = api_config.get("enable", True) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |             model_ids = api_config.get("model_ids", []) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 14:03:57 +08:00
										 |  |  |             if enable: | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |                 if len(model_ids) == 0: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                     request_tasks.append( | 
					
						
							|  |  |  |                         send_get_request( | 
					
						
							|  |  |  |                             f"{url}/models", | 
					
						
							|  |  |  |                             request.app.state.config.OPENAI_API_KEYS[idx], | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |                             user=user, | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |                         ) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     model_list = { | 
					
						
							|  |  |  |                         "object": "list", | 
					
						
							|  |  |  |                         "data": [ | 
					
						
							|  |  |  |                             { | 
					
						
							|  |  |  |                                 "id": model_id, | 
					
						
							|  |  |  |                                 "name": model_id, | 
					
						
							|  |  |  |                                 "owned_by": "openai", | 
					
						
							|  |  |  |                                 "openai": {"id": model_id}, | 
					
						
							|  |  |  |                                 "urlIdx": idx, | 
					
						
							|  |  |  |                             } | 
					
						
							|  |  |  |                             for model_id in model_ids | 
					
						
							|  |  |  |                         ], | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                     request_tasks.append( | 
					
						
							|  |  |  |                         asyncio.ensure_future(asyncio.sleep(0, model_list)) | 
					
						
							|  |  |  |                     ) | 
					
						
							| 
									
										
										
										
											2024-11-22 12:49:40 +08:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 request_tasks.append(asyncio.ensure_future(asyncio.sleep(0, None))) | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     responses = await asyncio.gather(*request_tasks) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for idx, response in enumerate(responses): | 
					
						
							|  |  |  |         if response: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             url = request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |             api_config = request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							| 
									
										
										
										
											2025-01-19 09:22:29 +08:00
										 |  |  |                 str(idx), | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |                 request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |                     url, {} | 
					
						
							|  |  |  |                 ),  # Legacy support | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-17 05:47:48 +08:00
										 |  |  |             connection_type = api_config.get("connection_type", "external") | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |             prefix_id = api_config.get("prefix_id", None) | 
					
						
							| 
									
										
										
										
											2025-03-12 04:37:30 +08:00
										 |  |  |             tags = api_config.get("tags", []) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-17 05:47:48 +08:00
										 |  |  |             for model in ( | 
					
						
							|  |  |  |                 response if isinstance(response, list) else response.get("data", []) | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 if prefix_id: | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |                     model["id"] = f"{prefix_id}.{model['id']}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-17 05:47:48 +08:00
										 |  |  |                 if tags: | 
					
						
							| 
									
										
										
										
											2025-03-12 04:37:30 +08:00
										 |  |  |                     model["tags"] = tags | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-17 05:47:48 +08:00
										 |  |  |                 if connection_type: | 
					
						
							|  |  |  |                     model["connection_type"] = connection_type | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |     log.debug(f"get_all_models:responses() {responses}") | 
					
						
							|  |  |  |     return responses | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | async def get_filtered_models(models, user): | 
					
						
							|  |  |  |     # Filter models based on user access control | 
					
						
							|  |  |  |     filtered_models = [] | 
					
						
							|  |  |  |     for model in models.get("data", []): | 
					
						
							|  |  |  |         model_info = Models.get_model_by_id(model["id"]) | 
					
						
							|  |  |  |         if model_info: | 
					
						
							|  |  |  |             if user.id == model_info.user_id or has_access( | 
					
						
							|  |  |  |                 user.id, type="read", access_control=model_info.access_control | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 filtered_models.append(model) | 
					
						
							|  |  |  |     return filtered_models | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-28 18:44:47 +08:00
										 |  |  | @cached(ttl=MODELS_CACHE_TTL) | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  | async def get_all_models(request: Request, user: UserModel) -> dict[str, list]: | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  |     log.info("get_all_models()") | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     if not request.app.state.config.ENABLE_OPENAI_API: | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |         return {"data": []} | 
					
						
							| 
									
										
										
										
											2024-03-11 10:00:43 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |     responses = await get_all_models_responses(request, user=user) | 
					
						
							| 
									
										
										
										
											2024-06-03 07:20:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |     def extract_data(response): | 
					
						
							|  |  |  |         if response and "data" in response: | 
					
						
							|  |  |  |             return response["data"] | 
					
						
							|  |  |  |         if isinstance(response, list): | 
					
						
							|  |  |  |             return response | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2024-03-18 16:11:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 12:15:23 +08:00
										 |  |  |     def merge_models_lists(model_lists): | 
					
						
							|  |  |  |         log.debug(f"merge_models_lists {model_lists}") | 
					
						
							|  |  |  |         merged_list = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for idx, models in enumerate(model_lists): | 
					
						
							|  |  |  |             if models is not None and "error" not in models: | 
					
						
							| 
									
										
										
										
											2025-03-09 00:23:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 12:15:23 +08:00
										 |  |  |                 merged_list.extend( | 
					
						
							|  |  |  |                     [ | 
					
						
							|  |  |  |                         { | 
					
						
							|  |  |  |                             **model, | 
					
						
							|  |  |  |                             "name": model.get("name", model["id"]), | 
					
						
							|  |  |  |                             "owned_by": "openai", | 
					
						
							|  |  |  |                             "openai": model, | 
					
						
							| 
									
										
										
										
											2025-05-17 05:47:48 +08:00
										 |  |  |                             "connection_type": model.get("connection_type", "external"), | 
					
						
							| 
									
										
										
										
											2024-12-12 12:15:23 +08:00
										 |  |  |                             "urlIdx": idx, | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         for model in models | 
					
						
							| 
									
										
										
										
											2025-03-09 00:23:20 +08:00
										 |  |  |                         if (model.get("id") or model.get("name")) | 
					
						
							|  |  |  |                         and ( | 
					
						
							|  |  |  |                             "api.openai.com" | 
					
						
							|  |  |  |                             not in request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							|  |  |  |                             or not any( | 
					
						
							|  |  |  |                                 name in model["id"] | 
					
						
							|  |  |  |                                 for name in [ | 
					
						
							|  |  |  |                                     "babbage", | 
					
						
							|  |  |  |                                     "dall-e", | 
					
						
							|  |  |  |                                     "davinci", | 
					
						
							|  |  |  |                                     "embedding", | 
					
						
							|  |  |  |                                     "tts", | 
					
						
							|  |  |  |                                     "whisper", | 
					
						
							|  |  |  |                                 ] | 
					
						
							|  |  |  |                             ) | 
					
						
							| 
									
										
										
										
											2024-12-12 12:15:23 +08:00
										 |  |  |                         ) | 
					
						
							|  |  |  |                     ] | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return merged_list | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |     models = {"data": merge_models_lists(map(extract_data, responses))} | 
					
						
							|  |  |  |     log.debug(f"models: {models}") | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     request.app.state.OPENAI_MODELS = {model["id"]: model for model in models["data"]} | 
					
						
							| 
									
										
										
										
											2024-05-09 20:25:30 +08:00
										 |  |  |     return models | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.get("/models") | 
					
						
							|  |  |  | @router.get("/models/{url_idx}") | 
					
						
							|  |  |  | async def get_models( | 
					
						
							|  |  |  |     request: Request, url_idx: Optional[int] = None, user=Depends(get_verified_user) | 
					
						
							|  |  |  | ): | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     models = { | 
					
						
							|  |  |  |         "data": [], | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |     if url_idx is None: | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |         models = await get_all_models(request, user=user) | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |     else: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         url = request.app.state.config.OPENAI_API_BASE_URLS[url_idx] | 
					
						
							|  |  |  |         key = request.app.state.config.OPENAI_API_KEYS[url_idx] | 
					
						
							| 
									
										
										
										
											2024-03-16 17:45:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |         api_config = request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |             str(url_idx), | 
					
						
							|  |  |  |             request.app.state.config.OPENAI_API_CONFIGS.get(url, {}),  # Legacy support | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 17:45:24 +08:00
										 |  |  |         r = None | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         async with aiohttp.ClientSession( | 
					
						
							| 
									
										
										
										
											2025-04-28 20:47:34 +08:00
										 |  |  |             trust_env=True, | 
					
						
							|  |  |  |             timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST), | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         ) as session: | 
					
						
							| 
									
										
										
										
											2024-11-12 06:11:20 +08:00
										 |  |  |             try: | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                 headers = { | 
					
						
							|  |  |  |                     "Content-Type": "application/json", | 
					
						
							|  |  |  |                     **( | 
					
						
							|  |  |  |                         { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                             "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                             "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                         } | 
					
						
							|  |  |  |                         if ENABLE_FORWARD_USER_INFO_HEADERS | 
					
						
							|  |  |  |                         else {} | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2024-11-12 06:11:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                 if api_config.get("azure", False): | 
					
						
							| 
									
										
										
										
											2025-05-19 08:31:04 +08:00
										 |  |  |                     models = { | 
					
						
							|  |  |  |                         "data": api_config.get("model_ids", []) or [], | 
					
						
							|  |  |  |                         "object": "list", | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     headers["Authorization"] = f"Bearer {key}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     async with session.get( | 
					
						
							|  |  |  |                         f"{url}/models", | 
					
						
							|  |  |  |                         headers=headers, | 
					
						
							|  |  |  |                         ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							|  |  |  |                     ) as r: | 
					
						
							|  |  |  |                         if r.status != 200: | 
					
						
							|  |  |  |                             # 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() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         # Check if we're calling OpenAI API based on the URL | 
					
						
							|  |  |  |                         if "api.openai.com" in url: | 
					
						
							|  |  |  |                             # Filter models according to the specified conditions | 
					
						
							|  |  |  |                             response_data["data"] = [ | 
					
						
							|  |  |  |                                 model | 
					
						
							|  |  |  |                                 for model in response_data.get("data", []) | 
					
						
							|  |  |  |                                 if not any( | 
					
						
							|  |  |  |                                     name in model["id"] | 
					
						
							|  |  |  |                                     for name in [ | 
					
						
							|  |  |  |                                         "babbage", | 
					
						
							|  |  |  |                                         "dall-e", | 
					
						
							|  |  |  |                                         "davinci", | 
					
						
							|  |  |  |                                         "embedding", | 
					
						
							|  |  |  |                                         "tts", | 
					
						
							|  |  |  |                                         "whisper", | 
					
						
							|  |  |  |                                     ] | 
					
						
							|  |  |  |                                 ) | 
					
						
							|  |  |  |                             ] | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                         models = response_data | 
					
						
							| 
									
										
										
										
											2024-11-12 06:11:20 +08:00
										 |  |  |             except aiohttp.ClientError as e: | 
					
						
							|  |  |  |                 # ClientError covers all aiohttp requests issues | 
					
						
							|  |  |  |                 log.exception(f"Client error: {str(e)}") | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |                 raise HTTPException( | 
					
						
							|  |  |  |                     status_code=500, detail="Open WebUI: Server Connection Error" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-12 06:11:20 +08:00
										 |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 log.exception(f"Unexpected error: {e}") | 
					
						
							|  |  |  |                 error_detail = f"Unexpected error: {str(e)}" | 
					
						
							|  |  |  |                 raise HTTPException(status_code=500, detail=error_detail) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-02 10:25:44 +08:00
										 |  |  |     if user.role == "user" and not BYPASS_MODEL_ACCESS_CONTROL: | 
					
						
							| 
									
										
										
										
											2025-01-29 21:47:54 +08:00
										 |  |  |         models["data"] = await get_filtered_models(models, user) | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return models | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | class ConnectionVerificationForm(BaseModel): | 
					
						
							|  |  |  |     url: str | 
					
						
							|  |  |  |     key: str | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |     config: Optional[dict] = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.post("/verify") | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | async def verify_connection( | 
					
						
							|  |  |  |     form_data: ConnectionVerificationForm, user=Depends(get_admin_user) | 
					
						
							|  |  |  | ): | 
					
						
							|  |  |  |     url = form_data.url | 
					
						
							|  |  |  |     key = form_data.key | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |     api_config = form_data.config or {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     async with aiohttp.ClientSession( | 
					
						
							| 
									
										
										
										
											2025-04-28 20:47:34 +08:00
										 |  |  |         trust_env=True, | 
					
						
							|  |  |  |         timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST), | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     ) as session: | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |         try: | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |             headers = { | 
					
						
							|  |  |  |                 "Content-Type": "application/json", | 
					
						
							|  |  |  |                 **( | 
					
						
							|  |  |  |                     { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                         "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                     } | 
					
						
							|  |  |  |                     if ENABLE_FORWARD_USER_INFO_HEADERS | 
					
						
							|  |  |  |                     else {} | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |             if api_config.get("azure", False): | 
					
						
							|  |  |  |                 headers["api-key"] = key | 
					
						
							| 
									
										
										
										
											2025-05-19 08:31:04 +08:00
										 |  |  |                 api_version = api_config.get("api_version", "") or "2023-03-15-preview" | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 async with session.get( | 
					
						
							| 
									
										
										
										
											2025-05-19 08:31:04 +08:00
										 |  |  |                     url=f"{url}/openai/models?api-version={api_version}", | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                     headers=headers, | 
					
						
							|  |  |  |                     ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							|  |  |  |                 ) as r: | 
					
						
							|  |  |  |                     if r.status != 200: | 
					
						
							|  |  |  |                         # 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() | 
					
						
							|  |  |  |                     return response_data | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 headers["Authorization"] = f"Bearer {key}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 async with session.get( | 
					
						
							|  |  |  |                     f"{url}/models", | 
					
						
							|  |  |  |                     headers=headers, | 
					
						
							|  |  |  |                     ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							|  |  |  |                 ) as r: | 
					
						
							|  |  |  |                     if r.status != 200: | 
					
						
							|  |  |  |                         # 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) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:40:32 +08:00
										 |  |  |                     response_data = await r.json() | 
					
						
							|  |  |  |                     return response_data | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         except aiohttp.ClientError as e: | 
					
						
							|  |  |  |             # ClientError covers all aiohttp requests issues | 
					
						
							|  |  |  |             log.exception(f"Client error: {str(e)}") | 
					
						
							|  |  |  |             raise HTTPException( | 
					
						
							|  |  |  |                 status_code=500, detail="Open WebUI: Server Connection Error" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             log.exception(f"Unexpected error: {e}") | 
					
						
							|  |  |  |             error_detail = f"Unexpected error: {str(e)}" | 
					
						
							|  |  |  |             raise HTTPException(status_code=500, detail=error_detail) | 
					
						
							| 
									
										
										
										
											2024-02-06 14:51:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  | def get_azure_allowed_params(api_version: str) -> set[str]: | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |     allowed_params = { | 
					
						
							|  |  |  |         "messages", | 
					
						
							|  |  |  |         "temperature", | 
					
						
							|  |  |  |         "role", | 
					
						
							|  |  |  |         "content", | 
					
						
							|  |  |  |         "contentPart", | 
					
						
							|  |  |  |         "contentPartImage", | 
					
						
							|  |  |  |         "enhancements", | 
					
						
							|  |  |  |         "dataSources", | 
					
						
							|  |  |  |         "n", | 
					
						
							|  |  |  |         "stream", | 
					
						
							|  |  |  |         "stop", | 
					
						
							|  |  |  |         "max_tokens", | 
					
						
							|  |  |  |         "presence_penalty", | 
					
						
							|  |  |  |         "frequency_penalty", | 
					
						
							|  |  |  |         "logit_bias", | 
					
						
							|  |  |  |         "user", | 
					
						
							|  |  |  |         "function_call", | 
					
						
							|  |  |  |         "functions", | 
					
						
							|  |  |  |         "tools", | 
					
						
							|  |  |  |         "tool_choice", | 
					
						
							|  |  |  |         "top_p", | 
					
						
							|  |  |  |         "log_probs", | 
					
						
							|  |  |  |         "top_logprobs", | 
					
						
							|  |  |  |         "response_format", | 
					
						
							|  |  |  |         "seed", | 
					
						
							|  |  |  |         "max_completion_tokens", | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-06-20 13:58:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         if api_version >= "2024-09-01-preview": | 
					
						
							|  |  |  |             allowed_params.add("stream_options") | 
					
						
							|  |  |  |     except ValueError: | 
					
						
							|  |  |  |         log.debug( | 
					
						
							|  |  |  |             f"Invalid API version {api_version} for Azure OpenAI. Defaulting to allowed parameters." | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |     return allowed_params | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-20 13:58:44 +08:00
										 |  |  | def convert_to_azure_payload(url, payload: dict, api_version: str): | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |     model = payload.get("model", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Filter allowed parameters based on Azure OpenAI API | 
					
						
							|  |  |  |     allowed_params = get_azure_allowed_params(api_version) | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Special handling for o-series models | 
					
						
							|  |  |  |     if model.startswith("o") and model.endswith("-mini"): | 
					
						
							|  |  |  |         # Convert max_tokens to max_completion_tokens for o-series models | 
					
						
							|  |  |  |         if "max_tokens" in payload: | 
					
						
							|  |  |  |             payload["max_completion_tokens"] = payload["max_tokens"] | 
					
						
							|  |  |  |             del payload["max_tokens"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Remove temperature if not 1 for o-series models | 
					
						
							|  |  |  |         if "temperature" in payload and payload["temperature"] != 1: | 
					
						
							|  |  |  |             log.debug( | 
					
						
							|  |  |  |                 f"Removing temperature parameter for o-series model {model} as only default value (1) is supported" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             del payload["temperature"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Filter out unsupported parameters | 
					
						
							|  |  |  |     payload = {k: v for k, v in payload.items() if k in allowed_params} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     url = f"{url}/openai/deployments/{model}" | 
					
						
							|  |  |  |     return url, payload | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.post("/chat/completions") | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | async def generate_chat_completion( | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     request: Request, | 
					
						
							| 
									
										
										
										
											2024-09-28 01:43:40 +08:00
										 |  |  |     form_data: dict, | 
					
						
							|  |  |  |     user=Depends(get_verified_user), | 
					
						
							| 
									
										
										
										
											2024-11-13 19:09:46 +08:00
										 |  |  |     bypass_filter: Optional[bool] = False, | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | ): | 
					
						
							| 
									
										
										
										
											2024-12-22 07:29:48 +08:00
										 |  |  |     if BYPASS_MODEL_ACCESS_CONTROL: | 
					
						
							|  |  |  |         bypass_filter = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  |     idx = 0 | 
					
						
							| 
									
										
										
										
											2025-01-30 13:56:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     payload = {**form_data} | 
					
						
							| 
									
										
										
										
											2025-01-30 13:56:51 +08:00
										 |  |  |     metadata = payload.pop("metadata", None) | 
					
						
							| 
									
										
										
										
											2024-08-08 18:30:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     model_id = form_data.get("model") | 
					
						
							|  |  |  |     model_info = Models.get_model_by_id(model_id) | 
					
						
							| 
									
										
										
										
											2024-05-25 17:05:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     # Check model info and override the payload | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     if model_info: | 
					
						
							|  |  |  |         if model_info.base_model_id: | 
					
						
							|  |  |  |             payload["model"] = model_info.base_model_id | 
					
						
							| 
									
										
										
										
											2024-12-22 07:29:48 +08:00
										 |  |  |             model_id = model_info.base_model_id | 
					
						
							| 
									
										
										
										
											2024-05-25 17:05:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |         params = model_info.params.model_dump() | 
					
						
							| 
									
										
										
										
											2025-05-29 16:57:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if params: | 
					
						
							|  |  |  |             system = params.pop("system", None) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             payload = apply_model_params_to_body_openai(params, payload) | 
					
						
							|  |  |  |             payload = apply_model_system_prompt_to_body(system, payload, metadata, user) | 
					
						
							| 
									
										
										
										
											2024-05-30 02:28:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |         # Check if user has access to the model | 
					
						
							| 
									
										
										
										
											2024-11-17 18:51:57 +08:00
										 |  |  |         if not bypass_filter and user.role == "user": | 
					
						
							|  |  |  |             if not ( | 
					
						
							|  |  |  |                 user.id == model_info.user_id | 
					
						
							|  |  |  |                 or has_access( | 
					
						
							|  |  |  |                     user.id, type="read", access_control=model_info.access_control | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ): | 
					
						
							|  |  |  |                 raise HTTPException( | 
					
						
							|  |  |  |                     status_code=403, | 
					
						
							|  |  |  |                     detail="Model not found", | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-11-18 23:40:37 +08:00
										 |  |  |     elif not bypass_filter: | 
					
						
							| 
									
										
										
										
											2024-11-18 11:15:09 +08:00
										 |  |  |         if user.role != "admin": | 
					
						
							|  |  |  |             raise HTTPException( | 
					
						
							|  |  |  |                 status_code=403, | 
					
						
							|  |  |  |                 detail="Model not found", | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-13 23:29:26 +08:00
										 |  |  |     await get_all_models(request, user=user) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     model = request.app.state.OPENAI_MODELS.get(model_id) | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     if model: | 
					
						
							| 
									
										
										
										
											2024-11-15 19:00:18 +08:00
										 |  |  |         idx = model["urlIdx"] | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     else: | 
					
						
							|  |  |  |         raise HTTPException( | 
					
						
							|  |  |  |             status_code=404, | 
					
						
							|  |  |  |             detail="Model not found", | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-05-30 02:28:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     # Get the API config for the model | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     api_config = request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							| 
									
										
										
										
											2025-01-19 09:22:29 +08:00
										 |  |  |         str(idx), | 
					
						
							| 
									
										
										
										
											2025-01-19 09:10:15 +08:00
										 |  |  |         request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |             request.app.state.config.OPENAI_API_BASE_URLS[idx], {} | 
					
						
							|  |  |  |         ),  # Legacy support | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     prefix_id = api_config.get("prefix_id", None) | 
					
						
							| 
									
										
										
										
											2024-11-12 13:18:51 +08:00
										 |  |  |     if prefix_id: | 
					
						
							|  |  |  |         payload["model"] = payload["model"].replace(f"{prefix_id}.", "") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-16 20:41:07 +08:00
										 |  |  |     # Add user info to the payload if the model is a pipeline | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     if "pipeline" in model and model.get("pipeline"): | 
					
						
							| 
									
										
										
										
											2024-06-20 18:45:13 +08:00
										 |  |  |         payload["user"] = { | 
					
						
							|  |  |  |             "name": user.name, | 
					
						
							|  |  |  |             "id": user.id, | 
					
						
							|  |  |  |             "email": user.email, | 
					
						
							|  |  |  |             "role": user.role, | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-05-30 02:28:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     url = request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							|  |  |  |     key = request.app.state.config.OPENAI_API_KEYS[idx] | 
					
						
							| 
									
										
										
										
											2024-09-21 09:06:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-20 15:14:27 +08:00
										 |  |  |     # Check if model is from "o" series | 
					
						
							|  |  |  |     is_o_series = payload["model"].lower().startswith(("o1", "o3", "o4")) | 
					
						
							|  |  |  |     if is_o_series: | 
					
						
							|  |  |  |         payload = openai_o_series_handler(payload) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     elif "api.openai.com" not in url: | 
					
						
							| 
									
										
										
										
											2024-12-20 11:05:20 +08:00
										 |  |  |         # Remove "max_completion_tokens" from the payload for backward compatibility | 
					
						
							|  |  |  |         if "max_completion_tokens" in payload: | 
					
						
							|  |  |  |             payload["max_tokens"] = payload["max_completion_tokens"] | 
					
						
							|  |  |  |             del payload["max_completion_tokens"] | 
					
						
							| 
									
										
										
										
											2024-09-21 09:06:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-26 07:46:49 +08:00
										 |  |  |     if "max_tokens" in payload and "max_completion_tokens" in payload: | 
					
						
							|  |  |  |         del payload["max_tokens"] | 
					
						
							| 
									
										
										
										
											2024-09-27 20:18:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     # Convert the modified body back to JSON | 
					
						
							| 
									
										
										
										
											2025-03-09 00:50:30 +08:00
										 |  |  |     if "logit_bias" in payload: | 
					
						
							|  |  |  |         payload["logit_bias"] = json.loads( | 
					
						
							|  |  |  |             convert_logit_bias_input_to_json(payload["logit_bias"]) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |     headers = { | 
					
						
							|  |  |  |         "Content-Type": "application/json", | 
					
						
							|  |  |  |         **( | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "HTTP-Referer": "https://openwebui.com/", | 
					
						
							|  |  |  |                 "X-Title": "Open WebUI", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if "openrouter.ai" in url | 
					
						
							|  |  |  |             else {} | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |         **( | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                 "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                 "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                 "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                 "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-07-18 19:03:46 +08:00
										 |  |  |                 **( | 
					
						
							|  |  |  |                     {"X-OpenWebUI-Chat-Id": metadata.get("chat_id")} | 
					
						
							|  |  |  |                     if metadata and metadata.get("chat_id") | 
					
						
							|  |  |  |                     else {} | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             } | 
					
						
							|  |  |  |             if ENABLE_FORWARD_USER_INFO_HEADERS | 
					
						
							|  |  |  |             else {} | 
					
						
							|  |  |  |         ), | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if api_config.get("azure", False): | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |         api_version = api_config.get("api_version", "2023-03-15-preview") | 
					
						
							|  |  |  |         request_url, payload = convert_to_azure_payload(url, payload, api_version) | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |         headers["api-key"] = key | 
					
						
							|  |  |  |         headers["api-version"] = api_version | 
					
						
							|  |  |  |         request_url = f"{request_url}/chat/completions?api-version={api_version}" | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         request_url = f"{url}/chat/completions" | 
					
						
							|  |  |  |         headers["Authorization"] = f"Bearer {key}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     payload = json.dumps(payload) | 
					
						
							| 
									
										
										
										
											2024-05-25 17:05:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     r = None | 
					
						
							|  |  |  |     session = None | 
					
						
							|  |  |  |     streaming = False | 
					
						
							| 
									
										
										
										
											2024-09-19 22:20:00 +08:00
										 |  |  |     response = None | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2024-07-01 14:29:26 +08:00
										 |  |  |         session = aiohttp.ClientSession( | 
					
						
							|  |  |  |             trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |         r = await session.request( | 
					
						
							|  |  |  |             method="POST", | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             url=request_url, | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |             data=payload, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             headers=headers, | 
					
						
							| 
									
										
										
										
											2025-04-18 13:11:42 +08:00
										 |  |  |             ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-03-07 08:13:25 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |         # Check if response is SSE | 
					
						
							|  |  |  |         if "text/event-stream" in r.headers.get("Content-Type", ""): | 
					
						
							|  |  |  |             streaming = True | 
					
						
							|  |  |  |             return StreamingResponse( | 
					
						
							|  |  |  |                 r.content, | 
					
						
							|  |  |  |                 status_code=r.status, | 
					
						
							|  |  |  |                 headers=dict(r.headers), | 
					
						
							|  |  |  |                 background=BackgroundTask( | 
					
						
							|  |  |  |                     cleanup_response, response=r, session=session | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-09-19 22:20:00 +08:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 response = await r.json() | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 log.error(e) | 
					
						
							|  |  |  |                 response = await r.text() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             r.raise_for_status() | 
					
						
							|  |  |  |             return response | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     except Exception as e: | 
					
						
							|  |  |  |         log.exception(e) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         detail = None | 
					
						
							| 
									
										
										
										
											2024-09-19 22:20:00 +08:00
										 |  |  |         if isinstance(response, dict): | 
					
						
							|  |  |  |             if "error" in response: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 detail = f"{response['error']['message'] if 'message' in response['error'] else response['error']}" | 
					
						
							| 
									
										
										
										
											2024-09-19 22:20:00 +08:00
										 |  |  |         elif isinstance(response, str): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |             detail = response | 
					
						
							| 
									
										
										
										
											2024-09-19 22:20:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |         raise HTTPException( | 
					
						
							|  |  |  |             status_code=r.status if r else 500, | 
					
						
							|  |  |  |             detail=detail if detail else "Open WebUI: Server Connection Error", | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |     finally: | 
					
						
							| 
									
										
										
										
											2025-07-15 09:11:22 +08:00
										 |  |  |         if not streaming: | 
					
						
							|  |  |  |             await cleanup_response(r, session) | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-05 05:12:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  | async def embeddings(request: Request, form_data: dict, user): | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  |     Calls the embeddings endpoint for OpenAI-compatible providers. | 
					
						
							| 
									
										
										
										
											2025-06-05 05:12:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  |     Args: | 
					
						
							|  |  |  |         request (Request): The FastAPI request context. | 
					
						
							|  |  |  |         form_data (dict): OpenAI-compatible embeddings payload. | 
					
						
							|  |  |  |         user (UserModel): The authenticated user. | 
					
						
							| 
									
										
										
										
											2025-06-05 05:12:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  |     Returns: | 
					
						
							|  |  |  |         dict: OpenAI-compatible embeddings response. | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     idx = 0 | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  |     # Prepare payload/body | 
					
						
							|  |  |  |     body = json.dumps(form_data) | 
					
						
							|  |  |  |     # Find correct backend url/key based on model | 
					
						
							|  |  |  |     await get_all_models(request, user=user) | 
					
						
							|  |  |  |     model_id = form_data.get("model") | 
					
						
							|  |  |  |     models = request.app.state.OPENAI_MODELS | 
					
						
							|  |  |  |     if model_id in models: | 
					
						
							|  |  |  |         idx = models[model_id]["urlIdx"] | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |     url = request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							|  |  |  |     key = request.app.state.config.OPENAI_API_KEYS[idx] | 
					
						
							|  |  |  |     r = None | 
					
						
							|  |  |  |     session = None | 
					
						
							|  |  |  |     streaming = False | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         session = aiohttp.ClientSession(trust_env=True) | 
					
						
							|  |  |  |         r = await session.request( | 
					
						
							| 
									
										
										
										
											2025-06-04 22:13:53 +08:00
										 |  |  |             method="POST", | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |             url=f"{url}/embeddings", | 
					
						
							|  |  |  |             data=body, | 
					
						
							|  |  |  |             headers={ | 
					
						
							|  |  |  |                 "Authorization": f"Bearer {key}", | 
					
						
							|  |  |  |                 "Content-Type": "application/json", | 
					
						
							|  |  |  |                 **( | 
					
						
							|  |  |  |                     { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                         "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                         "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |                     } | 
					
						
							| 
									
										
										
										
											2025-06-05 05:12:28 +08:00
										 |  |  |                     if ENABLE_FORWARD_USER_INFO_HEADERS and user | 
					
						
							|  |  |  |                     else {} | 
					
						
							| 
									
										
										
										
											2025-02-15 00:57:47 +08:00
										 |  |  |                 ), | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         r.raise_for_status() | 
					
						
							|  |  |  |         if "text/event-stream" in r.headers.get("Content-Type", ""): | 
					
						
							|  |  |  |             streaming = True | 
					
						
							|  |  |  |             return StreamingResponse( | 
					
						
							|  |  |  |                 r.content, | 
					
						
							|  |  |  |                 status_code=r.status, | 
					
						
							|  |  |  |                 headers=dict(r.headers), | 
					
						
							|  |  |  |                 background=BackgroundTask( | 
					
						
							|  |  |  |                     cleanup_response, response=r, session=session | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             response_data = await r.json() | 
					
						
							|  |  |  |             return response_data | 
					
						
							|  |  |  |     except Exception as 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( | 
					
						
							|  |  |  |             status_code=r.status if r else 500, | 
					
						
							|  |  |  |             detail=detail if detail else "Open WebUI: Server Connection Error", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     finally: | 
					
						
							| 
									
										
										
										
											2025-07-15 09:11:22 +08:00
										 |  |  |         if not streaming: | 
					
						
							|  |  |  |             await cleanup_response(r, session) | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-05 05:12:28 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | @router.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"]) | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | async def proxy(path: str, request: Request, user=Depends(get_verified_user)): | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Deprecated: proxy all requests to OpenAI API | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     body = await request.body() | 
					
						
							| 
									
										
										
										
											2024-05-25 17:05:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |     idx = 0 | 
					
						
							|  |  |  |     url = request.app.state.config.OPENAI_API_BASE_URLS[idx] | 
					
						
							|  |  |  |     key = request.app.state.config.OPENAI_API_KEYS[idx] | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |     api_config = request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |         str(idx), | 
					
						
							|  |  |  |         request.app.state.config.OPENAI_API_CONFIGS.get( | 
					
						
							|  |  |  |             request.app.state.config.OPENAI_API_BASE_URLS[idx], {} | 
					
						
							|  |  |  |         ),  # Legacy support | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-16 17:45:24 +08:00
										 |  |  |     r = None | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |     session = None | 
					
						
							|  |  |  |     streaming = False | 
					
						
							| 
									
										
										
										
											2024-03-16 17:45:24 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |         headers = { | 
					
						
							|  |  |  |             "Content-Type": "application/json", | 
					
						
							|  |  |  |             **( | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2025-07-11 03:00:14 +08:00
										 |  |  |                     "X-OpenWebUI-User-Name": quote(user.name, safe=" "), | 
					
						
							|  |  |  |                     "X-OpenWebUI-User-Id": user.id, | 
					
						
							|  |  |  |                     "X-OpenWebUI-User-Email": user.email, | 
					
						
							|  |  |  |                     "X-OpenWebUI-User-Role": user.role, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 if ENABLE_FORWARD_USER_INFO_HEADERS | 
					
						
							|  |  |  |                 else {} | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if api_config.get("azure", False): | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |             api_version = api_config.get("api_version", "2023-03-15-preview") | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             headers["api-key"] = key | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |             headers["api-version"] = api_version | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |             payload = json.loads(body) | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |             url, payload = convert_to_azure_payload(url, payload, api_version) | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             body = json.dumps(payload).encode() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-18 21:02:01 +08:00
										 |  |  |             request_url = f"{url}/{path}?api-version={api_version}" | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |         else: | 
					
						
							|  |  |  |             headers["Authorization"] = f"Bearer {key}" | 
					
						
							|  |  |  |             request_url = f"{url}/{path}" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-04 11:41:59 +08:00
										 |  |  |         session = aiohttp.ClientSession(trust_env=True) | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |         r = await session.request( | 
					
						
							| 
									
										
										
										
											2024-06-03 02:40:18 +08:00
										 |  |  |             method=request.method, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             url=request_url, | 
					
						
							| 
									
										
										
										
											2024-06-10 03:43:54 +08:00
										 |  |  |             data=body, | 
					
						
							| 
									
										
										
										
											2025-05-19 07:55:56 +08:00
										 |  |  |             headers=headers, | 
					
						
							| 
									
										
										
										
											2025-04-18 13:11:42 +08:00
										 |  |  |             ssl=AIOHTTP_CLIENT_SESSION_SSL, | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  |         r.raise_for_status() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 10:38:03 +08:00
										 |  |  |         # Check if response is SSE | 
					
						
							|  |  |  |         if "text/event-stream" in r.headers.get("Content-Type", ""): | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |             streaming = True | 
					
						
							| 
									
										
										
										
											2024-01-05 10:38:03 +08:00
										 |  |  |             return StreamingResponse( | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |                 r.content, | 
					
						
							|  |  |  |                 status_code=r.status, | 
					
						
							| 
									
										
										
										
											2024-01-05 10:38:03 +08:00
										 |  |  |                 headers=dict(r.headers), | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |                 background=BackgroundTask( | 
					
						
							|  |  |  |                     cleanup_response, response=r, session=session | 
					
						
							|  |  |  |                 ), | 
					
						
							| 
									
										
										
										
											2024-01-05 10:38:03 +08:00
										 |  |  |             ) | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |             response_data = await r.json() | 
					
						
							| 
									
										
										
										
											2024-01-05 10:38:03 +08:00
										 |  |  |             return response_data | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  |     except Exception as e: | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  |         log.exception(e) | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         detail = None | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  |         if r is not None: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |                 res = await r.json() | 
					
						
							| 
									
										
										
										
											2025-02-25 22:36:25 +08:00
										 |  |  |                 log.error(res) | 
					
						
							| 
									
										
										
										
											2024-01-05 08:49:34 +08:00
										 |  |  |                 if "error" in res: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                     detail = f"External: {res['error']['message'] if 'message' in res['error'] else res['error']}" | 
					
						
							| 
									
										
										
										
											2024-08-03 21:24:26 +08:00
										 |  |  |             except Exception: | 
					
						
							| 
									
										
										
										
											2024-12-12 09:50:48 +08:00
										 |  |  |                 detail = f"External: {e}" | 
					
						
							|  |  |  |         raise HTTPException( | 
					
						
							|  |  |  |             status_code=r.status if r else 500, | 
					
						
							|  |  |  |             detail=detail if detail else "Open WebUI: Server Connection Error", | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-06-03 01:48:45 +08:00
										 |  |  |     finally: | 
					
						
							| 
									
										
										
										
											2025-07-15 09:11:22 +08:00
										 |  |  |         if not streaming: | 
					
						
							|  |  |  |             await cleanup_response(r, session) |