|
@@ -2,12 +2,13 @@ import json
|
|
|
import logging
|
|
|
import os
|
|
|
import shutil
|
|
|
+import base64
|
|
|
+
|
|
|
from datetime import datetime
|
|
|
from pathlib import Path
|
|
|
from typing import Generic, Optional, TypeVar
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
-import chromadb
|
|
|
import requests
|
|
|
from pydantic import BaseModel
|
|
|
from sqlalchemy import JSON, Column, DateTime, Integer, func
|
|
@@ -42,7 +43,7 @@ logging.getLogger("uvicorn.access").addFilter(EndpointFilter())
|
|
|
|
|
|
# Function to run the alembic migrations
|
|
|
def run_migrations():
|
|
|
- print("Running migrations")
|
|
|
+ log.info("Running migrations")
|
|
|
try:
|
|
|
from alembic import command
|
|
|
from alembic.config import Config
|
|
@@ -55,7 +56,7 @@ def run_migrations():
|
|
|
|
|
|
command.upgrade(alembic_cfg, "head")
|
|
|
except Exception as e:
|
|
|
- print(f"Error: {e}")
|
|
|
+ log.exception(f"Error running migrations: {e}")
|
|
|
|
|
|
|
|
|
run_migrations()
|
|
@@ -586,6 +587,14 @@ load_oauth_providers()
|
|
|
|
|
|
STATIC_DIR = Path(os.getenv("STATIC_DIR", OPEN_WEBUI_DIR / "static")).resolve()
|
|
|
|
|
|
+for file_path in (FRONTEND_BUILD_DIR / "static").glob("**/*"):
|
|
|
+ if file_path.is_file():
|
|
|
+ target_path = STATIC_DIR / file_path.relative_to(
|
|
|
+ (FRONTEND_BUILD_DIR / "static")
|
|
|
+ )
|
|
|
+ target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
+ shutil.copyfile(file_path, target_path)
|
|
|
+
|
|
|
frontend_favicon = FRONTEND_BUILD_DIR / "static" / "favicon.png"
|
|
|
|
|
|
if frontend_favicon.exists():
|
|
@@ -593,8 +602,6 @@ if frontend_favicon.exists():
|
|
|
shutil.copyfile(frontend_favicon, STATIC_DIR / "favicon.png")
|
|
|
except Exception as e:
|
|
|
logging.error(f"An error occurred: {e}")
|
|
|
-else:
|
|
|
- logging.warning(f"Frontend favicon not found at {frontend_favicon}")
|
|
|
|
|
|
frontend_splash = FRONTEND_BUILD_DIR / "static" / "splash.png"
|
|
|
|
|
@@ -603,12 +610,18 @@ if frontend_splash.exists():
|
|
|
shutil.copyfile(frontend_splash, STATIC_DIR / "splash.png")
|
|
|
except Exception as e:
|
|
|
logging.error(f"An error occurred: {e}")
|
|
|
-else:
|
|
|
- logging.warning(f"Frontend splash not found at {frontend_splash}")
|
|
|
+
|
|
|
+frontend_loader = FRONTEND_BUILD_DIR / "static" / "loader.js"
|
|
|
+
|
|
|
+if frontend_loader.exists():
|
|
|
+ try:
|
|
|
+ shutil.copyfile(frontend_loader, STATIC_DIR / "loader.js")
|
|
|
+ except Exception as e:
|
|
|
+ logging.error(f"An error occurred: {e}")
|
|
|
|
|
|
|
|
|
####################################
|
|
|
-# CUSTOM_NAME
|
|
|
+# CUSTOM_NAME (Legacy)
|
|
|
####################################
|
|
|
|
|
|
CUSTOM_NAME = os.environ.get("CUSTOM_NAME", "")
|
|
@@ -650,6 +663,12 @@ if CUSTOM_NAME:
|
|
|
pass
|
|
|
|
|
|
|
|
|
+####################################
|
|
|
+# LICENSE_KEY
|
|
|
+####################################
|
|
|
+
|
|
|
+LICENSE_KEY = os.environ.get("LICENSE_KEY", "")
|
|
|
+
|
|
|
####################################
|
|
|
# STORAGE PROVIDER
|
|
|
####################################
|
|
@@ -660,27 +679,47 @@ S3_ACCESS_KEY_ID = os.environ.get("S3_ACCESS_KEY_ID", None)
|
|
|
S3_SECRET_ACCESS_KEY = os.environ.get("S3_SECRET_ACCESS_KEY", None)
|
|
|
S3_REGION_NAME = os.environ.get("S3_REGION_NAME", None)
|
|
|
S3_BUCKET_NAME = os.environ.get("S3_BUCKET_NAME", None)
|
|
|
+S3_KEY_PREFIX = os.environ.get("S3_KEY_PREFIX", None)
|
|
|
S3_ENDPOINT_URL = os.environ.get("S3_ENDPOINT_URL", None)
|
|
|
+S3_USE_ACCELERATE_ENDPOINT = (
|
|
|
+ os.environ.get("S3_USE_ACCELERATE_ENDPOINT", "False").lower() == "true"
|
|
|
+)
|
|
|
+S3_ADDRESSING_STYLE = os.environ.get("S3_ADDRESSING_STYLE", None)
|
|
|
|
|
|
GCS_BUCKET_NAME = os.environ.get("GCS_BUCKET_NAME", None)
|
|
|
GOOGLE_APPLICATION_CREDENTIALS_JSON = os.environ.get(
|
|
|
"GOOGLE_APPLICATION_CREDENTIALS_JSON", None
|
|
|
)
|
|
|
|
|
|
+AZURE_STORAGE_ENDPOINT = os.environ.get("AZURE_STORAGE_ENDPOINT", None)
|
|
|
+AZURE_STORAGE_CONTAINER_NAME = os.environ.get("AZURE_STORAGE_CONTAINER_NAME", None)
|
|
|
+AZURE_STORAGE_KEY = os.environ.get("AZURE_STORAGE_KEY", None)
|
|
|
+
|
|
|
####################################
|
|
|
# File Upload DIR
|
|
|
####################################
|
|
|
|
|
|
-UPLOAD_DIR = f"{DATA_DIR}/uploads"
|
|
|
-Path(UPLOAD_DIR).mkdir(parents=True, exist_ok=True)
|
|
|
+UPLOAD_DIR = DATA_DIR / "uploads"
|
|
|
+UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
|
|
|
####################################
|
|
|
# Cache DIR
|
|
|
####################################
|
|
|
|
|
|
-CACHE_DIR = f"{DATA_DIR}/cache"
|
|
|
-Path(CACHE_DIR).mkdir(parents=True, exist_ok=True)
|
|
|
+CACHE_DIR = DATA_DIR / "cache"
|
|
|
+CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
+
|
|
|
+
|
|
|
+####################################
|
|
|
+# DIRECT CONNECTIONS
|
|
|
+####################################
|
|
|
+
|
|
|
+ENABLE_DIRECT_CONNECTIONS = PersistentConfig(
|
|
|
+ "ENABLE_DIRECT_CONNECTIONS",
|
|
|
+ "direct.enable",
|
|
|
+ os.environ.get("ENABLE_DIRECT_CONNECTIONS", "True").lower() == "true",
|
|
|
+)
|
|
|
|
|
|
####################################
|
|
|
# OLLAMA_BASE_URL
|
|
@@ -755,6 +794,9 @@ ENABLE_OPENAI_API = PersistentConfig(
|
|
|
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
|
|
|
OPENAI_API_BASE_URL = os.environ.get("OPENAI_API_BASE_URL", "")
|
|
|
|
|
|
+GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
|
|
|
+GEMINI_API_BASE_URL = os.environ.get("GEMINI_API_BASE_URL", "")
|
|
|
+
|
|
|
|
|
|
if OPENAI_API_BASE_URL == "":
|
|
|
OPENAI_API_BASE_URL = "https://api.openai.com/v1"
|
|
@@ -927,6 +969,12 @@ USER_PERMISSIONS_FEATURES_IMAGE_GENERATION = (
|
|
|
== "true"
|
|
|
)
|
|
|
|
|
|
+USER_PERMISSIONS_FEATURES_CODE_INTERPRETER = (
|
|
|
+ os.environ.get("USER_PERMISSIONS_FEATURES_CODE_INTERPRETER", "True").lower()
|
|
|
+ == "true"
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
DEFAULT_USER_PERMISSIONS = {
|
|
|
"workspace": {
|
|
|
"models": USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS,
|
|
@@ -944,6 +992,7 @@ DEFAULT_USER_PERMISSIONS = {
|
|
|
"features": {
|
|
|
"web_search": USER_PERMISSIONS_FEATURES_WEB_SEARCH,
|
|
|
"image_generation": USER_PERMISSIONS_FEATURES_IMAGE_GENERATION,
|
|
|
+ "code_interpreter": USER_PERMISSIONS_FEATURES_CODE_INTERPRETER,
|
|
|
},
|
|
|
}
|
|
|
|
|
@@ -1052,7 +1101,7 @@ try:
|
|
|
banners = json.loads(os.environ.get("WEBUI_BANNERS", "[]"))
|
|
|
banners = [BannerModel(**banner) for banner in banners]
|
|
|
except Exception as e:
|
|
|
- print(f"Error loading WEBUI_BANNERS: {e}")
|
|
|
+ log.exception(f"Error loading WEBUI_BANNERS: {e}")
|
|
|
banners = []
|
|
|
|
|
|
WEBUI_BANNERS = PersistentConfig("WEBUI_BANNERS", "ui.banners", banners)
|
|
@@ -1094,21 +1143,27 @@ TITLE_GENERATION_PROMPT_TEMPLATE = PersistentConfig(
|
|
|
os.environ.get("TITLE_GENERATION_PROMPT_TEMPLATE", ""),
|
|
|
)
|
|
|
|
|
|
-DEFAULT_TITLE_GENERATION_PROMPT_TEMPLATE = """Create a concise, 3-5 word title with an emoji as a title for the chat history, in the given language. Suitable Emojis for the summary can be used to enhance understanding but avoid quotation marks or special formatting. RESPOND ONLY WITH THE TITLE TEXT.
|
|
|
-
|
|
|
-Examples of titles:
|
|
|
-📉 Stock Market Trends
|
|
|
-🍪 Perfect Chocolate Chip Recipe
|
|
|
-Evolution of Music Streaming
|
|
|
-Remote Work Productivity Tips
|
|
|
-Artificial Intelligence in Healthcare
|
|
|
-🎮 Video Game Development Insights
|
|
|
-
|
|
|
+DEFAULT_TITLE_GENERATION_PROMPT_TEMPLATE = """### Task:
|
|
|
+Generate a concise, 3-5 word title with an emoji summarizing the chat history.
|
|
|
+### Guidelines:
|
|
|
+- The title should clearly represent the main theme or subject of the conversation.
|
|
|
+- Use emojis that enhance understanding of the topic, but avoid quotation marks or special formatting.
|
|
|
+- Write the title in the chat's primary language; default to English if multilingual.
|
|
|
+- Prioritize accuracy over excessive creativity; keep it clear and simple.
|
|
|
+### Output:
|
|
|
+JSON format: { "title": "your concise title here" }
|
|
|
+### Examples:
|
|
|
+- { "title": "📉 Stock Market Trends" },
|
|
|
+- { "title": "🍪 Perfect Chocolate Chip Recipe" },
|
|
|
+- { "title": "Evolution of Music Streaming" },
|
|
|
+- { "title": "Remote Work Productivity Tips" },
|
|
|
+- { "title": "Artificial Intelligence in Healthcare" },
|
|
|
+- { "title": "🎮 Video Game Development Insights" }
|
|
|
+### Chat History:
|
|
|
<chat_history>
|
|
|
{{MESSAGES:END:2}}
|
|
|
</chat_history>"""
|
|
|
|
|
|
-
|
|
|
TAGS_GENERATION_PROMPT_TEMPLATE = PersistentConfig(
|
|
|
"TAGS_GENERATION_PROMPT_TEMPLATE",
|
|
|
"task.tags.prompt_template",
|
|
@@ -1165,6 +1220,12 @@ ENABLE_TAGS_GENERATION = PersistentConfig(
|
|
|
os.environ.get("ENABLE_TAGS_GENERATION", "True").lower() == "true",
|
|
|
)
|
|
|
|
|
|
+ENABLE_TITLE_GENERATION = PersistentConfig(
|
|
|
+ "ENABLE_TITLE_GENERATION",
|
|
|
+ "task.title.enable",
|
|
|
+ os.environ.get("ENABLE_TITLE_GENERATION", "True").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
|
|
|
ENABLE_SEARCH_QUERY_GENERATION = PersistentConfig(
|
|
|
"ENABLE_SEARCH_QUERY_GENERATION",
|
|
@@ -1277,7 +1338,28 @@ TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = PersistentConfig(
|
|
|
)
|
|
|
|
|
|
|
|
|
-DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = """Available Tools: {{TOOLS}}\nReturn an empty string if no tools match the query. If a function tool matches, construct and return a JSON object in the format {\"name\": \"functionName\", \"parameters\": {\"requiredFunctionParamKey\": \"requiredFunctionParamValue\"}} using the appropriate tool and its parameters. Only return the object and limit the response to the JSON object without additional text."""
|
|
|
+DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = """Available Tools: {{TOOLS}}
|
|
|
+
|
|
|
+Your task is to choose and return the correct tool(s) from the list of available tools based on the query. Follow these guidelines:
|
|
|
+
|
|
|
+- Return only the JSON object, without any additional text or explanation.
|
|
|
+
|
|
|
+- If no tools match the query, return an empty array:
|
|
|
+ {
|
|
|
+ "tool_calls": []
|
|
|
+ }
|
|
|
+
|
|
|
+- If one or more tools match the query, construct a JSON response containing a "tool_calls" array with objects that include:
|
|
|
+ - "name": The tool's name.
|
|
|
+ - "parameters": A dictionary of required parameters and their corresponding values.
|
|
|
+
|
|
|
+The format for the JSON response is strictly:
|
|
|
+{
|
|
|
+ "tool_calls": [
|
|
|
+ {"name": "toolName1", "parameters": {"key1": "value1"}},
|
|
|
+ {"name": "toolName2", "parameters": {"key2": "value2"}}
|
|
|
+ ]
|
|
|
+}"""
|
|
|
|
|
|
|
|
|
DEFAULT_EMOJI_GENERATION_PROMPT_TEMPLATE = """Your task is to reflect the speaker's likely facial expression through a fitting emoji. Interpret emotions from the message and reflect their facial expression using fitting, diverse emojis (e.g., 😊, 😢, 😡, 😱).
|
|
@@ -1290,6 +1372,131 @@ Your task is to synthesize these responses into a single, high-quality response.
|
|
|
|
|
|
Responses from models: {{responses}}"""
|
|
|
|
|
|
+
|
|
|
+####################################
|
|
|
+# Code Interpreter
|
|
|
+####################################
|
|
|
+
|
|
|
+
|
|
|
+CODE_EXECUTION_ENGINE = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_ENGINE",
|
|
|
+ "code_execution.engine",
|
|
|
+ os.environ.get("CODE_EXECUTION_ENGINE", "pyodide"),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_EXECUTION_JUPYTER_URL = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_JUPYTER_URL",
|
|
|
+ "code_execution.jupyter.url",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_URL", ""),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_EXECUTION_JUPYTER_AUTH = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_JUPYTER_AUTH",
|
|
|
+ "code_execution.jupyter.auth",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH", ""),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_EXECUTION_JUPYTER_AUTH_TOKEN = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_JUPYTER_AUTH_TOKEN",
|
|
|
+ "code_execution.jupyter.auth_token",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH_TOKEN", ""),
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+CODE_EXECUTION_JUPYTER_AUTH_PASSWORD = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_JUPYTER_AUTH_PASSWORD",
|
|
|
+ "code_execution.jupyter.auth_password",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH_PASSWORD", ""),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_EXECUTION_JUPYTER_TIMEOUT = PersistentConfig(
|
|
|
+ "CODE_EXECUTION_JUPYTER_TIMEOUT",
|
|
|
+ "code_execution.jupyter.timeout",
|
|
|
+ int(os.environ.get("CODE_EXECUTION_JUPYTER_TIMEOUT", "60")),
|
|
|
+)
|
|
|
+
|
|
|
+ENABLE_CODE_INTERPRETER = PersistentConfig(
|
|
|
+ "ENABLE_CODE_INTERPRETER",
|
|
|
+ "code_interpreter.enable",
|
|
|
+ os.environ.get("ENABLE_CODE_INTERPRETER", "True").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_ENGINE = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_ENGINE",
|
|
|
+ "code_interpreter.engine",
|
|
|
+ os.environ.get("CODE_INTERPRETER_ENGINE", "pyodide"),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_PROMPT_TEMPLATE = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_PROMPT_TEMPLATE",
|
|
|
+ "code_interpreter.prompt_template",
|
|
|
+ os.environ.get("CODE_INTERPRETER_PROMPT_TEMPLATE", ""),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_JUPYTER_URL = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_URL",
|
|
|
+ "code_interpreter.jupyter.url",
|
|
|
+ os.environ.get(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_URL", os.environ.get("CODE_EXECUTION_JUPYTER_URL", "")
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_JUPYTER_AUTH = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH",
|
|
|
+ "code_interpreter.jupyter.auth",
|
|
|
+ os.environ.get(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH", ""),
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH_TOKEN",
|
|
|
+ "code_interpreter.jupyter.auth_token",
|
|
|
+ os.environ.get(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH_TOKEN",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH_TOKEN", ""),
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD",
|
|
|
+ "code_interpreter.jupyter.auth_password",
|
|
|
+ os.environ.get(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_AUTH_PASSWORD", ""),
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+CODE_INTERPRETER_JUPYTER_TIMEOUT = PersistentConfig(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_TIMEOUT",
|
|
|
+ "code_interpreter.jupyter.timeout",
|
|
|
+ int(
|
|
|
+ os.environ.get(
|
|
|
+ "CODE_INTERPRETER_JUPYTER_TIMEOUT",
|
|
|
+ os.environ.get("CODE_EXECUTION_JUPYTER_TIMEOUT", "60"),
|
|
|
+ )
|
|
|
+ ),
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+DEFAULT_CODE_INTERPRETER_PROMPT = """
|
|
|
+#### Tools Available
|
|
|
+
|
|
|
+1. **Code Interpreter**: `<code_interpreter type="code" lang="python"></code_interpreter>`
|
|
|
+ - You have access to a Python shell that runs directly in the user's browser, enabling fast execution of code for analysis, calculations, or problem-solving. Use it in this response.
|
|
|
+ - The Python code you write can incorporate a wide array of libraries, handle data manipulation or visualization, perform API calls for web-related tasks, or tackle virtually any computational challenge. Use this flexibility to **think outside the box, craft elegant solutions, and harness Python's full potential**.
|
|
|
+ - To use it, **you must enclose your code within `<code_interpreter type="code" lang="python">` XML tags** and stop right away. If you don't, the code won't execute. Do NOT use triple backticks.
|
|
|
+ - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user.
|
|
|
+ - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.**
|
|
|
+ - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary.
|
|
|
+ - **If a link to an image, audio, or any file is provided in markdown format in the output, ALWAYS regurgitate word for word, explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.**
|
|
|
+ - All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity.
|
|
|
+
|
|
|
+Ensure that the tools are effectively utilized to achieve the highest-quality analysis for the user."""
|
|
|
+
|
|
|
+
|
|
|
####################################
|
|
|
# Vector Database
|
|
|
####################################
|
|
@@ -1298,27 +1505,34 @@ VECTOR_DB = os.environ.get("VECTOR_DB", "chroma")
|
|
|
|
|
|
# Chroma
|
|
|
CHROMA_DATA_PATH = f"{DATA_DIR}/vector_db"
|
|
|
-CHROMA_TENANT = os.environ.get("CHROMA_TENANT", chromadb.DEFAULT_TENANT)
|
|
|
-CHROMA_DATABASE = os.environ.get("CHROMA_DATABASE", chromadb.DEFAULT_DATABASE)
|
|
|
-CHROMA_HTTP_HOST = os.environ.get("CHROMA_HTTP_HOST", "")
|
|
|
-CHROMA_HTTP_PORT = int(os.environ.get("CHROMA_HTTP_PORT", "8000"))
|
|
|
-CHROMA_CLIENT_AUTH_PROVIDER = os.environ.get("CHROMA_CLIENT_AUTH_PROVIDER", "")
|
|
|
-CHROMA_CLIENT_AUTH_CREDENTIALS = os.environ.get("CHROMA_CLIENT_AUTH_CREDENTIALS", "")
|
|
|
-# Comma-separated list of header=value pairs
|
|
|
-CHROMA_HTTP_HEADERS = os.environ.get("CHROMA_HTTP_HEADERS", "")
|
|
|
-if CHROMA_HTTP_HEADERS:
|
|
|
- CHROMA_HTTP_HEADERS = dict(
|
|
|
- [pair.split("=") for pair in CHROMA_HTTP_HEADERS.split(",")]
|
|
|
+
|
|
|
+if VECTOR_DB == "chroma":
|
|
|
+ import chromadb
|
|
|
+
|
|
|
+ CHROMA_TENANT = os.environ.get("CHROMA_TENANT", chromadb.DEFAULT_TENANT)
|
|
|
+ CHROMA_DATABASE = os.environ.get("CHROMA_DATABASE", chromadb.DEFAULT_DATABASE)
|
|
|
+ CHROMA_HTTP_HOST = os.environ.get("CHROMA_HTTP_HOST", "")
|
|
|
+ CHROMA_HTTP_PORT = int(os.environ.get("CHROMA_HTTP_PORT", "8000"))
|
|
|
+ CHROMA_CLIENT_AUTH_PROVIDER = os.environ.get("CHROMA_CLIENT_AUTH_PROVIDER", "")
|
|
|
+ CHROMA_CLIENT_AUTH_CREDENTIALS = os.environ.get(
|
|
|
+ "CHROMA_CLIENT_AUTH_CREDENTIALS", ""
|
|
|
)
|
|
|
-else:
|
|
|
- CHROMA_HTTP_HEADERS = None
|
|
|
-CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true"
|
|
|
+ # Comma-separated list of header=value pairs
|
|
|
+ CHROMA_HTTP_HEADERS = os.environ.get("CHROMA_HTTP_HEADERS", "")
|
|
|
+ if CHROMA_HTTP_HEADERS:
|
|
|
+ CHROMA_HTTP_HEADERS = dict(
|
|
|
+ [pair.split("=") for pair in CHROMA_HTTP_HEADERS.split(",")]
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ CHROMA_HTTP_HEADERS = None
|
|
|
+ CHROMA_HTTP_SSL = os.environ.get("CHROMA_HTTP_SSL", "false").lower() == "true"
|
|
|
# this uses the model defined in the Dockerfile ENV variable. If you dont use docker or docker based deployments such as k8s, the default embedding model will be used (sentence-transformers/all-MiniLM-L6-v2)
|
|
|
|
|
|
# Milvus
|
|
|
|
|
|
MILVUS_URI = os.environ.get("MILVUS_URI", f"{DATA_DIR}/vector_db/milvus.db")
|
|
|
MILVUS_DB = os.environ.get("MILVUS_DB", "default")
|
|
|
+MILVUS_TOKEN = os.environ.get("MILVUS_TOKEN", None)
|
|
|
|
|
|
# Qdrant
|
|
|
QDRANT_URI = os.environ.get("QDRANT_URI", None)
|
|
@@ -1331,6 +1545,15 @@ OPENSEARCH_CERT_VERIFY = os.environ.get("OPENSEARCH_CERT_VERIFY", False)
|
|
|
OPENSEARCH_USERNAME = os.environ.get("OPENSEARCH_USERNAME", None)
|
|
|
OPENSEARCH_PASSWORD = os.environ.get("OPENSEARCH_PASSWORD", None)
|
|
|
|
|
|
+# ElasticSearch
|
|
|
+ELASTICSEARCH_URL = os.environ.get("ELASTICSEARCH_URL", "https://localhost:9200")
|
|
|
+ELASTICSEARCH_CA_CERTS = os.environ.get("ELASTICSEARCH_CA_CERTS", None)
|
|
|
+ELASTICSEARCH_API_KEY = os.environ.get("ELASTICSEARCH_API_KEY", None)
|
|
|
+ELASTICSEARCH_USERNAME = os.environ.get("ELASTICSEARCH_USERNAME", None)
|
|
|
+ELASTICSEARCH_PASSWORD = os.environ.get("ELASTICSEARCH_PASSWORD", None)
|
|
|
+ELASTICSEARCH_CLOUD_ID = os.environ.get("ELASTICSEARCH_CLOUD_ID", None)
|
|
|
+SSL_ASSERT_FINGERPRINT = os.environ.get("SSL_ASSERT_FINGERPRINT", None)
|
|
|
+
|
|
|
# Pgvector
|
|
|
PGVECTOR_DB_URL = os.environ.get("PGVECTOR_DB_URL", DATABASE_URL)
|
|
|
if VECTOR_DB == "pgvector" and not PGVECTOR_DB_URL.startswith("postgres"):
|
|
@@ -1365,6 +1588,18 @@ GOOGLE_DRIVE_API_KEY = PersistentConfig(
|
|
|
os.environ.get("GOOGLE_DRIVE_API_KEY", ""),
|
|
|
)
|
|
|
|
|
|
+ENABLE_ONEDRIVE_INTEGRATION = PersistentConfig(
|
|
|
+ "ENABLE_ONEDRIVE_INTEGRATION",
|
|
|
+ "onedrive.enable",
|
|
|
+ os.getenv("ENABLE_ONEDRIVE_INTEGRATION", "False").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
+ONEDRIVE_CLIENT_ID = PersistentConfig(
|
|
|
+ "ONEDRIVE_CLIENT_ID",
|
|
|
+ "onedrive.client_id",
|
|
|
+ os.environ.get("ONEDRIVE_CLIENT_ID", ""),
|
|
|
+)
|
|
|
+
|
|
|
# RAG Content Extraction
|
|
|
CONTENT_EXTRACTION_ENGINE = PersistentConfig(
|
|
|
"CONTENT_EXTRACTION_ENGINE",
|
|
@@ -1384,6 +1619,26 @@ DOCLING_SERVER_URL = PersistentConfig(
|
|
|
os.getenv("DOCLING_SERVER_URL", "http://docling:5001"),
|
|
|
)
|
|
|
|
|
|
+DOCUMENT_INTELLIGENCE_ENDPOINT = PersistentConfig(
|
|
|
+ "DOCUMENT_INTELLIGENCE_ENDPOINT",
|
|
|
+ "rag.document_intelligence_endpoint",
|
|
|
+ os.getenv("DOCUMENT_INTELLIGENCE_ENDPOINT", ""),
|
|
|
+)
|
|
|
+
|
|
|
+DOCUMENT_INTELLIGENCE_KEY = PersistentConfig(
|
|
|
+ "DOCUMENT_INTELLIGENCE_KEY",
|
|
|
+ "rag.document_intelligence_key",
|
|
|
+ os.getenv("DOCUMENT_INTELLIGENCE_KEY", ""),
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+BYPASS_EMBEDDING_AND_RETRIEVAL = PersistentConfig(
|
|
|
+ "BYPASS_EMBEDDING_AND_RETRIEVAL",
|
|
|
+ "rag.bypass_embedding_and_retrieval",
|
|
|
+ os.environ.get("BYPASS_EMBEDDING_AND_RETRIEVAL", "False").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
RAG_TOP_K = PersistentConfig(
|
|
|
"RAG_TOP_K", "rag.top_k", int(os.environ.get("RAG_TOP_K", "3"))
|
|
|
)
|
|
@@ -1399,6 +1654,12 @@ ENABLE_RAG_HYBRID_SEARCH = PersistentConfig(
|
|
|
os.environ.get("ENABLE_RAG_HYBRID_SEARCH", "").lower() == "true",
|
|
|
)
|
|
|
|
|
|
+RAG_FULL_CONTEXT = PersistentConfig(
|
|
|
+ "RAG_FULL_CONTEXT",
|
|
|
+ "rag.full_context",
|
|
|
+ os.getenv("RAG_FULL_CONTEXT", "False").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
RAG_FILE_MAX_COUNT = PersistentConfig(
|
|
|
"RAG_FILE_MAX_COUNT",
|
|
|
"rag.file.max_count",
|
|
@@ -1513,7 +1774,7 @@ Respond to the user query using the provided context, incorporating inline citat
|
|
|
- Respond in the same language as the user's query.
|
|
|
- If the context is unreadable or of poor quality, inform the user and provide the best possible answer.
|
|
|
- If the answer isn't present in the context but you possess the knowledge, explain this to the user and provide the answer using your own understanding.
|
|
|
-- **Only include inline citations using [source_id] when a <source_id> tag is explicitly provided in the context.**
|
|
|
+- **Only include inline citations using [source_id] (e.g., [1], [2]) when a `<source_id>` tag is explicitly provided in the context.**
|
|
|
- Do not cite if the <source_id> tag is not provided in the context.
|
|
|
- Do not use XML tags in your response.
|
|
|
- Ensure citations are concise and directly related to the information provided.
|
|
@@ -1594,11 +1855,17 @@ RAG_WEB_SEARCH_ENGINE = PersistentConfig(
|
|
|
os.getenv("RAG_WEB_SEARCH_ENGINE", ""),
|
|
|
)
|
|
|
|
|
|
+BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = PersistentConfig(
|
|
|
+ "BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL",
|
|
|
+ "rag.web.search.bypass_embedding_and_retrieval",
|
|
|
+ os.getenv("BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL", "False").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
# You can provide a list of your own websites to filter after performing a web search.
|
|
|
# This ensures the highest level of safety and reliability of the information sources.
|
|
|
RAG_WEB_SEARCH_DOMAIN_FILTER_LIST = PersistentConfig(
|
|
|
"RAG_WEB_SEARCH_DOMAIN_FILTER_LIST",
|
|
|
- "rag.rag.web.search.domain.filter_list",
|
|
|
+ "rag.web.search.domain.filter_list",
|
|
|
[
|
|
|
# "wikipedia.com",
|
|
|
# "wikimedia.org",
|
|
@@ -1643,6 +1910,12 @@ MOJEEK_SEARCH_API_KEY = PersistentConfig(
|
|
|
os.getenv("MOJEEK_SEARCH_API_KEY", ""),
|
|
|
)
|
|
|
|
|
|
+BOCHA_SEARCH_API_KEY = PersistentConfig(
|
|
|
+ "BOCHA_SEARCH_API_KEY",
|
|
|
+ "rag.web.search.bocha_search_api_key",
|
|
|
+ os.getenv("BOCHA_SEARCH_API_KEY", ""),
|
|
|
+)
|
|
|
+
|
|
|
SERPSTACK_API_KEY = PersistentConfig(
|
|
|
"SERPSTACK_API_KEY",
|
|
|
"rag.web.search.serpstack_api_key",
|
|
@@ -1691,6 +1964,18 @@ SEARCHAPI_ENGINE = PersistentConfig(
|
|
|
os.getenv("SEARCHAPI_ENGINE", ""),
|
|
|
)
|
|
|
|
|
|
+SERPAPI_API_KEY = PersistentConfig(
|
|
|
+ "SERPAPI_API_KEY",
|
|
|
+ "rag.web.search.serpapi_api_key",
|
|
|
+ os.getenv("SERPAPI_API_KEY", ""),
|
|
|
+)
|
|
|
+
|
|
|
+SERPAPI_ENGINE = PersistentConfig(
|
|
|
+ "SERPAPI_ENGINE",
|
|
|
+ "rag.web.search.serpapi_engine",
|
|
|
+ os.getenv("SERPAPI_ENGINE", ""),
|
|
|
+)
|
|
|
+
|
|
|
BING_SEARCH_V7_ENDPOINT = PersistentConfig(
|
|
|
"BING_SEARCH_V7_ENDPOINT",
|
|
|
"rag.web.search.bing_search_v7_endpoint",
|
|
@@ -1705,6 +1990,17 @@ BING_SEARCH_V7_SUBSCRIPTION_KEY = PersistentConfig(
|
|
|
os.environ.get("BING_SEARCH_V7_SUBSCRIPTION_KEY", ""),
|
|
|
)
|
|
|
|
|
|
+EXA_API_KEY = PersistentConfig(
|
|
|
+ "EXA_API_KEY",
|
|
|
+ "rag.web.search.exa_api_key",
|
|
|
+ os.getenv("EXA_API_KEY", ""),
|
|
|
+)
|
|
|
+
|
|
|
+PERPLEXITY_API_KEY = PersistentConfig(
|
|
|
+ "PERPLEXITY_API_KEY",
|
|
|
+ "rag.web.search.perplexity_api_key",
|
|
|
+ os.getenv("PERPLEXITY_API_KEY", ""),
|
|
|
+)
|
|
|
|
|
|
RAG_WEB_SEARCH_RESULT_COUNT = PersistentConfig(
|
|
|
"RAG_WEB_SEARCH_RESULT_COUNT",
|
|
@@ -1718,6 +2014,35 @@ RAG_WEB_SEARCH_CONCURRENT_REQUESTS = PersistentConfig(
|
|
|
int(os.getenv("RAG_WEB_SEARCH_CONCURRENT_REQUESTS", "10")),
|
|
|
)
|
|
|
|
|
|
+RAG_WEB_LOADER_ENGINE = PersistentConfig(
|
|
|
+ "RAG_WEB_LOADER_ENGINE",
|
|
|
+ "rag.web.loader.engine",
|
|
|
+ os.environ.get("RAG_WEB_LOADER_ENGINE", "safe_web"),
|
|
|
+)
|
|
|
+
|
|
|
+RAG_WEB_SEARCH_TRUST_ENV = PersistentConfig(
|
|
|
+ "RAG_WEB_SEARCH_TRUST_ENV",
|
|
|
+ "rag.web.search.trust_env",
|
|
|
+ os.getenv("RAG_WEB_SEARCH_TRUST_ENV", "False").lower() == "true",
|
|
|
+)
|
|
|
+
|
|
|
+PLAYWRIGHT_WS_URI = PersistentConfig(
|
|
|
+ "PLAYWRIGHT_WS_URI",
|
|
|
+ "rag.web.loader.engine.playwright.ws.uri",
|
|
|
+ os.environ.get("PLAYWRIGHT_WS_URI", None),
|
|
|
+)
|
|
|
+
|
|
|
+FIRECRAWL_API_KEY = PersistentConfig(
|
|
|
+ "FIRECRAWL_API_KEY",
|
|
|
+ "firecrawl.api_key",
|
|
|
+ os.environ.get("FIRECRAWL_API_KEY", ""),
|
|
|
+)
|
|
|
+
|
|
|
+FIRECRAWL_API_BASE_URL = PersistentConfig(
|
|
|
+ "FIRECRAWL_API_BASE_URL",
|
|
|
+ "firecrawl.api_url",
|
|
|
+ os.environ.get("FIRECRAWL_API_BASE_URL", "https://api.firecrawl.dev"),
|
|
|
+)
|
|
|
|
|
|
####################################
|
|
|
# Images
|
|
@@ -1929,6 +2254,17 @@ IMAGES_OPENAI_API_KEY = PersistentConfig(
|
|
|
os.getenv("IMAGES_OPENAI_API_KEY", OPENAI_API_KEY),
|
|
|
)
|
|
|
|
|
|
+IMAGES_GEMINI_API_BASE_URL = PersistentConfig(
|
|
|
+ "IMAGES_GEMINI_API_BASE_URL",
|
|
|
+ "image_generation.gemini.api_base_url",
|
|
|
+ os.getenv("IMAGES_GEMINI_API_BASE_URL", GEMINI_API_BASE_URL),
|
|
|
+)
|
|
|
+IMAGES_GEMINI_API_KEY = PersistentConfig(
|
|
|
+ "IMAGES_GEMINI_API_KEY",
|
|
|
+ "image_generation.gemini.api_key",
|
|
|
+ os.getenv("IMAGES_GEMINI_API_KEY", GEMINI_API_KEY),
|
|
|
+)
|
|
|
+
|
|
|
IMAGE_SIZE = PersistentConfig(
|
|
|
"IMAGE_SIZE", "image_generation.size", os.getenv("IMAGE_SIZE", "512x512")
|
|
|
)
|
|
@@ -1960,6 +2296,12 @@ WHISPER_MODEL_AUTO_UPDATE = (
|
|
|
and os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true"
|
|
|
)
|
|
|
|
|
|
+# Add Deepgram configuration
|
|
|
+DEEPGRAM_API_KEY = PersistentConfig(
|
|
|
+ "DEEPGRAM_API_KEY",
|
|
|
+ "audio.stt.deepgram.api_key",
|
|
|
+ os.getenv("DEEPGRAM_API_KEY", ""),
|
|
|
+)
|
|
|
|
|
|
AUDIO_STT_OPENAI_API_BASE_URL = PersistentConfig(
|
|
|
"AUDIO_STT_OPENAI_API_BASE_URL",
|
|
@@ -2099,7 +2441,7 @@ LDAP_SEARCH_BASE = PersistentConfig(
|
|
|
LDAP_SEARCH_FILTERS = PersistentConfig(
|
|
|
"LDAP_SEARCH_FILTER",
|
|
|
"ldap.server.search_filter",
|
|
|
- os.environ.get("LDAP_SEARCH_FILTER", ""),
|
|
|
+ os.environ.get("LDAP_SEARCH_FILTER", os.environ.get("LDAP_SEARCH_FILTERS", "")),
|
|
|
)
|
|
|
|
|
|
LDAP_USE_TLS = PersistentConfig(
|