· 5 months ago · Apr 17, 2025, 11:20 AM
1## WIP. Creating a persistant memory with personality project
2import asyncio
3import inspect
4import json
5import logging
6import mimetypes
7import os
8import shutil
9import sys
10import time
11import random
12
13from contextlib import asynccontextmanager
14from urllib.parse import urlencode, parse_qs, urlparse
15from pydantic import BaseModel
16from sqlalchemy import text
17
18from typing import Optional
19from aiocache import cached
20import aiohttp
21import requests
22
23
24from fastapi import (
25 Depends,
26 FastAPI,
27 File,
28 Form,
29 HTTPException,
30 Request,
31 UploadFile,
32 status,
33 applications,
34 BackgroundTasks,
35)
36
37from fastapi.openapi.docs import get_swagger_ui_html
38
39from fastapi.middleware.cors import CORSMiddleware
40from fastapi.responses import JSONResponse, RedirectResponse
41from fastapi.staticfiles import StaticFiles
42
43from starlette.exceptions import HTTPException as StarletteHTTPException
44from starlette.middleware.base import BaseHTTPMiddleware
45from starlette.middleware.sessions import SessionMiddleware
46from starlette.responses import Response, StreamingResponse
47
48
49from open_webui.utils import logger
50from open_webui.utils.audit import AuditLevel, AuditLoggingMiddleware
51from open_webui.utils.logger import start_logger
52from open_webui.socket.main import (
53 app as socket_app,
54 periodic_usage_pool_cleanup,
55)
56from open_webui.routers import (
57 audio,
58 images,
59 ollama,
60 openai,
61 retrieval,
62 pipelines,
63 tasks,
64 auths,
65 channels,
66 chats,
67 folders,
68 configs,
69 groups,
70 files,
71 functions,
72 memories,
73 models,
74 knowledge,
75 prompts,
76 evaluations,
77 tools,
78 users,
79 utils,
80)
81
82from open_webui.routers.retrieval import (
83 get_embedding_function,
84 get_ef,
85 get_rf,
86)
87
88from open_webui.internal.db import Session, engine
89
90from open_webui.models.functions import Functions
91from open_webui.models.models import Models
92from open_webui.models.users import UserModel, Users
93from open_webui.models.chats import Chats
94
95from open_webui.config import (
96 LICENSE_KEY,
97 # Ollama
98 ENABLE_OLLAMA_API,
99 OLLAMA_BASE_URLS,
100 OLLAMA_API_CONFIGS,
101 # OpenAI
102 ENABLE_OPENAI_API,
103 ONEDRIVE_CLIENT_ID,
104 OPENAI_API_BASE_URLS,
105 OPENAI_API_KEYS,
106 OPENAI_API_CONFIGS,
107 # Direct Connections
108 ENABLE_DIRECT_CONNECTIONS,
109 # Tool Server Configs
110 TOOL_SERVER_CONNECTIONS,
111 # Code Execution
112 ENABLE_CODE_EXECUTION,
113 CODE_EXECUTION_ENGINE,
114 CODE_EXECUTION_JUPYTER_URL,
115 CODE_EXECUTION_JUPYTER_AUTH,
116 CODE_EXECUTION_JUPYTER_AUTH_TOKEN,
117 CODE_EXECUTION_JUPYTER_AUTH_PASSWORD,
118 CODE_EXECUTION_JUPYTER_TIMEOUT,
119 ENABLE_CODE_INTERPRETER,
120 CODE_INTERPRETER_ENGINE,
121 CODE_INTERPRETER_PROMPT_TEMPLATE,
122 CODE_INTERPRETER_JUPYTER_URL,
123 CODE_INTERPRETER_JUPYTER_AUTH,
124 CODE_INTERPRETER_JUPYTER_AUTH_TOKEN,
125 CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD,
126 CODE_INTERPRETER_JUPYTER_TIMEOUT,
127 # Image
128 AUTOMATIC1111_API_AUTH,
129 AUTOMATIC1111_BASE_URL,
130 AUTOMATIC1111_CFG_SCALE,
131 AUTOMATIC1111_SAMPLER,
132 AUTOMATIC1111_SCHEDULER,
133 COMFYUI_BASE_URL,
134 COMFYUI_API_KEY,
135 COMFYUI_WORKFLOW,
136 COMFYUI_WORKFLOW_NODES,
137 ENABLE_IMAGE_GENERATION,
138 ENABLE_IMAGE_PROMPT_GENERATION,
139 IMAGE_GENERATION_ENGINE,
140 IMAGE_GENERATION_MODEL,
141 IMAGE_SIZE,
142 IMAGE_STEPS,
143 IMAGES_OPENAI_API_BASE_URL,
144 IMAGES_OPENAI_API_KEY,
145 IMAGES_GEMINI_API_BASE_URL,
146 IMAGES_GEMINI_API_KEY,
147 # Audio
148 AUDIO_STT_ENGINE,
149 AUDIO_STT_MODEL,
150 AUDIO_STT_OPENAI_API_BASE_URL,
151 AUDIO_STT_OPENAI_API_KEY,
152 AUDIO_STT_AZURE_API_KEY,
153 AUDIO_STT_AZURE_REGION,
154 AUDIO_STT_AZURE_LOCALES,
155 AUDIO_TTS_API_KEY,
156 AUDIO_TTS_ENGINE,
157 AUDIO_TTS_MODEL,
158 AUDIO_TTS_OPENAI_API_BASE_URL,
159 AUDIO_TTS_OPENAI_API_KEY,
160 AUDIO_TTS_SPLIT_ON,
161 AUDIO_TTS_VOICE,
162 AUDIO_TTS_AZURE_SPEECH_REGION,
163 AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT,
164 PLAYWRIGHT_WS_URL,
165 PLAYWRIGHT_TIMEOUT,
166 FIRECRAWL_API_BASE_URL,
167 FIRECRAWL_API_KEY,
168 WEB_LOADER_ENGINE,
169 WHISPER_MODEL,
170 WHISPER_VAD_FILTER,
171 DEEPGRAM_API_KEY,
172 WHISPER_MODEL_AUTO_UPDATE,
173 WHISPER_MODEL_DIR,
174 # Retrieval
175 RAG_TEMPLATE,
176 DEFAULT_RAG_TEMPLATE,
177 RAG_FULL_CONTEXT,
178 BYPASS_EMBEDDING_AND_RETRIEVAL,
179 RAG_EMBEDDING_MODEL,
180 RAG_EMBEDDING_MODEL_AUTO_UPDATE,
181 RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE,
182 RAG_RERANKING_MODEL,
183 RAG_RERANKING_MODEL_AUTO_UPDATE,
184 RAG_RERANKING_MODEL_TRUST_REMOTE_CODE,
185 RAG_EMBEDDING_ENGINE,
186 RAG_EMBEDDING_BATCH_SIZE,
187 RAG_RELEVANCE_THRESHOLD,
188 RAG_FILE_MAX_COUNT,
189 RAG_FILE_MAX_SIZE,
190 RAG_OPENAI_API_BASE_URL,
191 RAG_OPENAI_API_KEY,
192 RAG_OLLAMA_BASE_URL,
193 RAG_OLLAMA_API_KEY,
194 CHUNK_OVERLAP,
195 CHUNK_SIZE,
196 CONTENT_EXTRACTION_ENGINE,
197 TIKA_SERVER_URL,
198 DOCLING_SERVER_URL,
199 DOCUMENT_INTELLIGENCE_ENDPOINT,
200 DOCUMENT_INTELLIGENCE_KEY,
201 MISTRAL_OCR_API_KEY,
202 RAG_TOP_K,
203 RAG_TOP_K_RERANKER,
204 RAG_TEXT_SPLITTER,
205 TIKTOKEN_ENCODING_NAME,
206 PDF_EXTRACT_IMAGES,
207 YOUTUBE_LOADER_LANGUAGE,
208 YOUTUBE_LOADER_PROXY_URL,
209 # Retrieval (Web Search)
210 ENABLE_WEB_SEARCH,
211 WEB_SEARCH_ENGINE,
212 BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL,
213 WEB_SEARCH_RESULT_COUNT,
214 WEB_SEARCH_CONCURRENT_REQUESTS,
215 WEB_SEARCH_TRUST_ENV,
216 WEB_SEARCH_DOMAIN_FILTER_LIST,
217 JINA_API_KEY,
218 SEARCHAPI_API_KEY,
219 SEARCHAPI_ENGINE,
220 SERPAPI_API_KEY,
221 SERPAPI_ENGINE,
222 SEARXNG_QUERY_URL,
223 SERPER_API_KEY,
224 SERPLY_API_KEY,
225 SERPSTACK_API_KEY,
226 SERPSTACK_HTTPS,
227 TAVILY_API_KEY,
228 TAVILY_EXTRACT_DEPTH,
229 BING_SEARCH_V7_ENDPOINT,
230 BING_SEARCH_V7_SUBSCRIPTION_KEY,
231 BRAVE_SEARCH_API_KEY,
232 EXA_API_KEY,
233 PERPLEXITY_API_KEY,
234 SOUGOU_API_SID,
235 SOUGOU_API_SK,
236 KAGI_SEARCH_API_KEY,
237 MOJEEK_SEARCH_API_KEY,
238 BOCHA_SEARCH_API_KEY,
239 GOOGLE_PSE_API_KEY,
240 GOOGLE_PSE_ENGINE_ID,
241 GOOGLE_DRIVE_CLIENT_ID,
242 GOOGLE_DRIVE_API_KEY,
243 ONEDRIVE_CLIENT_ID,
244 ENABLE_RAG_HYBRID_SEARCH,
245 ENABLE_RAG_LOCAL_WEB_FETCH,
246 ENABLE_WEB_LOADER_SSL_VERIFICATION,
247 ENABLE_GOOGLE_DRIVE_INTEGRATION,
248 ENABLE_ONEDRIVE_INTEGRATION,
249 UPLOAD_DIR,
250 # WebUI
251 WEBUI_AUTH,
252 WEBUI_NAME,
253 WEBUI_BANNERS,
254 WEBHOOK_URL,
255 ADMIN_EMAIL,
256 SHOW_ADMIN_DETAILS,
257 JWT_EXPIRES_IN,
258 ENABLE_SIGNUP,
259 ENABLE_LOGIN_FORM,
260 ENABLE_API_KEY,
261 ENABLE_API_KEY_ENDPOINT_RESTRICTIONS,
262 API_KEY_ALLOWED_ENDPOINTS,
263 ENABLE_CHANNELS,
264 ENABLE_COMMUNITY_SHARING,
265 ENABLE_MESSAGE_RATING,
266 ENABLE_USER_WEBHOOKS,
267 ENABLE_EVALUATION_ARENA_MODELS,
268 USER_PERMISSIONS,
269 DEFAULT_USER_ROLE,
270 DEFAULT_PROMPT_SUGGESTIONS,
271 DEFAULT_MODELS,
272 DEFAULT_ARENA_MODEL,
273 MODEL_ORDER_LIST,
274 EVALUATION_ARENA_MODELS,
275 # WebUI (OAuth)
276 ENABLE_OAUTH_ROLE_MANAGEMENT,
277 OAUTH_ROLES_CLAIM,
278 OAUTH_EMAIL_CLAIM,
279 OAUTH_PICTURE_CLAIM,
280 OAUTH_USERNAME_CLAIM,
281 OAUTH_ALLOWED_ROLES,
282 OAUTH_ADMIN_ROLES,
283 # WebUI (LDAP)
284 ENABLE_LDAP,
285 LDAP_SERVER_LABEL,
286 LDAP_SERVER_HOST,
287 LDAP_SERVER_PORT,
288 LDAP_ATTRIBUTE_FOR_MAIL,
289 LDAP_ATTRIBUTE_FOR_USERNAME,
290 LDAP_SEARCH_FILTERS,
291 LDAP_SEARCH_BASE,
292 LDAP_APP_DN,
293 LDAP_APP_PASSWORD,
294 LDAP_USE_TLS,
295 LDAP_CA_CERT_FILE,
296 LDAP_CIPHERS,
297 # Misc
298 ENV,
299 CACHE_DIR,
300 STATIC_DIR,
301 FRONTEND_BUILD_DIR,
302 CORS_ALLOW_ORIGIN,
303 DEFAULT_LOCALE,
304 OAUTH_PROVIDERS,
305 WEBUI_URL,
306 # Admin
307 ENABLE_ADMIN_CHAT_ACCESS,
308 ENABLE_ADMIN_EXPORT,
309 # Tasks
310 TASK_MODEL,
311 TASK_MODEL_EXTERNAL,
312 ENABLE_TAGS_GENERATION,
313 ENABLE_TITLE_GENERATION,
314 ENABLE_SEARCH_QUERY_GENERATION,
315 ENABLE_RETRIEVAL_QUERY_GENERATION,
316 ENABLE_AUTOCOMPLETE_GENERATION,
317 TITLE_GENERATION_PROMPT_TEMPLATE,
318 TAGS_GENERATION_PROMPT_TEMPLATE,
319 IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE,
320 TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE,
321 QUERY_GENERATION_PROMPT_TEMPLATE,
322 AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE,
323 AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH,
324 AppConfig,
325 reset_config,
326)
327from open_webui.env import (
328 AUDIT_EXCLUDED_PATHS,
329 AUDIT_LOG_LEVEL,
330 CHANGELOG,
331 REDIS_URL,
332 REDIS_SENTINEL_HOSTS,
333 REDIS_SENTINEL_PORT,
334 GLOBAL_LOG_LEVEL,
335 MAX_BODY_LOG_SIZE,
336 SAFE_MODE,
337 SRC_LOG_LEVELS,
338 VERSION,
339 WEBUI_BUILD_HASH,
340 WEBUI_SECRET_KEY,
341 WEBUI_SESSION_COOKIE_SAME_SITE,
342 WEBUI_SESSION_COOKIE_SECURE,
343 WEBUI_AUTH_TRUSTED_EMAIL_HEADER,
344 WEBUI_AUTH_TRUSTED_NAME_HEADER,
345 ENABLE_WEBSOCKET_SUPPORT,
346 BYPASS_MODEL_ACCESS_CONTROL,
347 RESET_CONFIG_ON_START,
348 OFFLINE_MODE,
349 ENABLE_OTEL,
350 EXTERNAL_PWA_MANIFEST_URL,
351)
352
353
354from open_webui.utils.models import (
355 get_all_models,
356 get_all_base_models,
357 check_model_access,
358)
359from open_webui.utils.chat import (
360 generate_chat_completion as chat_completion_handler,
361 chat_completed as chat_completed_handler,
362 chat_action as chat_action_handler,
363)
364from open_webui.utils.middleware import process_chat_payload, process_chat_response
365from open_webui.utils.access_control import has_access
366
367from open_webui.utils.auth import (
368 get_license_data,
369 get_http_authorization_cred,
370 decode_token,
371 get_admin_user,
372 get_verified_user,
373)
374from open_webui.utils.oauth import OAuthManager
375from open_webui.utils.security_headers import SecurityHeadersMiddleware
376
377from open_webui.tasks import (
378 list_task_ids_by_chat_id,
379 stop_task,
380 list_tasks,
381) # Import from tasks.py
382
383from open_webui.utils.redis import get_sentinels_from_env
384
385
386if SAFE_MODE:
387 print("SAFE MODE ENABLED")
388 Functions.deactivate_all_functions()
389
390logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
391log = logging.getLogger(__name__)
392log.setLevel(SRC_LOG_LEVELS["MAIN"])
393
394
395class SPAStaticFiles(StaticFiles):
396 async def get_response(self, path: str, scope):
397 try:
398 return await super().get_response(path, scope)
399 except (HTTPException, StarletteHTTPException) as ex:
400 if ex.status_code == 404:
401 if path.endswith(".js"):
402 # Return 404 for javascript files
403 raise ex
404 else:
405 return await super().get_response("index.html", scope)
406 else:
407 raise ex
408
409
410print(
411 rf"""
412 ██████╗ ██████╗ ███████╗███╗ ██╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██╗
413██╔═══██╗██╔══██╗██╔════╝████╗ ██║ ██║ ██║██╔════╝██╔══██╗██║ ██║██║
414██║ ██║██████╔╝█████╗ ██╔██╗ ██║ ██║ █╗ ██║█████╗ ██████╔╝██║ ██║██║
415██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║███╗██║██╔══╝ ██╔══██╗██║ ██║██║
416╚██████╔╝██║ ███████╗██║ ╚████║ ╚███╔███╔╝███████╗██████╔╝╚██████╔╝██║
417 ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═════╝ ╚═╝
418
419
420v{VERSION} - building the best open-source AI user interface.
421{f"Commit: {WEBUI_BUILD_HASH}" if WEBUI_BUILD_HASH != "dev-build" else ""}
422https://github.com/open-webui/open-webui
423"""
424)
425
426# === Custom AI Config (external mods) ===
427BASE_DIR = "I:/myAI/data"
428sys.path.insert(0, BASE_DIR)
429#
430# MY IMPORTS FROM DATA FOLDER
431#
432import ai_memory #loads the ai_memory.py from the data folder
433
434#Connect to memory.db
435#Create tables if they’re missing
436#Confirm everything’s wired up
437try:
438 ai_memory.initialize()
439 print("\n\n✅ Memory DB initialized.\n\n")
440except Exception as e:
441 print(f"\n\n❌ Failed to initialize memory DB: {e}\n\n")
442
443
444PERSONALITY_FILE = os.path.join(BASE_DIR, "personality.txt")
445
446try:
447 with open(PERSONALITY_FILE, "r", encoding="utf-8") as f:
448 personality = f.read()
449 print(f"️\nperonality.txt Read SUCCESSFULLY!\n")
450except Exception as e:
451 personality = "You are Richards girlfriend."
452 print(f"⚠️ Could not load personality.txt: {e}")
453
454@asynccontextmanager
455async def lifespan(app: FastAPI):
456 start_logger()
457 if RESET_CONFIG_ON_START:
458 reset_config()
459
460 if LICENSE_KEY:
461 get_license_data(app, LICENSE_KEY)
462
463 asyncio.create_task(periodic_usage_pool_cleanup())
464 yield
465
466
467app = FastAPI(
468 title="Open WebUI",
469 docs_url="/docs" if ENV == "dev" else None,
470 openapi_url="/openapi.json" if ENV == "dev" else None,
471 redoc_url=None,
472 lifespan=lifespan,
473)
474
475oauth_manager = OAuthManager(app)
476
477app.state.config = AppConfig(
478 redis_url=REDIS_URL,
479 redis_sentinels=get_sentinels_from_env(REDIS_SENTINEL_HOSTS, REDIS_SENTINEL_PORT),
480)
481
482app.state.WEBUI_NAME = WEBUI_NAME
483app.state.LICENSE_METADATA = None
484
485
486########################################
487#
488# OPENTELEMETRY
489#
490########################################
491
492if ENABLE_OTEL:
493 from open_webui.utils.telemetry.setup import setup as setup_opentelemetry
494
495 setup_opentelemetry(app=app, db_engine=engine)
496
497
498########################################
499#
500# OLLAMA
501#
502########################################
503
504
505app.state.config.ENABLE_OLLAMA_API = ENABLE_OLLAMA_API
506app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS
507app.state.config.OLLAMA_API_CONFIGS = OLLAMA_API_CONFIGS
508
509app.state.OLLAMA_MODELS = {}
510
511########################################
512#
513# OPENAI
514#
515########################################
516
517app.state.config.ENABLE_OPENAI_API = ENABLE_OPENAI_API
518app.state.config.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS
519app.state.config.OPENAI_API_KEYS = OPENAI_API_KEYS
520app.state.config.OPENAI_API_CONFIGS = OPENAI_API_CONFIGS
521
522app.state.OPENAI_MODELS = {}
523
524########################################
525#
526# TOOL SERVERS
527#
528########################################
529
530app.state.config.TOOL_SERVER_CONNECTIONS = TOOL_SERVER_CONNECTIONS
531app.state.TOOL_SERVERS = []
532
533########################################
534#
535# DIRECT CONNECTIONS
536#
537########################################
538
539app.state.config.ENABLE_DIRECT_CONNECTIONS = ENABLE_DIRECT_CONNECTIONS
540
541########################################
542#
543# WEBUI
544#
545########################################
546
547app.state.config.WEBUI_URL = WEBUI_URL
548app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP
549app.state.config.ENABLE_LOGIN_FORM = ENABLE_LOGIN_FORM
550
551app.state.config.ENABLE_API_KEY = ENABLE_API_KEY
552app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS = (
553 ENABLE_API_KEY_ENDPOINT_RESTRICTIONS
554)
555app.state.config.API_KEY_ALLOWED_ENDPOINTS = API_KEY_ALLOWED_ENDPOINTS
556
557app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN
558
559app.state.config.SHOW_ADMIN_DETAILS = SHOW_ADMIN_DETAILS
560app.state.config.ADMIN_EMAIL = ADMIN_EMAIL
561
562
563app.state.config.DEFAULT_MODELS = DEFAULT_MODELS
564app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS
565app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE
566
567app.state.config.USER_PERMISSIONS = USER_PERMISSIONS
568app.state.config.WEBHOOK_URL = WEBHOOK_URL
569app.state.config.BANNERS = WEBUI_BANNERS
570app.state.config.MODEL_ORDER_LIST = MODEL_ORDER_LIST
571
572
573app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS
574app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING
575app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING
576app.state.config.ENABLE_USER_WEBHOOKS = ENABLE_USER_WEBHOOKS
577
578app.state.config.ENABLE_EVALUATION_ARENA_MODELS = ENABLE_EVALUATION_ARENA_MODELS
579app.state.config.EVALUATION_ARENA_MODELS = EVALUATION_ARENA_MODELS
580
581app.state.config.OAUTH_USERNAME_CLAIM = OAUTH_USERNAME_CLAIM
582app.state.config.OAUTH_PICTURE_CLAIM = OAUTH_PICTURE_CLAIM
583app.state.config.OAUTH_EMAIL_CLAIM = OAUTH_EMAIL_CLAIM
584
585app.state.config.ENABLE_OAUTH_ROLE_MANAGEMENT = ENABLE_OAUTH_ROLE_MANAGEMENT
586app.state.config.OAUTH_ROLES_CLAIM = OAUTH_ROLES_CLAIM
587app.state.config.OAUTH_ALLOWED_ROLES = OAUTH_ALLOWED_ROLES
588app.state.config.OAUTH_ADMIN_ROLES = OAUTH_ADMIN_ROLES
589
590app.state.config.ENABLE_LDAP = ENABLE_LDAP
591app.state.config.LDAP_SERVER_LABEL = LDAP_SERVER_LABEL
592app.state.config.LDAP_SERVER_HOST = LDAP_SERVER_HOST
593app.state.config.LDAP_SERVER_PORT = LDAP_SERVER_PORT
594app.state.config.LDAP_ATTRIBUTE_FOR_MAIL = LDAP_ATTRIBUTE_FOR_MAIL
595app.state.config.LDAP_ATTRIBUTE_FOR_USERNAME = LDAP_ATTRIBUTE_FOR_USERNAME
596app.state.config.LDAP_APP_DN = LDAP_APP_DN
597app.state.config.LDAP_APP_PASSWORD = LDAP_APP_PASSWORD
598app.state.config.LDAP_SEARCH_BASE = LDAP_SEARCH_BASE
599app.state.config.LDAP_SEARCH_FILTERS = LDAP_SEARCH_FILTERS
600app.state.config.LDAP_USE_TLS = LDAP_USE_TLS
601app.state.config.LDAP_CA_CERT_FILE = LDAP_CA_CERT_FILE
602app.state.config.LDAP_CIPHERS = LDAP_CIPHERS
603
604
605app.state.AUTH_TRUSTED_EMAIL_HEADER = WEBUI_AUTH_TRUSTED_EMAIL_HEADER
606app.state.AUTH_TRUSTED_NAME_HEADER = WEBUI_AUTH_TRUSTED_NAME_HEADER
607app.state.EXTERNAL_PWA_MANIFEST_URL = EXTERNAL_PWA_MANIFEST_URL
608
609app.state.USER_COUNT = None
610app.state.TOOLS = {}
611app.state.FUNCTIONS = {}
612
613########################################
614#
615# RETRIEVAL
616#
617########################################
618
619
620app.state.config.TOP_K = RAG_TOP_K
621app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER
622app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD
623app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE
624app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT
625
626
627app.state.config.RAG_FULL_CONTEXT = RAG_FULL_CONTEXT
628app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL = BYPASS_EMBEDDING_AND_RETRIEVAL
629app.state.config.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH
630app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = ENABLE_WEB_LOADER_SSL_VERIFICATION
631
632app.state.config.CONTENT_EXTRACTION_ENGINE = CONTENT_EXTRACTION_ENGINE
633app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL
634app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL
635app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT
636app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY
637app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY
638
639app.state.config.TEXT_SPLITTER = RAG_TEXT_SPLITTER
640app.state.config.TIKTOKEN_ENCODING_NAME = TIKTOKEN_ENCODING_NAME
641
642app.state.config.CHUNK_SIZE = CHUNK_SIZE
643app.state.config.CHUNK_OVERLAP = CHUNK_OVERLAP
644
645app.state.config.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE
646app.state.config.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL
647app.state.config.RAG_EMBEDDING_BATCH_SIZE = RAG_EMBEDDING_BATCH_SIZE
648app.state.config.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL
649app.state.config.RAG_TEMPLATE = RAG_TEMPLATE
650
651app.state.config.RAG_OPENAI_API_BASE_URL = RAG_OPENAI_API_BASE_URL
652app.state.config.RAG_OPENAI_API_KEY = RAG_OPENAI_API_KEY
653
654app.state.config.RAG_OLLAMA_BASE_URL = RAG_OLLAMA_BASE_URL
655app.state.config.RAG_OLLAMA_API_KEY = RAG_OLLAMA_API_KEY
656
657app.state.config.PDF_EXTRACT_IMAGES = PDF_EXTRACT_IMAGES
658
659app.state.config.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE
660app.state.config.YOUTUBE_LOADER_PROXY_URL = YOUTUBE_LOADER_PROXY_URL
661
662
663app.state.config.ENABLE_WEB_SEARCH = ENABLE_WEB_SEARCH
664app.state.config.WEB_SEARCH_ENGINE = WEB_SEARCH_ENGINE
665app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST = WEB_SEARCH_DOMAIN_FILTER_LIST
666app.state.config.WEB_SEARCH_RESULT_COUNT = WEB_SEARCH_RESULT_COUNT
667app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS = WEB_SEARCH_CONCURRENT_REQUESTS
668app.state.config.WEB_LOADER_ENGINE = WEB_LOADER_ENGINE
669app.state.config.WEB_SEARCH_TRUST_ENV = WEB_SEARCH_TRUST_ENV
670app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = (
671 BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL
672)
673
674app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION = ENABLE_GOOGLE_DRIVE_INTEGRATION
675app.state.config.ENABLE_ONEDRIVE_INTEGRATION = ENABLE_ONEDRIVE_INTEGRATION
676app.state.config.SEARXNG_QUERY_URL = SEARXNG_QUERY_URL
677app.state.config.GOOGLE_PSE_API_KEY = GOOGLE_PSE_API_KEY
678app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID
679app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY
680app.state.config.KAGI_SEARCH_API_KEY = KAGI_SEARCH_API_KEY
681app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY
682app.state.config.BOCHA_SEARCH_API_KEY = BOCHA_SEARCH_API_KEY
683app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY
684app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS
685app.state.config.SERPER_API_KEY = SERPER_API_KEY
686app.state.config.SERPLY_API_KEY = SERPLY_API_KEY
687app.state.config.TAVILY_API_KEY = TAVILY_API_KEY
688app.state.config.SEARCHAPI_API_KEY = SEARCHAPI_API_KEY
689app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE
690app.state.config.SERPAPI_API_KEY = SERPAPI_API_KEY
691app.state.config.SERPAPI_ENGINE = SERPAPI_ENGINE
692app.state.config.JINA_API_KEY = JINA_API_KEY
693app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT
694app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY
695app.state.config.EXA_API_KEY = EXA_API_KEY
696app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY
697app.state.config.SOUGOU_API_SID = SOUGOU_API_SID
698app.state.config.SOUGOU_API_SK = SOUGOU_API_SK
699
700
701app.state.config.PLAYWRIGHT_WS_URL = PLAYWRIGHT_WS_URL
702app.state.config.PLAYWRIGHT_TIMEOUT = PLAYWRIGHT_TIMEOUT
703app.state.config.FIRECRAWL_API_BASE_URL = FIRECRAWL_API_BASE_URL
704app.state.config.FIRECRAWL_API_KEY = FIRECRAWL_API_KEY
705app.state.config.TAVILY_EXTRACT_DEPTH = TAVILY_EXTRACT_DEPTH
706
707app.state.EMBEDDING_FUNCTION = None
708app.state.ef = None
709app.state.rf = None
710
711app.state.YOUTUBE_LOADER_TRANSLATION = None
712
713
714try:
715 app.state.ef = get_ef(
716 app.state.config.RAG_EMBEDDING_ENGINE,
717 app.state.config.RAG_EMBEDDING_MODEL,
718 RAG_EMBEDDING_MODEL_AUTO_UPDATE,
719 )
720
721 app.state.rf = get_rf(
722 app.state.config.RAG_RERANKING_MODEL,
723 RAG_RERANKING_MODEL_AUTO_UPDATE,
724 )
725except Exception as e:
726 log.error(f"Error updating models: {e}")
727 pass
728
729
730app.state.EMBEDDING_FUNCTION = get_embedding_function(
731 app.state.config.RAG_EMBEDDING_ENGINE,
732 app.state.config.RAG_EMBEDDING_MODEL,
733 app.state.ef,
734 (
735 app.state.config.RAG_OPENAI_API_BASE_URL
736 if app.state.config.RAG_EMBEDDING_ENGINE == "openai"
737 else app.state.config.RAG_OLLAMA_BASE_URL
738 ),
739 (
740 app.state.config.RAG_OPENAI_API_KEY
741 if app.state.config.RAG_EMBEDDING_ENGINE == "openai"
742 else app.state.config.RAG_OLLAMA_API_KEY
743 ),
744 app.state.config.RAG_EMBEDDING_BATCH_SIZE,
745)
746
747########################################
748#
749# CODE EXECUTION
750#
751########################################
752
753app.state.config.ENABLE_CODE_EXECUTION = ENABLE_CODE_EXECUTION
754app.state.config.CODE_EXECUTION_ENGINE = CODE_EXECUTION_ENGINE
755app.state.config.CODE_EXECUTION_JUPYTER_URL = CODE_EXECUTION_JUPYTER_URL
756app.state.config.CODE_EXECUTION_JUPYTER_AUTH = CODE_EXECUTION_JUPYTER_AUTH
757app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN = CODE_EXECUTION_JUPYTER_AUTH_TOKEN
758app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD = (
759 CODE_EXECUTION_JUPYTER_AUTH_PASSWORD
760)
761app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT = CODE_EXECUTION_JUPYTER_TIMEOUT
762
763app.state.config.ENABLE_CODE_INTERPRETER = ENABLE_CODE_INTERPRETER
764app.state.config.CODE_INTERPRETER_ENGINE = CODE_INTERPRETER_ENGINE
765app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = CODE_INTERPRETER_PROMPT_TEMPLATE
766
767app.state.config.CODE_INTERPRETER_JUPYTER_URL = CODE_INTERPRETER_JUPYTER_URL
768app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = CODE_INTERPRETER_JUPYTER_AUTH
769app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = (
770 CODE_INTERPRETER_JUPYTER_AUTH_TOKEN
771)
772app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = (
773 CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD
774)
775app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT = CODE_INTERPRETER_JUPYTER_TIMEOUT
776
777########################################
778#
779# IMAGES
780#
781########################################
782
783app.state.config.IMAGE_GENERATION_ENGINE = IMAGE_GENERATION_ENGINE
784app.state.config.ENABLE_IMAGE_GENERATION = ENABLE_IMAGE_GENERATION
785app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = ENABLE_IMAGE_PROMPT_GENERATION
786
787app.state.config.IMAGES_OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL
788app.state.config.IMAGES_OPENAI_API_KEY = IMAGES_OPENAI_API_KEY
789
790app.state.config.IMAGES_GEMINI_API_BASE_URL = IMAGES_GEMINI_API_BASE_URL
791app.state.config.IMAGES_GEMINI_API_KEY = IMAGES_GEMINI_API_KEY
792
793app.state.config.IMAGE_GENERATION_MODEL = IMAGE_GENERATION_MODEL
794
795app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL
796app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH
797app.state.config.AUTOMATIC1111_CFG_SCALE = AUTOMATIC1111_CFG_SCALE
798app.state.config.AUTOMATIC1111_SAMPLER = AUTOMATIC1111_SAMPLER
799app.state.config.AUTOMATIC1111_SCHEDULER = AUTOMATIC1111_SCHEDULER
800app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL
801app.state.config.COMFYUI_API_KEY = COMFYUI_API_KEY
802app.state.config.COMFYUI_WORKFLOW = COMFYUI_WORKFLOW
803app.state.config.COMFYUI_WORKFLOW_NODES = COMFYUI_WORKFLOW_NODES
804
805app.state.config.IMAGE_SIZE = IMAGE_SIZE
806app.state.config.IMAGE_STEPS = IMAGE_STEPS
807
808
809########################################
810#
811# AUDIO
812#
813########################################
814
815app.state.config.STT_OPENAI_API_BASE_URL = AUDIO_STT_OPENAI_API_BASE_URL
816app.state.config.STT_OPENAI_API_KEY = AUDIO_STT_OPENAI_API_KEY
817app.state.config.STT_ENGINE = AUDIO_STT_ENGINE
818app.state.config.STT_MODEL = AUDIO_STT_MODEL
819
820app.state.config.WHISPER_MODEL = WHISPER_MODEL
821app.state.config.WHISPER_VAD_FILTER = WHISPER_VAD_FILTER
822app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY
823
824app.state.config.AUDIO_STT_AZURE_API_KEY = AUDIO_STT_AZURE_API_KEY
825app.state.config.AUDIO_STT_AZURE_REGION = AUDIO_STT_AZURE_REGION
826app.state.config.AUDIO_STT_AZURE_LOCALES = AUDIO_STT_AZURE_LOCALES
827
828app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL
829app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY
830app.state.config.TTS_ENGINE = AUDIO_TTS_ENGINE
831app.state.config.TTS_MODEL = AUDIO_TTS_MODEL
832app.state.config.TTS_VOICE = AUDIO_TTS_VOICE
833app.state.config.TTS_API_KEY = AUDIO_TTS_API_KEY
834app.state.config.TTS_SPLIT_ON = AUDIO_TTS_SPLIT_ON
835
836
837app.state.config.TTS_AZURE_SPEECH_REGION = AUDIO_TTS_AZURE_SPEECH_REGION
838app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT = AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT
839
840
841app.state.faster_whisper_model = None
842app.state.speech_synthesiser = None
843app.state.speech_speaker_embeddings_dataset = None
844
845
846########################################
847#
848# TASKS
849#
850########################################
851
852
853app.state.config.TASK_MODEL = TASK_MODEL
854app.state.config.TASK_MODEL_EXTERNAL = TASK_MODEL_EXTERNAL
855
856
857app.state.config.ENABLE_SEARCH_QUERY_GENERATION = ENABLE_SEARCH_QUERY_GENERATION
858app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION = ENABLE_RETRIEVAL_QUERY_GENERATION
859app.state.config.ENABLE_AUTOCOMPLETE_GENERATION = ENABLE_AUTOCOMPLETE_GENERATION
860app.state.config.ENABLE_TAGS_GENERATION = ENABLE_TAGS_GENERATION
861app.state.config.ENABLE_TITLE_GENERATION = ENABLE_TITLE_GENERATION
862
863
864app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE = TITLE_GENERATION_PROMPT_TEMPLATE
865app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE = TAGS_GENERATION_PROMPT_TEMPLATE
866app.state.config.IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE = (
867 IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE
868)
869
870app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = (
871 TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE
872)
873app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE = QUERY_GENERATION_PROMPT_TEMPLATE
874app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE = (
875 AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE
876)
877app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH = (
878 AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH
879)
880
881
882########################################
883#
884# WEBUI
885#
886########################################
887
888app.state.MODELS = {}
889
890
891class RedirectMiddleware(BaseHTTPMiddleware):
892 async def dispatch(self, request: Request, call_next):
893 # Check if the request is a GET request
894 if request.method == "GET":
895 path = request.url.path
896 query_params = dict(parse_qs(urlparse(str(request.url)).query))
897
898 # Check for the specific watch path and the presence of 'v' parameter
899 if path.endswith("/watch") and "v" in query_params:
900 video_id = query_params["v"][0] # Extract the first 'v' parameter
901 encoded_video_id = urlencode({"youtube": video_id})
902 redirect_url = f"/?{encoded_video_id}"
903 return RedirectResponse(url=redirect_url)
904
905 # Proceed with the normal flow of other requests
906 response = await call_next(request)
907 return response
908
909
910# Add the middleware to the app
911app.add_middleware(RedirectMiddleware)
912app.add_middleware(SecurityHeadersMiddleware)
913
914
915@app.middleware("http")
916async def commit_session_after_request(request: Request, call_next):
917 response = await call_next(request)
918 # log.debug("Commit session after request")
919 Session.commit()
920 return response
921
922
923@app.middleware("http")
924async def check_url(request: Request, call_next):
925 start_time = int(time.time())
926 request.state.token = get_http_authorization_cred(
927 request.headers.get("Authorization")
928 )
929
930 request.state.enable_api_key = app.state.config.ENABLE_API_KEY
931 response = await call_next(request)
932 process_time = int(time.time()) - start_time
933 response.headers["X-Process-Time"] = str(process_time)
934 return response
935
936
937@app.middleware("http")
938async def inspect_websocket(request: Request, call_next):
939 if (
940 "/ws/socket.io" in request.url.path
941 and request.query_params.get("transport") == "websocket"
942 ):
943 upgrade = (request.headers.get("Upgrade") or "").lower()
944 connection = (request.headers.get("Connection") or "").lower().split(",")
945 # Check that there's the correct headers for an upgrade, else reject the connection
946 # This is to work around this upstream issue: https://github.com/miguelgrinberg/python-engineio/issues/367
947 if upgrade != "websocket" or "upgrade" not in connection:
948 return JSONResponse(
949 status_code=status.HTTP_400_BAD_REQUEST,
950 content={"detail": "Invalid WebSocket upgrade request"},
951 )
952 return await call_next(request)
953
954
955app.add_middleware(
956 CORSMiddleware,
957 allow_origins=CORS_ALLOW_ORIGIN,
958 allow_credentials=True,
959 allow_methods=["*"],
960 allow_headers=["*"],
961)
962
963
964app.mount("/ws", socket_app)
965
966
967app.include_router(ollama.router, prefix="/ollama", tags=["ollama"])
968app.include_router(openai.router, prefix="/openai", tags=["openai"])
969
970
971app.include_router(pipelines.router, prefix="/api/v1/pipelines", tags=["pipelines"])
972app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
973app.include_router(images.router, prefix="/api/v1/images", tags=["images"])
974
975app.include_router(audio.router, prefix="/api/v1/audio", tags=["audio"])
976app.include_router(retrieval.router, prefix="/api/v1/retrieval", tags=["retrieval"])
977
978app.include_router(configs.router, prefix="/api/v1/configs", tags=["configs"])
979
980app.include_router(auths.router, prefix="/api/v1/auths", tags=["auths"])
981app.include_router(users.router, prefix="/api/v1/users", tags=["users"])
982
983
984app.include_router(channels.router, prefix="/api/v1/channels", tags=["channels"])
985app.include_router(chats.router, prefix="/api/v1/chats", tags=["chats"])
986
987app.include_router(models.router, prefix="/api/v1/models", tags=["models"])
988app.include_router(knowledge.router, prefix="/api/v1/knowledge", tags=["knowledge"])
989app.include_router(prompts.router, prefix="/api/v1/prompts", tags=["prompts"])
990app.include_router(tools.router, prefix="/api/v1/tools", tags=["tools"])
991
992app.include_router(memories.router, prefix="/api/v1/memories", tags=["memories"])
993app.include_router(folders.router, prefix="/api/v1/folders", tags=["folders"])
994app.include_router(groups.router, prefix="/api/v1/groups", tags=["groups"])
995app.include_router(files.router, prefix="/api/v1/files", tags=["files"])
996app.include_router(functions.router, prefix="/api/v1/functions", tags=["functions"])
997app.include_router(
998 evaluations.router, prefix="/api/v1/evaluations", tags=["evaluations"]
999)
1000app.include_router(utils.router, prefix="/api/v1/utils", tags=["utils"])
1001
1002
1003try:
1004 audit_level = AuditLevel(AUDIT_LOG_LEVEL)
1005except ValueError as e:
1006 logger.error(f"Invalid audit level: {AUDIT_LOG_LEVEL}. Error: {e}")
1007 audit_level = AuditLevel.NONE
1008
1009if audit_level != AuditLevel.NONE:
1010 app.add_middleware(
1011 AuditLoggingMiddleware,
1012 audit_level=audit_level,
1013 excluded_paths=AUDIT_EXCLUDED_PATHS,
1014 max_body_size=MAX_BODY_LOG_SIZE,
1015 )
1016##################################
1017#
1018# Chat Endpoints
1019#
1020##################################
1021
1022
1023@app.get("/api/models")
1024async def get_models(request: Request, user=Depends(get_verified_user)):
1025 def get_filtered_models(models, user):
1026 filtered_models = []
1027 for model in models:
1028 if model.get("arena"):
1029 if has_access(
1030 user.id,
1031 type="read",
1032 access_control=model.get("info", {})
1033 .get("meta", {})
1034 .get("access_control", {}),
1035 ):
1036 filtered_models.append(model)
1037 continue
1038
1039 model_info = Models.get_model_by_id(model["id"])
1040 if model_info:
1041 if user.id == model_info.user_id or has_access(
1042 user.id, type="read", access_control=model_info.access_control
1043 ):
1044 filtered_models.append(model)
1045
1046 return filtered_models
1047
1048 all_models = await get_all_models(request, user=user)
1049
1050 models = []
1051 for model in all_models:
1052 # Filter out filter pipelines
1053 if "pipeline" in model and model["pipeline"].get("type", None) == "filter":
1054 continue
1055
1056 try:
1057 model_tags = [
1058 tag.get("name")
1059 for tag in model.get("info", {}).get("meta", {}).get("tags", [])
1060 ]
1061 tags = [tag.get("name") for tag in model.get("tags", [])]
1062
1063 tags = list(set(model_tags + tags))
1064 model["tags"] = [{"name": tag} for tag in tags]
1065 except Exception as e:
1066 log.debug(f"Error processing model tags: {e}")
1067 model["tags"] = []
1068 pass
1069
1070 models.append(model)
1071
1072 model_order_list = request.app.state.config.MODEL_ORDER_LIST
1073 if model_order_list:
1074 model_order_dict = {model_id: i for i, model_id in enumerate(model_order_list)}
1075 # Sort models by order list priority, with fallback for those not in the list
1076 models.sort(
1077 key=lambda x: (model_order_dict.get(x["id"], float("inf")), x["name"])
1078 )
1079
1080 # Filter out models that the user does not have access to
1081 if user.role == "user" and not BYPASS_MODEL_ACCESS_CONTROL:
1082 models = get_filtered_models(models, user)
1083
1084 log.debug(
1085 f"/api/models returned filtered models accessible to the user: {json.dumps([model['id'] for model in models])}"
1086 )
1087 return {"data": models}
1088
1089
1090@app.get("/api/models/base")
1091async def get_base_models(request: Request, user=Depends(get_admin_user)):
1092 models = await get_all_base_models(request, user=user)
1093 return {"data": models}
1094
1095
1096@app.post("/api/chat/completions")
1097async def chat_completion(
1098 request: Request,
1099 form_data: dict,
1100 user=Depends(get_verified_user),
1101):
1102 if not request.app.state.MODELS:
1103 await get_all_models(request, user=user)
1104
1105 model_item = form_data.pop("model_item", {})
1106 tasks = form_data.pop("background_tasks", None)
1107
1108 metadata = {}
1109 try:
1110 if not model_item.get("direct", False):
1111 model_id = form_data.get("model", None)
1112 if model_id not in request.app.state.MODELS:
1113 raise Exception("Model not found")
1114
1115 model = request.app.state.MODELS[model_id]
1116 model_info = Models.get_model_by_id(model_id)
1117
1118 # Check if user has access to the model
1119 if not BYPASS_MODEL_ACCESS_CONTROL and user.role == "user":
1120 try:
1121 check_model_access(user, model)
1122 except Exception as e:
1123 raise e
1124 else:
1125 model = model_item
1126 model_info = None
1127
1128 request.state.direct = True
1129 request.state.model = model
1130
1131 metadata = {
1132 "user_id": user.id,
1133 "chat_id": form_data.pop("chat_id", None),
1134 "message_id": form_data.pop("id", None),
1135 "session_id": form_data.pop("session_id", None),
1136 "tool_ids": form_data.get("tool_ids", None),
1137 "tool_servers": form_data.pop("tool_servers", None),
1138 "files": form_data.get("files", None),
1139 "features": form_data.get("features", None),
1140 "variables": form_data.get("variables", None),
1141 "model": model,
1142 "direct": model_item.get("direct", False),
1143 **(
1144 {"function_calling": "native"}
1145 if form_data.get("params", {}).get("function_calling") == "native"
1146 or (
1147 model_info
1148 and model_info.params.model_dump().get("function_calling")
1149 == "native"
1150 )
1151 else {}
1152 ),
1153 }
1154
1155 request.state.metadata = metadata
1156 form_data["metadata"] = metadata
1157
1158 form_data, metadata, events = await process_chat_payload(
1159 request, form_data, user, metadata, model
1160 )
1161
1162 except Exception as e:
1163 log.debug(f"Error processing chat payload: {e}")
1164 if metadata.get("chat_id") and metadata.get("message_id"):
1165 # Update the chat message with the error
1166 Chats.upsert_message_to_chat_by_id_and_message_id(
1167 metadata["chat_id"],
1168 metadata["message_id"],
1169 {
1170 "error": {"content": str(e)},
1171 },
1172 )
1173
1174 raise HTTPException(
1175 status_code=status.HTTP_400_BAD_REQUEST,
1176 detail=str(e),
1177 )
1178
1179 try:
1180 # [[ MODDED 4/16/25 TO INJECT PERSONALITY ]]
1181 # [[ -------------------------------------]]
1182 # Inject personality into system prompt
1183 # Pull saved memory facts and inject into system prompt
1184 facts = ai_memory.get_facts()
1185 fact_lines = [f"{k} is {v}" for k, v in facts.items()]
1186 fact_block = "\n\nHere’s what you know so far:\n- " + "\n- ".join(fact_lines) if fact_lines else ""
1187
1188 system_prompt = personality.strip() + fact_block
1189
1190 # Wake-up primer (gets the AI warmed up with context)
1191 primer_msg = {
1192 "role": "user",
1193 "content": "This is just a warm-up to help you remember who you are. Please wait for my real question."
1194 }
1195
1196 form_data.setdefault("messages", [])
1197 form_data["messages"].insert(0, primer_msg)
1198 form_data["messages"].insert(0, {
1199 "role": "system",
1200 "content": system_prompt
1201 })
1202
1203
1204 # Check if user told the AI to remember something
1205 user_messages = [msg["content"] for msg in form_data["messages"] if msg.get("role") == "user"]
1206 last_user_msg = user_messages[-1] if user_messages else ""
1207
1208 if last_user_msg.lower().startswith("remember that"):
1209 try:
1210 _, memory = last_user_msg.split("remember that", 1)
1211 subject, fact = memory.strip().split(" is ", 1)
1212 ai_memory.save_fact(subject.strip(), fact.strip())
1213 print(f"💾 Remembered: {subject.strip()} = {fact.strip()}")
1214 except Exception as e:
1215 print(f"⚠️ Failed to save memory: {e}")
1216
1217 response = await chat_completion_handler(request, form_data, user)
1218
1219 return await process_chat_response(
1220 request, response, form_data, user, metadata, model, events, tasks
1221 )
1222 except Exception as e:
1223 raise HTTPException(
1224 status_code=status.HTTP_400_BAD_REQUEST,
1225 detail=str(e),
1226 )
1227
1228
1229# Alias for chat_completion (Legacy)
1230generate_chat_completions = chat_completion
1231generate_chat_completion = chat_completion
1232
1233
1234@app.post("/api/chat/completed")
1235async def chat_completed(
1236 request: Request, form_data: dict, user=Depends(get_verified_user)
1237):
1238 try:
1239 model_item = form_data.pop("model_item", {})
1240
1241 if model_item.get("direct", False):
1242 request.state.direct = True
1243 request.state.model = model_item
1244
1245 return await chat_completed_handler(request, form_data, user)
1246 except Exception as e:
1247 raise HTTPException(
1248 status_code=status.HTTP_400_BAD_REQUEST,
1249 detail=str(e),
1250 )
1251
1252
1253@app.post("/api/chat/actions/{action_id}")
1254async def chat_action(
1255 request: Request, action_id: str, form_data: dict, user=Depends(get_verified_user)
1256):
1257 try:
1258 model_item = form_data.pop("model_item", {})
1259
1260 if model_item.get("direct", False):
1261 request.state.direct = True
1262 request.state.model = model_item
1263
1264 return await chat_action_handler(request, action_id, form_data, user)
1265 except Exception as e:
1266 raise HTTPException(
1267 status_code=status.HTTP_400_BAD_REQUEST,
1268 detail=str(e),
1269 )
1270
1271
1272@app.post("/api/tasks/stop/{task_id}")
1273async def stop_task_endpoint(task_id: str, user=Depends(get_verified_user)):
1274 try:
1275 result = await stop_task(task_id)
1276 return result
1277 except ValueError as e:
1278 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
1279
1280
1281@app.get("/api/tasks")
1282async def list_tasks_endpoint(user=Depends(get_verified_user)):
1283 return {"tasks": list_tasks()}
1284
1285
1286@app.get("/api/tasks/chat/{chat_id}")
1287async def list_tasks_by_chat_id_endpoint(chat_id: str, user=Depends(get_verified_user)):
1288 chat = Chats.get_chat_by_id(chat_id)
1289 if chat is None or chat.user_id != user.id:
1290 return {"task_ids": []}
1291
1292 task_ids = list_task_ids_by_chat_id(chat_id)
1293
1294 print(f"Task IDs for chat {chat_id}: {task_ids}")
1295 return {"task_ids": task_ids}
1296
1297
1298##################################
1299#
1300# Config Endpoints
1301#
1302##################################
1303
1304
1305@app.get("/api/config")
1306async def get_app_config(request: Request):
1307 user = None
1308 if "token" in request.cookies:
1309 token = request.cookies.get("token")
1310 try:
1311 data = decode_token(token)
1312 except Exception as e:
1313 log.debug(e)
1314 raise HTTPException(
1315 status_code=status.HTTP_401_UNAUTHORIZED,
1316 detail="Invalid token",
1317 )
1318 if data is not None and "id" in data:
1319 user = Users.get_user_by_id(data["id"])
1320
1321 user_count = Users.get_num_users()
1322 onboarding = False
1323
1324 if user is None:
1325 onboarding = user_count == 0
1326
1327 return {
1328 **({"onboarding": True} if onboarding else {}),
1329 "status": True,
1330 "name": app.state.WEBUI_NAME,
1331 "version": VERSION,
1332 "default_locale": str(DEFAULT_LOCALE),
1333 "oauth": {
1334 "providers": {
1335 name: config.get("name", name)
1336 for name, config in OAUTH_PROVIDERS.items()
1337 }
1338 },
1339 "features": {
1340 "auth": WEBUI_AUTH,
1341 "auth_trusted_header": bool(app.state.AUTH_TRUSTED_EMAIL_HEADER),
1342 "enable_ldap": app.state.config.ENABLE_LDAP,
1343 "enable_api_key": app.state.config.ENABLE_API_KEY,
1344 "enable_signup": app.state.config.ENABLE_SIGNUP,
1345 "enable_login_form": app.state.config.ENABLE_LOGIN_FORM,
1346 "enable_websocket": ENABLE_WEBSOCKET_SUPPORT,
1347 **(
1348 {
1349 "enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS,
1350 "enable_channels": app.state.config.ENABLE_CHANNELS,
1351 "enable_web_search": app.state.config.ENABLE_WEB_SEARCH,
1352 "enable_code_execution": app.state.config.ENABLE_CODE_EXECUTION,
1353 "enable_code_interpreter": app.state.config.ENABLE_CODE_INTERPRETER,
1354 "enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION,
1355 "enable_autocomplete_generation": app.state.config.ENABLE_AUTOCOMPLETE_GENERATION,
1356 "enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING,
1357 "enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING,
1358 "enable_user_webhooks": app.state.config.ENABLE_USER_WEBHOOKS,
1359 "enable_admin_export": ENABLE_ADMIN_EXPORT,
1360 "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS,
1361 "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION,
1362 "enable_onedrive_integration": app.state.config.ENABLE_ONEDRIVE_INTEGRATION,
1363 }
1364 if user is not None
1365 else {}
1366 ),
1367 },
1368 **(
1369 {
1370 "default_models": app.state.config.DEFAULT_MODELS,
1371 "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS,
1372 "user_count": user_count,
1373 "code": {
1374 "engine": app.state.config.CODE_EXECUTION_ENGINE,
1375 },
1376 "audio": {
1377 "tts": {
1378 "engine": app.state.config.TTS_ENGINE,
1379 "voice": app.state.config.TTS_VOICE,
1380 "split_on": app.state.config.TTS_SPLIT_ON,
1381 },
1382 "stt": {
1383 "engine": app.state.config.STT_ENGINE,
1384 },
1385 },
1386 "file": {
1387 "max_size": app.state.config.FILE_MAX_SIZE,
1388 "max_count": app.state.config.FILE_MAX_COUNT,
1389 },
1390 "permissions": {**app.state.config.USER_PERMISSIONS},
1391 "google_drive": {
1392 "client_id": GOOGLE_DRIVE_CLIENT_ID.value,
1393 "api_key": GOOGLE_DRIVE_API_KEY.value,
1394 },
1395 "onedrive": {"client_id": ONEDRIVE_CLIENT_ID.value},
1396 "license_metadata": app.state.LICENSE_METADATA,
1397 **(
1398 {
1399 "active_entries": app.state.USER_COUNT,
1400 }
1401 if user.role == "admin"
1402 else {}
1403 ),
1404 }
1405 if user is not None
1406 else {}
1407 ),
1408 }
1409
1410
1411class UrlForm(BaseModel):
1412 url: str
1413
1414
1415@app.get("/api/webhook")
1416async def get_webhook_url(user=Depends(get_admin_user)):
1417 return {
1418 "url": app.state.config.WEBHOOK_URL,
1419 }
1420
1421
1422@app.post("/api/webhook")
1423async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)):
1424 app.state.config.WEBHOOK_URL = form_data.url
1425 app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL
1426 return {"url": app.state.config.WEBHOOK_URL}
1427
1428
1429@app.get("/api/version")
1430async def get_app_version():
1431 return {
1432 "version": VERSION,
1433 }
1434
1435
1436@app.get("/api/version/updates")
1437async def get_app_latest_release_version(user=Depends(get_verified_user)):
1438 if OFFLINE_MODE:
1439 log.debug(
1440 f"Offline mode is enabled, returning current version as latest version"
1441 )
1442 return {"current": VERSION, "latest": VERSION}
1443 try:
1444 timeout = aiohttp.ClientTimeout(total=1)
1445 async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
1446 async with session.get(
1447 "https://api.github.com/repos/open-webui/open-webui/releases/latest"
1448 ) as response:
1449 response.raise_for_status()
1450 data = await response.json()
1451 latest_version = data["tag_name"]
1452
1453 return {"current": VERSION, "latest": latest_version[1:]}
1454 except Exception as e:
1455 log.debug(e)
1456 return {"current": VERSION, "latest": VERSION}
1457
1458
1459@app.get("/api/changelog")
1460async def get_app_changelog():
1461 return {key: CHANGELOG[key] for idx, key in enumerate(CHANGELOG) if idx < 5}
1462
1463
1464############################
1465# OAuth Login & Callback
1466############################
1467
1468# SessionMiddleware is used by authlib for oauth
1469if len(OAUTH_PROVIDERS) > 0:
1470 app.add_middleware(
1471 SessionMiddleware,
1472 secret_key=WEBUI_SECRET_KEY,
1473 session_cookie="oui-session",
1474 same_site=WEBUI_SESSION_COOKIE_SAME_SITE,
1475 https_only=WEBUI_SESSION_COOKIE_SECURE,
1476 )
1477
1478
1479@app.get("/oauth/{provider}/login")
1480async def oauth_login(provider: str, request: Request):
1481 return await oauth_manager.handle_login(request, provider)
1482
1483
1484# OAuth login logic is as follows:
1485# 1. Attempt to find a user with matching subject ID, tied to the provider
1486# 2. If OAUTH_MERGE_ACCOUNTS_BY_EMAIL is true, find a user with the email address provided via OAuth
1487# - This is considered insecure in general, as OAuth providers do not always verify email addresses
1488# 3. If there is no user, and ENABLE_OAUTH_SIGNUP is true, create a user
1489# - Email addresses are considered unique, so we fail registration if the email address is already taken
1490@app.get("/oauth/{provider}/callback")
1491async def oauth_callback(provider: str, request: Request, response: Response):
1492 return await oauth_manager.handle_callback(request, provider, response)
1493
1494
1495@app.get("/manifest.json")
1496async def get_manifest_json():
1497 if app.state.EXTERNAL_PWA_MANIFEST_URL:
1498 return requests.get(app.state.EXTERNAL_PWA_MANIFEST_URL).json()
1499 else:
1500 return {
1501 "name": app.state.WEBUI_NAME,
1502 "short_name": app.state.WEBUI_NAME,
1503 "description": "Open WebUI is an open, extensible, user-friendly interface for AI that adapts to your workflow.",
1504 "start_url": "/",
1505 "display": "standalone",
1506 "background_color": "#343541",
1507 "orientation": "natural",
1508 "icons": [
1509 {
1510 "src": "/static/logo.png",
1511 "type": "image/png",
1512 "sizes": "500x500",
1513 "purpose": "any",
1514 },
1515 {
1516 "src": "/static/logo.png",
1517 "type": "image/png",
1518 "sizes": "500x500",
1519 "purpose": "maskable",
1520 },
1521 ],
1522 }
1523
1524
1525@app.get("/opensearch.xml")
1526async def get_opensearch_xml():
1527 xml_content = rf"""
1528 <OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
1529 <ShortName>{app.state.WEBUI_NAME}</ShortName>
1530 <Description>Search {app.state.WEBUI_NAME}</Description>
1531 <InputEncoding>UTF-8</InputEncoding>
1532 <Image width="16" height="16" type="image/x-icon">{app.state.config.WEBUI_URL}/static/favicon.png</Image>
1533 <Url type="text/html" method="get" template="{app.state.config.WEBUI_URL}/?q={"{searchTerms}"}"/>
1534 <moz:SearchForm>{app.state.config.WEBUI_URL}</moz:SearchForm>
1535 </OpenSearchDescription>
1536 """
1537 return Response(content=xml_content, media_type="application/xml")
1538
1539
1540@app.get("/health")
1541async def healthcheck():
1542 return {"status": True}
1543
1544
1545@app.get("/health/db")
1546async def healthcheck_with_db():
1547 Session.execute(text("SELECT 1;")).all()
1548 return {"status": True}
1549
1550
1551app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
1552app.mount("/cache", StaticFiles(directory=CACHE_DIR), name="cache")
1553
1554
1555def swagger_ui_html(*args, **kwargs):
1556 return get_swagger_ui_html(
1557 *args,
1558 **kwargs,
1559 swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",
1560 swagger_css_url="/static/swagger-ui/swagger-ui.css",
1561 swagger_favicon_url="/static/swagger-ui/favicon.png",
1562 )
1563
1564
1565applications.get_swagger_ui_html = swagger_ui_html
1566
1567if os.path.exists(FRONTEND_BUILD_DIR):
1568 mimetypes.add_type("text/javascript", ".js")
1569 app.mount(
1570 "/",
1571 SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True),
1572 name="spa-static-files",
1573 )
1574else:
1575 log.warning(
1576 f"Frontend build directory not found at '{FRONTEND_BUILD_DIR}'. Serving API only."
1577 )
1578