| 
									
										
										
										
											2024-05-09 12:00:03 +08:00
										 |  |  | from contextlib import asynccontextmanager | 
					
						
							| 
									
										
										
										
											2024-02-23 16:30:26 +08:00
										 |  |  | from bs4 import BeautifulSoup | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import markdown | 
					
						
							| 
									
										
										
										
											2024-01-07 18:48:21 +08:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2024-02-24 16:21:53 +08:00
										 |  |  | import os | 
					
						
							|  |  |  | import sys | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  | import logging | 
					
						
							| 
									
										
										
										
											2024-04-10 14:03:05 +08:00
										 |  |  | import aiohttp | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  | import requests | 
					
						
							| 
									
										
										
										
											2024-05-22 06:04:00 +08:00
										 |  |  | import mimetypes | 
					
						
							| 
									
										
										
										
											2024-02-23 16:30:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  | from fastapi import FastAPI, Request, Depends, status | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | from fastapi.staticfiles import StaticFiles | 
					
						
							|  |  |  | from fastapi import HTTPException | 
					
						
							|  |  |  | from fastapi.middleware.wsgi import WSGIMiddleware | 
					
						
							|  |  |  | from fastapi.middleware.cors import CORSMiddleware | 
					
						
							| 
									
										
										
										
											2023-11-19 08:47:12 +08:00
										 |  |  | from starlette.exceptions import HTTPException as StarletteHTTPException | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  | from starlette.middleware.base import BaseHTTPMiddleware | 
					
						
							| 
									
										
										
										
											2024-05-07 08:29:16 +08:00
										 |  |  | from starlette.responses import StreamingResponse, Response | 
					
						
							| 
									
										
										
										
											2024-01-07 14:07:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  | from apps.ollama.main import app as ollama_app, get_all_models as get_ollama_models | 
					
						
							|  |  |  | from apps.openai.main import app as openai_app, get_all_models as get_openai_models | 
					
						
							| 
									
										
										
										
											2024-04-10 14:03:05 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-11 16:17:50 +08:00
										 |  |  | from apps.audio.main import app as audio_app | 
					
						
							| 
									
										
										
										
											2024-02-22 10:12:01 +08:00
										 |  |  | from apps.images.main import app as images_app | 
					
						
							|  |  |  | from apps.rag.main import app as rag_app | 
					
						
							| 
									
										
										
										
											2024-05-26 16:15:48 +08:00
										 |  |  | from apps.webui.main import app as webui_app | 
					
						
							| 
									
										
										
										
											2024-01-07 14:07:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-21 14:22:02 +08:00
										 |  |  | import asyncio | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | from pydantic import BaseModel | 
					
						
							| 
									
										
										
										
											2024-05-19 18:46:24 +08:00
										 |  |  | from typing import List, Optional | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-26 16:15:48 +08:00
										 |  |  | from apps.webui.models.models import Models, ModelModel | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  | from utils.utils import get_admin_user, get_verified_user | 
					
						
							| 
									
										
										
										
											2024-03-11 09:40:50 +08:00
										 |  |  | from apps.rag.utils import rag_messages | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  | from config import ( | 
					
						
							| 
									
										
										
										
											2024-03-24 11:16:18 +08:00
										 |  |  |     CONFIG_DATA, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     WEBUI_NAME, | 
					
						
							| 
									
										
										
										
											2024-05-07 08:29:16 +08:00
										 |  |  |     WEBUI_URL, | 
					
						
							| 
									
										
										
										
											2024-05-08 23:40:18 +08:00
										 |  |  |     WEBUI_AUTH, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     ENV, | 
					
						
							|  |  |  |     VERSION, | 
					
						
							|  |  |  |     CHANGELOG, | 
					
						
							|  |  |  |     FRONTEND_BUILD_DIR, | 
					
						
							| 
									
										
										
										
											2024-04-09 18:32:28 +08:00
										 |  |  |     CACHE_DIR, | 
					
						
							|  |  |  |     STATIC_DIR, | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |     ENABLE_OPENAI_API, | 
					
						
							|  |  |  |     ENABLE_OLLAMA_API, | 
					
						
							| 
									
										
										
										
											2024-04-27 05:17:18 +08:00
										 |  |  |     ENABLE_MODEL_FILTER, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     MODEL_FILTER_LIST, | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  |     GLOBAL_LOG_LEVEL, | 
					
						
							|  |  |  |     SRC_LOG_LEVELS, | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  |     WEBHOOK_URL, | 
					
						
							| 
									
										
										
										
											2024-04-23 02:55:46 +08:00
										 |  |  |     ENABLE_ADMIN_EXPORT, | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |     AppConfig, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  | from constants import ERROR_MESSAGES | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  | logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) | 
					
						
							|  |  |  | log = logging.getLogger(__name__) | 
					
						
							|  |  |  | log.setLevel(SRC_LOG_LEVELS["MAIN"]) | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-28 17:45:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | class SPAStaticFiles(StaticFiles): | 
					
						
							|  |  |  |     async def get_response(self, path: str, scope): | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             return await super().get_response(path, scope) | 
					
						
							|  |  |  |         except (HTTPException, StarletteHTTPException) as ex: | 
					
						
							|  |  |  |             if ex.status_code == 404: | 
					
						
							|  |  |  |                 return await super().get_response("index.html", scope) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise ex | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 18:03:55 +08:00
										 |  |  | print( | 
					
						
							| 
									
										
										
										
											2024-05-04 05:23:38 +08:00
										 |  |  |     rf"""
 | 
					
						
							| 
									
										
										
										
											2024-04-02 18:03:55 +08:00
										 |  |  |   ___                    __        __   _     _   _ ___  | 
					
						
							|  |  |  |  / _ \ _ __   ___ _ __   \ \      / /__| |__ | | | |_ _| | 
					
						
							|  |  |  | | | | | '_ \ / _ \ '_ \   \ \ /\ / / _ \ '_ \| | | || |  | 
					
						
							|  |  |  | | |_| | |_) |  __/ | | |   \ V  V /  __/ |_) | |_| || |  | 
					
						
							|  |  |  |  \___/| .__/ \___|_| |_|    \_/\_/ \___|_.__/ \___/|___| | 
					
						
							|  |  |  |       |_|                                                | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |        | 
					
						
							|  |  |  | v{VERSION} - building the best open-source AI user interface.       | 
					
						
							|  |  |  | https://github.com/open-webui/open-webui | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-09 12:00:03 +08:00
										 |  |  | @asynccontextmanager | 
					
						
							|  |  |  | async def lifespan(app: FastAPI): | 
					
						
							|  |  |  |     yield | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | app = FastAPI( | 
					
						
							|  |  |  |     docs_url="/docs" if ENV == "dev" else None, redoc_url=None, lifespan=lifespan | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  | app.state.config = AppConfig() | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | app.state.config.ENABLE_OPENAI_API = ENABLE_OPENAI_API | 
					
						
							|  |  |  | app.state.config.ENABLE_OLLAMA_API = ENABLE_OLLAMA_API | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  | app.state.config.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER | 
					
						
							|  |  |  | app.state.config.MODEL_FILTER_LIST = MODEL_FILTER_LIST | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-09 23:49:54 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  | app.state.config.WEBHOOK_URL = WEBHOOK_URL | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 09:26:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | app.state.MODELS = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | origins = ["*"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-24 16:21:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-17 11:49:28 +08:00
										 |  |  | # Custom middleware to add security headers | 
					
						
							| 
									
										
										
										
											2024-05-18 01:35:33 +08:00
										 |  |  | # class SecurityHeadersMiddleware(BaseHTTPMiddleware): | 
					
						
							|  |  |  | #     async def dispatch(self, request: Request, call_next): | 
					
						
							|  |  |  | #         response: Response = await call_next(request) | 
					
						
							|  |  |  | #         response.headers["Cross-Origin-Opener-Policy"] = "same-origin" | 
					
						
							|  |  |  | #         response.headers["Cross-Origin-Embedder-Policy"] = "require-corp" | 
					
						
							|  |  |  | #         return response | 
					
						
							| 
									
										
										
										
											2024-05-17 11:49:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-18 01:35:33 +08:00
										 |  |  | # app.add_middleware(SecurityHeadersMiddleware) | 
					
						
							| 
									
										
										
										
											2024-05-17 11:49:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  | class RAGMiddleware(BaseHTTPMiddleware): | 
					
						
							|  |  |  |     async def dispatch(self, request: Request, call_next): | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  |         return_citations = False | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:51:42 +08:00
										 |  |  |         if request.method == "POST" and ( | 
					
						
							|  |  |  |             "/api/chat" in request.url.path or "/chat/completions" in request.url.path | 
					
						
							|  |  |  |         ): | 
					
						
							| 
									
										
										
										
											2024-03-21 07:11:36 +08:00
										 |  |  |             log.debug(f"request.url.path: {request.url.path}") | 
					
						
							| 
									
										
										
										
											2024-03-09 14:52:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  |             # Read the original request body | 
					
						
							|  |  |  |             body = await request.body() | 
					
						
							|  |  |  |             # Decode body to string | 
					
						
							|  |  |  |             body_str = body.decode("utf-8") | 
					
						
							|  |  |  |             # Parse string to JSON | 
					
						
							|  |  |  |             data = json.loads(body_str) if body_str else {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  |             return_citations = data.get("citations", False) | 
					
						
							|  |  |  |             if "citations" in data: | 
					
						
							|  |  |  |                 del data["citations"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  |             # Example: Add a new key-value pair or modify existing ones | 
					
						
							|  |  |  |             # data["modified"] = True  # Example modification | 
					
						
							|  |  |  |             if "docs" in data: | 
					
						
							| 
									
										
										
										
											2024-03-11 09:40:50 +08:00
										 |  |  |                 data = {**data} | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  |                 data["messages"], citations = rag_messages( | 
					
						
							| 
									
										
										
										
											2024-04-28 03:38:50 +08:00
										 |  |  |                     docs=data["docs"], | 
					
						
							|  |  |  |                     messages=data["messages"], | 
					
						
							| 
									
										
										
										
											2024-05-14 14:30:15 +08:00
										 |  |  |                     template=rag_app.state.config.RAG_TEMPLATE, | 
					
						
							| 
									
										
										
										
											2024-04-28 03:38:50 +08:00
										 |  |  |                     embedding_function=rag_app.state.EMBEDDING_FUNCTION, | 
					
						
							| 
									
										
										
										
											2024-05-14 14:30:15 +08:00
										 |  |  |                     k=rag_app.state.config.TOP_K, | 
					
						
							| 
									
										
										
										
											2024-04-28 03:38:50 +08:00
										 |  |  |                     reranking_function=rag_app.state.sentence_transformer_rf, | 
					
						
							| 
									
										
										
										
											2024-05-14 14:30:15 +08:00
										 |  |  |                     r=rag_app.state.config.RELEVANCE_THRESHOLD, | 
					
						
							|  |  |  |                     hybrid_search=rag_app.state.config.ENABLE_RAG_HYBRID_SEARCH, | 
					
						
							| 
									
										
										
										
											2024-03-11 09:40:50 +08:00
										 |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  |                 del data["docs"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  |                 log.debug( | 
					
						
							|  |  |  |                     f"data['messages']: {data['messages']}, citations: {citations}" | 
					
						
							|  |  |  |                 ) | 
					
						
							| 
									
										
										
										
											2024-03-10 12:12:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  |             modified_body_bytes = json.dumps(data).encode("utf-8") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 09:40:50 +08:00
										 |  |  |             # Replace the request body with the modified one | 
					
						
							|  |  |  |             request._body = modified_body_bytes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Set custom header to ensure content-length matches new body length | 
					
						
							|  |  |  |             request.headers.__dict__["_list"] = [ | 
					
						
							|  |  |  |                 (b"content-length", str(len(modified_body_bytes)).encode("utf-8")), | 
					
						
							|  |  |  |                 *[ | 
					
						
							|  |  |  |                     (k, v) | 
					
						
							|  |  |  |                     for k, v in request.headers.raw | 
					
						
							|  |  |  |                     if k.lower() != b"content-length" | 
					
						
							|  |  |  |                 ], | 
					
						
							|  |  |  |             ] | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         response = await call_next(request) | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if return_citations: | 
					
						
							|  |  |  |             # Inject the citations into the response | 
					
						
							|  |  |  |             if isinstance(response, StreamingResponse): | 
					
						
							|  |  |  |                 # If it's a streaming response, inject it as SSE event or NDJSON line | 
					
						
							|  |  |  |                 content_type = response.headers.get("Content-Type") | 
					
						
							|  |  |  |                 if "text/event-stream" in content_type: | 
					
						
							|  |  |  |                     return StreamingResponse( | 
					
						
							|  |  |  |                         self.openai_stream_wrapper(response.body_iterator, citations), | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 if "application/x-ndjson" in content_type: | 
					
						
							|  |  |  |                     return StreamingResponse( | 
					
						
							|  |  |  |                         self.ollama_stream_wrapper(response.body_iterator, citations), | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  |         return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async def _receive(self, body: bytes): | 
					
						
							|  |  |  |         return {"type": "http.request", "body": body, "more_body": False} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-06 21:14:51 +08:00
										 |  |  |     async def openai_stream_wrapper(self, original_generator, citations): | 
					
						
							|  |  |  |         yield f"data: {json.dumps({'citations': citations})}\n\n" | 
					
						
							|  |  |  |         async for data in original_generator: | 
					
						
							|  |  |  |             yield data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async def ollama_stream_wrapper(self, original_generator, citations): | 
					
						
							|  |  |  |         yield f"{json.dumps({'citations': citations})}\n" | 
					
						
							|  |  |  |         async for data in original_generator: | 
					
						
							|  |  |  |             yield data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-09 14:34:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | app.add_middleware(RAGMiddleware) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-11 09:40:50 +08:00
										 |  |  | app.add_middleware( | 
					
						
							|  |  |  |     CORSMiddleware, | 
					
						
							|  |  |  |     allow_origins=origins, | 
					
						
							|  |  |  |     allow_credentials=True, | 
					
						
							|  |  |  |     allow_methods=["*"], | 
					
						
							|  |  |  |     allow_headers=["*"], | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  | @app.middleware("http") | 
					
						
							|  |  |  | async def check_url(request: Request, call_next): | 
					
						
							| 
									
										
										
										
											2024-05-25 09:26:36 +08:00
										 |  |  |     if len(app.state.MODELS) == 0: | 
					
						
							|  |  |  |         await get_all_models() | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         pass | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-15 08:28:51 +08:00
										 |  |  |     start_time = int(time.time()) | 
					
						
							|  |  |  |     response = await call_next(request) | 
					
						
							|  |  |  |     process_time = int(time.time()) - start_time | 
					
						
							|  |  |  |     response.headers["X-Process-Time"] = str(process_time) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return response | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 23:00:07 +08:00
										 |  |  | @app.middleware("http") | 
					
						
							|  |  |  | async def update_embedding_function(request: Request, call_next): | 
					
						
							|  |  |  |     response = await call_next(request) | 
					
						
							|  |  |  |     if "/embedding/update" in request.url.path: | 
					
						
							|  |  |  |         webui_app.state.EMBEDDING_FUNCTION = rag_app.state.EMBEDDING_FUNCTION | 
					
						
							|  |  |  |     return response | 
					
						
							| 
									
										
										
										
											2024-02-22 19:22:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 23:00:07 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-04 11:55:32 +08:00
										 |  |  | app.mount("/ollama", ollama_app) | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  | app.mount("/openai", openai_app) | 
					
						
							| 
									
										
										
										
											2024-02-11 16:17:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 10:12:01 +08:00
										 |  |  | app.mount("/images/api/v1", images_app) | 
					
						
							| 
									
										
										
										
											2024-02-11 16:17:50 +08:00
										 |  |  | app.mount("/audio/api/v1", audio_app) | 
					
						
							| 
									
										
										
										
											2024-01-07 14:07:20 +08:00
										 |  |  | app.mount("/rag/api/v1", rag_app) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-19 23:00:07 +08:00
										 |  |  | app.mount("/api/v1", webui_app) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | webui_app.state.EMBEDDING_FUNCTION = rag_app.state.EMBEDDING_FUNCTION | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 04:59:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 09:26:36 +08:00
										 |  |  | async def get_all_models(): | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |     openai_models = [] | 
					
						
							|  |  |  |     ollama_models = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if app.state.config.ENABLE_OPENAI_API: | 
					
						
							|  |  |  |         openai_models = await get_openai_models() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         openai_models = openai_models["data"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if app.state.config.ENABLE_OLLAMA_API: | 
					
						
							|  |  |  |         ollama_models = await get_ollama_models() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ollama_models = [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 "id": model["model"], | 
					
						
							|  |  |  |                 "name": model["name"], | 
					
						
							|  |  |  |                 "object": "model", | 
					
						
							|  |  |  |                 "created": int(time.time()), | 
					
						
							|  |  |  |                 "owned_by": "ollama", | 
					
						
							|  |  |  |                 "ollama": model, | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             for model in ollama_models["models"] | 
					
						
							|  |  |  |         ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     models = openai_models + ollama_models | 
					
						
							|  |  |  |     custom_models = Models.get_all_models() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for custom_model in custom_models: | 
					
						
							|  |  |  |         if custom_model.base_model_id == None: | 
					
						
							|  |  |  |             for model in models: | 
					
						
							| 
									
										
										
										
											2024-05-24 17:11:17 +08:00
										 |  |  |                 if ( | 
					
						
							|  |  |  |                     custom_model.id == model["id"] | 
					
						
							|  |  |  |                     or custom_model.id == model["id"].split(":")[0] | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |                     model["name"] = custom_model.name | 
					
						
							|  |  |  |                     model["info"] = custom_model.model_dump() | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-05-24 18:06:57 +08:00
										 |  |  |             owned_by = "openai" | 
					
						
							|  |  |  |             for model in models: | 
					
						
							| 
									
										
										
										
											2024-05-25 11:29:13 +08:00
										 |  |  |                 if ( | 
					
						
							|  |  |  |                     custom_model.base_model_id == model["id"] | 
					
						
							|  |  |  |                     or custom_model.base_model_id == model["id"].split(":")[0] | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2024-05-24 18:06:57 +08:00
										 |  |  |                     owned_by = model["owned_by"] | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |             models.append( | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "id": custom_model.id, | 
					
						
							|  |  |  |                     "name": custom_model.name, | 
					
						
							|  |  |  |                     "object": "model", | 
					
						
							|  |  |  |                     "created": custom_model.created_at, | 
					
						
							| 
									
										
										
										
											2024-05-24 18:06:57 +08:00
										 |  |  |                     "owned_by": owned_by, | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |                     "info": custom_model.model_dump(), | 
					
						
							| 
									
										
										
										
											2024-05-25 11:29:13 +08:00
										 |  |  |                     "preset": True, | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-25 09:26:36 +08:00
										 |  |  |     app.state.MODELS = {model["id"]: model for model in models} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     webui_app.state.MODELS = app.state.MODELS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return models | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @app.get("/api/models") | 
					
						
							|  |  |  | async def get_models(user=Depends(get_verified_user)): | 
					
						
							|  |  |  |     models = await get_all_models() | 
					
						
							| 
									
										
										
										
											2024-05-24 16:40:48 +08:00
										 |  |  |     if app.state.config.ENABLE_MODEL_FILTER: | 
					
						
							|  |  |  |         if user.role == "user": | 
					
						
							|  |  |  |             models = list( | 
					
						
							|  |  |  |                 filter( | 
					
						
							|  |  |  |                     lambda model: model["id"] in app.state.config.MODEL_FILTER_LIST, | 
					
						
							|  |  |  |                     models, | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             return {"data": models} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return {"data": models} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-22 10:12:01 +08:00
										 |  |  | @app.get("/api/config") | 
					
						
							|  |  |  | async def get_app_config(): | 
					
						
							| 
									
										
										
										
											2024-04-01 02:06:15 +08:00
										 |  |  |     # Checking and Handling the Absence of 'ui' in CONFIG_DATA | 
					
						
							| 
									
										
										
										
											2024-04-01 04:59:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     default_locale = "en-US" | 
					
						
							| 
									
										
										
										
											2024-04-01 02:06:15 +08:00
										 |  |  |     if "ui" in CONFIG_DATA: | 
					
						
							|  |  |  |         default_locale = CONFIG_DATA["ui"].get("default_locale", "en-US") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # The Rest of the Function Now Uses the Variables Defined Above | 
					
						
							| 
									
										
										
										
											2024-02-22 10:12:01 +08:00
										 |  |  |     return { | 
					
						
							|  |  |  |         "status": True, | 
					
						
							| 
									
										
										
										
											2024-02-24 09:12:19 +08:00
										 |  |  |         "name": WEBUI_NAME, | 
					
						
							| 
									
										
										
										
											2024-02-23 16:30:26 +08:00
										 |  |  |         "version": VERSION, | 
					
						
							| 
									
										
										
										
											2024-04-01 02:06:15 +08:00
										 |  |  |         "default_locale": default_locale, | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |         "default_models": webui_app.state.config.DEFAULT_MODELS, | 
					
						
							|  |  |  |         "default_prompt_suggestions": webui_app.state.config.DEFAULT_PROMPT_SUGGESTIONS, | 
					
						
							| 
									
										
										
										
											2024-05-27 00:05:26 +08:00
										 |  |  |         "feature_flags": { | 
					
						
							|  |  |  |             "auth": WEBUI_AUTH, | 
					
						
							|  |  |  |             "enable_signup": webui_app.state.config.ENABLE_SIGNUP, | 
					
						
							|  |  |  |             "auth_trusted_header": bool(webui_app.state.AUTH_TRUSTED_EMAIL_HEADER), | 
					
						
							|  |  |  |             "enable_image_generation": images_app.state.config.ENABLED, | 
					
						
							|  |  |  |             "enable_admin_export": ENABLE_ADMIN_EXPORT, | 
					
						
							| 
									
										
										
										
											2024-05-27 00:10:25 +08:00
										 |  |  |             "enable_community_sharing": webui_app.state.config.ENABLE_COMMUNITY_SHARING, | 
					
						
							| 
									
										
										
										
											2024-05-27 00:05:26 +08:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2024-02-22 10:12:01 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | @app.get("/api/config/model/filter") | 
					
						
							|  |  |  | async def get_model_filter_config(user=Depends(get_admin_user)): | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |         "enabled": app.state.config.ENABLE_MODEL_FILTER, | 
					
						
							|  |  |  |         "models": app.state.config.MODEL_FILTER_LIST, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ModelFilterConfigForm(BaseModel): | 
					
						
							|  |  |  |     enabled: bool | 
					
						
							|  |  |  |     models: List[str] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @app.post("/api/config/model/filter") | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  | async def update_model_filter_config( | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  |     form_data: ModelFilterConfigForm, user=Depends(get_admin_user) | 
					
						
							|  |  |  | ): | 
					
						
							| 
									
										
										
										
											2024-05-18 01:35:33 +08:00
										 |  |  |     app.state.config.ENABLE_MODEL_FILTER = form_data.enabled | 
					
						
							|  |  |  |     app.state.config.MODEL_FILTER_LIST = form_data.models | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |         "enabled": app.state.config.ENABLE_MODEL_FILTER, | 
					
						
							|  |  |  |         "models": app.state.config.MODEL_FILTER_LIST, | 
					
						
							| 
									
										
										
										
											2024-03-10 13:47:01 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-10 13:19:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  | @app.get("/api/webhook") | 
					
						
							|  |  |  | async def get_webhook_url(user=Depends(get_admin_user)): | 
					
						
							|  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |         "url": app.state.config.WEBHOOK_URL, | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UrlForm(BaseModel): | 
					
						
							|  |  |  |     url: str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @app.post("/api/webhook") | 
					
						
							|  |  |  | async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)): | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |     app.state.config.WEBHOOK_URL = form_data.url | 
					
						
							|  |  |  |     webui_app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-05-10 15:03:24 +08:00
										 |  |  |         "url": app.state.config.WEBHOOK_URL, | 
					
						
							| 
									
										
										
										
											2024-03-21 09:35:02 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-27 00:23:24 +08:00
										 |  |  | @app.get("/api/community_sharing", response_model=bool) | 
					
						
							|  |  |  | async def get_community_sharing_status(request: Request, user=Depends(get_admin_user)): | 
					
						
							|  |  |  |     return webui_app.state.config.ENABLE_COMMUNITY_SHARING | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @app.get("/api/community_sharing/toggle", response_model=bool) | 
					
						
							|  |  |  | async def toggle_community_sharing(request: Request, user=Depends(get_admin_user)): | 
					
						
							|  |  |  |     webui_app.state.config.ENABLE_COMMUNITY_SHARING = ( | 
					
						
							|  |  |  |         not webui_app.state.config.ENABLE_COMMUNITY_SHARING | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     return webui_app.state.config.ENABLE_COMMUNITY_SHARING | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-05 16:59:35 +08:00
										 |  |  | @app.get("/api/version") | 
					
						
							|  |  |  | async def get_app_config(): | 
					
						
							|  |  |  |     return { | 
					
						
							|  |  |  |         "version": VERSION, | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-23 16:30:26 +08:00
										 |  |  | @app.get("/api/changelog") | 
					
						
							|  |  |  | async def get_app_changelog(): | 
					
						
							| 
									
										
										
										
											2024-03-31 16:10:57 +08:00
										 |  |  |     return {key: CHANGELOG[key] for idx, key in enumerate(CHANGELOG) if idx < 5} | 
					
						
							| 
									
										
										
										
											2024-02-23 16:30:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  | @app.get("/api/version/updates") | 
					
						
							|  |  |  | async def get_app_latest_release_version(): | 
					
						
							|  |  |  |     try: | 
					
						
							| 
									
										
										
										
											2024-04-10 14:03:05 +08:00
										 |  |  |         async with aiohttp.ClientSession() as session: | 
					
						
							|  |  |  |             async with session.get( | 
					
						
							|  |  |  |                 "https://api.github.com/repos/open-webui/open-webui/releases/latest" | 
					
						
							|  |  |  |             ) as response: | 
					
						
							|  |  |  |                 response.raise_for_status() | 
					
						
							|  |  |  |                 data = await response.json() | 
					
						
							|  |  |  |                 latest_version = data["tag_name"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 return {"current": VERSION, "latest": latest_version[1:]} | 
					
						
							|  |  |  |     except aiohttp.ClientError as e: | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  |         raise HTTPException( | 
					
						
							|  |  |  |             status_code=status.HTTP_503_SERVICE_UNAVAILABLE, | 
					
						
							| 
									
										
										
										
											2024-02-26 03:55:15 +08:00
										 |  |  |             detail=ERROR_MESSAGES.RATE_LIMIT_EXCEEDED, | 
					
						
							| 
									
										
										
										
											2024-02-26 03:26:58 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 16:27:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-03 02:55:00 +08:00
										 |  |  | @app.get("/manifest.json") | 
					
						
							|  |  |  | async def get_manifest_json(): | 
					
						
							|  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2024-04-04 11:43:55 +08:00
										 |  |  |         "name": WEBUI_NAME, | 
					
						
							|  |  |  |         "short_name": WEBUI_NAME, | 
					
						
							| 
									
										
										
										
											2024-04-03 02:55:00 +08:00
										 |  |  |         "start_url": "/", | 
					
						
							|  |  |  |         "display": "standalone", | 
					
						
							|  |  |  |         "background_color": "#343541", | 
					
						
							|  |  |  |         "theme_color": "#343541", | 
					
						
							|  |  |  |         "orientation": "portrait-primary", | 
					
						
							| 
									
										
										
										
											2024-05-02 10:32:36 +08:00
										 |  |  |         "icons": [{"src": "/static/logo.png", "type": "image/png", "sizes": "500x500"}], | 
					
						
							| 
									
										
										
										
											2024-04-03 02:55:00 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-10 16:27:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-07 08:29:16 +08:00
										 |  |  | @app.get("/opensearch.xml") | 
					
						
							|  |  |  | async def get_opensearch_xml(): | 
					
						
							|  |  |  |     xml_content = rf"""
 | 
					
						
							|  |  |  |     <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/"> | 
					
						
							|  |  |  |     <ShortName>{WEBUI_NAME}</ShortName> | 
					
						
							|  |  |  |     <Description>Search {WEBUI_NAME}</Description> | 
					
						
							|  |  |  |     <InputEncoding>UTF-8</InputEncoding> | 
					
						
							|  |  |  |     <Image width="16" height="16" type="image/x-icon">{WEBUI_URL}/favicon.png</Image> | 
					
						
							|  |  |  |     <Url type="text/html" method="get" template="{WEBUI_URL}/?q={"{searchTerms}"}"/> | 
					
						
							|  |  |  |     <moz:SearchForm>{WEBUI_URL}</moz:SearchForm> | 
					
						
							|  |  |  |     </OpenSearchDescription> | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     return Response(content=xml_content, media_type="application/xml") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-16 02:17:18 +08:00
										 |  |  | @app.get("/health") | 
					
						
							|  |  |  | async def healthcheck(): | 
					
						
							|  |  |  |     return {"status": True} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-09 18:32:28 +08:00
										 |  |  | app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") | 
					
						
							|  |  |  | app.mount("/cache", StaticFiles(directory=CACHE_DIR), name="cache") | 
					
						
							| 
									
										
										
										
											2024-02-24 09:12:19 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-28 23:03:30 +08:00
										 |  |  | if os.path.exists(FRONTEND_BUILD_DIR): | 
					
						
							| 
									
										
										
										
											2024-05-22 12:38:58 +08:00
										 |  |  |     mimetypes.add_type("text/javascript", ".js") | 
					
						
							| 
									
										
										
										
											2024-04-28 23:03:30 +08:00
										 |  |  |     app.mount( | 
					
						
							|  |  |  |         "/", | 
					
						
							|  |  |  |         SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True), | 
					
						
							|  |  |  |         name="spa-static-files", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  | else: | 
					
						
							|  |  |  |     log.warning( | 
					
						
							|  |  |  |         f"Frontend build directory not found at '{FRONTEND_BUILD_DIR}'. Serving API only." | 
					
						
							|  |  |  |     ) |