|
|
import importlib.metadata |
|
|
import json |
|
|
import logging |
|
|
import os |
|
|
import pkgutil |
|
|
import sys |
|
|
import shutil |
|
|
from uuid import uuid4 |
|
|
from pathlib import Path |
|
|
from cryptography.hazmat.primitives import serialization |
|
|
import re |
|
|
|
|
|
|
|
|
import markdown |
|
|
from bs4 import BeautifulSoup |
|
|
from open_webui.constants import ERROR_MESSAGES |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENV_FILE_PATH = Path(__file__).resolve() |
|
|
|
|
|
|
|
|
OPEN_WEBUI_DIR = ENV_FILE_PATH.parent |
|
|
|
|
|
|
|
|
BACKEND_DIR = OPEN_WEBUI_DIR.parent |
|
|
|
|
|
|
|
|
BASE_DIR = BACKEND_DIR.parent |
|
|
|
|
|
try: |
|
|
from dotenv import find_dotenv, load_dotenv |
|
|
|
|
|
load_dotenv(find_dotenv(str(BASE_DIR / ".env"))) |
|
|
except ImportError: |
|
|
print("dotenv not installed, skipping...") |
|
|
|
|
|
DOCKER = os.environ.get("DOCKER", "False").lower() == "true" |
|
|
|
|
|
|
|
|
USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false") |
|
|
|
|
|
if USE_CUDA.lower() == "true": |
|
|
try: |
|
|
import torch |
|
|
|
|
|
assert torch.cuda.is_available(), "CUDA not available" |
|
|
DEVICE_TYPE = "cuda" |
|
|
except Exception as e: |
|
|
cuda_error = ( |
|
|
"Error when testing CUDA but USE_CUDA_DOCKER is true. " |
|
|
f"Resetting USE_CUDA_DOCKER to false: {e}" |
|
|
) |
|
|
os.environ["USE_CUDA_DOCKER"] = "false" |
|
|
USE_CUDA = "false" |
|
|
DEVICE_TYPE = "cpu" |
|
|
else: |
|
|
DEVICE_TYPE = "cpu" |
|
|
|
|
|
try: |
|
|
import torch |
|
|
|
|
|
if torch.backends.mps.is_available() and torch.backends.mps.is_built(): |
|
|
DEVICE_TYPE = "mps" |
|
|
except Exception: |
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper() |
|
|
if GLOBAL_LOG_LEVEL in logging.getLevelNamesMapping(): |
|
|
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True) |
|
|
else: |
|
|
GLOBAL_LOG_LEVEL = "INFO" |
|
|
|
|
|
log = logging.getLogger(__name__) |
|
|
log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}") |
|
|
|
|
|
if "cuda_error" in locals(): |
|
|
log.exception(cuda_error) |
|
|
del cuda_error |
|
|
|
|
|
SRC_LOG_LEVELS = {} |
|
|
|
|
|
WEBUI_NAME = "JyotiGPT" |
|
|
WEBUI_FAVICON_URL = "https://baudrytherapy.com/wp-content/uploads/2015/11/500x500.png" |
|
|
|
|
|
TRUSTED_SIGNATURE_KEY = os.environ.get("TRUSTED_SIGNATURE_KEY", "") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENV = os.environ.get("ENV", "dev") |
|
|
|
|
|
FROM_INIT_PY = os.environ.get("FROM_INIT_PY", "False").lower() == "true" |
|
|
|
|
|
if FROM_INIT_PY: |
|
|
PACKAGE_DATA = {"version": importlib.metadata.version("open-webui")} |
|
|
else: |
|
|
try: |
|
|
PACKAGE_DATA = json.loads((BASE_DIR / "package.json").read_text()) |
|
|
except Exception: |
|
|
PACKAGE_DATA = {"version": "0.0.0"} |
|
|
|
|
|
VERSION = PACKAGE_DATA["version"] |
|
|
|
|
|
|
|
|
DEPLOYMENT_ID = os.environ.get("DEPLOYMENT_ID", "") |
|
|
INSTANCE_ID = os.environ.get("INSTANCE_ID", str(uuid4())) |
|
|
|
|
|
ENABLE_DB_MIGRATIONS = os.environ.get("ENABLE_DB_MIGRATIONS", "True").lower() == "true" |
|
|
|
|
|
|
|
|
|
|
|
def parse_section(section): |
|
|
items = [] |
|
|
for li in section.find_all("li"): |
|
|
|
|
|
raw_html = str(li) |
|
|
|
|
|
|
|
|
text = li.get_text(separator=" ", strip=True) |
|
|
|
|
|
|
|
|
parts = text.split(": ", 1) |
|
|
title = parts[0].strip() if len(parts) > 1 else "" |
|
|
content = parts[1].strip() if len(parts) > 1 else text |
|
|
|
|
|
items.append({"title": title, "content": content, "raw": raw_html}) |
|
|
return items |
|
|
|
|
|
|
|
|
try: |
|
|
changelog_path = BASE_DIR / "CHANGELOG.md" |
|
|
with open(str(changelog_path.absolute()), "r", encoding="utf8") as file: |
|
|
changelog_content = file.read() |
|
|
|
|
|
except Exception: |
|
|
changelog_content = (pkgutil.get_data("open_webui", "CHANGELOG.md") or b"").decode() |
|
|
|
|
|
|
|
|
html_content = markdown.markdown(changelog_content) |
|
|
|
|
|
|
|
|
soup = BeautifulSoup(html_content, "html.parser") |
|
|
|
|
|
|
|
|
changelog_json = {} |
|
|
|
|
|
|
|
|
for version in soup.find_all("h2"): |
|
|
version_number = version.get_text().strip().split(" - ")[0][1:-1] |
|
|
date = version.get_text().strip().split(" - ")[1] |
|
|
|
|
|
version_data = {"date": date} |
|
|
|
|
|
|
|
|
current = version.find_next_sibling() |
|
|
|
|
|
while current and current.name != "h2": |
|
|
if current.name == "h3": |
|
|
section_title = current.get_text().lower() |
|
|
section_items = parse_section(current.find_next_sibling("ul")) |
|
|
version_data[section_title] = section_items |
|
|
|
|
|
|
|
|
current = current.find_next_sibling() |
|
|
|
|
|
changelog_json[version_number] = version_data |
|
|
|
|
|
CHANGELOG = changelog_json |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_FORWARD_USER_INFO_HEADERS = ( |
|
|
os.environ.get("ENABLE_FORWARD_USER_INFO_HEADERS", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
ENABLE_STAR_SESSIONS_MIDDLEWARE = ( |
|
|
os.environ.get("ENABLE_STAR_SESSIONS_MIDDLEWARE", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WEBUI_BUILD_HASH = os.environ.get("WEBUI_BUILD_HASH", "dev-build") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DATA_DIR = Path(os.getenv("DATA_DIR", BACKEND_DIR / "data")).resolve() |
|
|
|
|
|
if FROM_INIT_PY: |
|
|
NEW_DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data")).resolve() |
|
|
NEW_DATA_DIR.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
|
if DATA_DIR.exists() and DATA_DIR != NEW_DATA_DIR: |
|
|
log.info(f"Moving {DATA_DIR} to {NEW_DATA_DIR}") |
|
|
for item in DATA_DIR.iterdir(): |
|
|
dest = NEW_DATA_DIR / item.name |
|
|
if item.is_dir(): |
|
|
shutil.copytree(item, dest, dirs_exist_ok=True) |
|
|
else: |
|
|
shutil.copy2(item, dest) |
|
|
|
|
|
|
|
|
shutil.make_archive(DATA_DIR.parent / "open_webui_data", "zip", DATA_DIR) |
|
|
|
|
|
|
|
|
shutil.rmtree(DATA_DIR) |
|
|
|
|
|
DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data")) |
|
|
|
|
|
STATIC_DIR = Path(os.getenv("STATIC_DIR", OPEN_WEBUI_DIR / "static")) |
|
|
|
|
|
FONTS_DIR = Path(os.getenv("FONTS_DIR", OPEN_WEBUI_DIR / "static" / "fonts")) |
|
|
|
|
|
FRONTEND_BUILD_DIR = Path(os.getenv("FRONTEND_BUILD_DIR", BASE_DIR / "build")).resolve() |
|
|
|
|
|
if FROM_INIT_PY: |
|
|
FRONTEND_BUILD_DIR = Path( |
|
|
os.getenv("FRONTEND_BUILD_DIR", OPEN_WEBUI_DIR / "frontend") |
|
|
).resolve() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.exists(f"{DATA_DIR}/ollama.db"): |
|
|
|
|
|
os.rename(f"{DATA_DIR}/ollama.db", f"{DATA_DIR}/webui.db") |
|
|
log.info("Database migrated from Ollama-WebUI successfully.") |
|
|
else: |
|
|
pass |
|
|
|
|
|
DATABASE_URL = os.environ.get("DATABASE_URL", f"sqlite:///{DATA_DIR}/webui.db") |
|
|
|
|
|
DATABASE_TYPE = os.environ.get("DATABASE_TYPE") |
|
|
DATABASE_USER = os.environ.get("DATABASE_USER") |
|
|
DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD") |
|
|
|
|
|
DATABASE_CRED = "" |
|
|
if DATABASE_USER: |
|
|
DATABASE_CRED += f"{DATABASE_USER}" |
|
|
if DATABASE_PASSWORD: |
|
|
DATABASE_CRED += f":{DATABASE_PASSWORD}" |
|
|
|
|
|
DB_VARS = { |
|
|
"db_type": DATABASE_TYPE, |
|
|
"db_cred": DATABASE_CRED, |
|
|
"db_host": os.environ.get("DATABASE_HOST"), |
|
|
"db_port": os.environ.get("DATABASE_PORT"), |
|
|
"db_name": os.environ.get("DATABASE_NAME"), |
|
|
} |
|
|
|
|
|
if all(DB_VARS.values()): |
|
|
DATABASE_URL = f"{DB_VARS['db_type']}://{DB_VARS['db_cred']}@{DB_VARS['db_host']}:{DB_VARS['db_port']}/{DB_VARS['db_name']}" |
|
|
elif DATABASE_TYPE == "sqlite+sqlcipher" and not os.environ.get("DATABASE_URL"): |
|
|
|
|
|
DATABASE_URL = f"sqlite+sqlcipher:///{DATA_DIR}/webui.db" |
|
|
|
|
|
|
|
|
if "postgres://" in DATABASE_URL: |
|
|
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://") |
|
|
|
|
|
DATABASE_SCHEMA = os.environ.get("DATABASE_SCHEMA", None) |
|
|
|
|
|
DATABASE_POOL_SIZE = os.environ.get("DATABASE_POOL_SIZE", None) |
|
|
|
|
|
if DATABASE_POOL_SIZE != None: |
|
|
try: |
|
|
DATABASE_POOL_SIZE = int(DATABASE_POOL_SIZE) |
|
|
except Exception: |
|
|
DATABASE_POOL_SIZE = None |
|
|
|
|
|
DATABASE_POOL_MAX_OVERFLOW = os.environ.get("DATABASE_POOL_MAX_OVERFLOW", 0) |
|
|
|
|
|
if DATABASE_POOL_MAX_OVERFLOW == "": |
|
|
DATABASE_POOL_MAX_OVERFLOW = 0 |
|
|
else: |
|
|
try: |
|
|
DATABASE_POOL_MAX_OVERFLOW = int(DATABASE_POOL_MAX_OVERFLOW) |
|
|
except Exception: |
|
|
DATABASE_POOL_MAX_OVERFLOW = 0 |
|
|
|
|
|
DATABASE_POOL_TIMEOUT = os.environ.get("DATABASE_POOL_TIMEOUT", 30) |
|
|
|
|
|
if DATABASE_POOL_TIMEOUT == "": |
|
|
DATABASE_POOL_TIMEOUT = 30 |
|
|
else: |
|
|
try: |
|
|
DATABASE_POOL_TIMEOUT = int(DATABASE_POOL_TIMEOUT) |
|
|
except Exception: |
|
|
DATABASE_POOL_TIMEOUT = 30 |
|
|
|
|
|
DATABASE_POOL_RECYCLE = os.environ.get("DATABASE_POOL_RECYCLE", 3600) |
|
|
|
|
|
if DATABASE_POOL_RECYCLE == "": |
|
|
DATABASE_POOL_RECYCLE = 3600 |
|
|
else: |
|
|
try: |
|
|
DATABASE_POOL_RECYCLE = int(DATABASE_POOL_RECYCLE) |
|
|
except Exception: |
|
|
DATABASE_POOL_RECYCLE = 3600 |
|
|
|
|
|
DATABASE_ENABLE_SQLITE_WAL = ( |
|
|
os.environ.get("DATABASE_ENABLE_SQLITE_WAL", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = os.environ.get( |
|
|
"DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL", None |
|
|
) |
|
|
if DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL is not None: |
|
|
try: |
|
|
DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = float( |
|
|
DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL |
|
|
) |
|
|
except Exception: |
|
|
DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = 0.0 |
|
|
|
|
|
|
|
|
DATABASE_ENABLE_SESSION_SHARING = ( |
|
|
os.environ.get("DATABASE_ENABLE_SESSION_SHARING", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
ENABLE_PUBLIC_ACTIVE_USERS_COUNT = ( |
|
|
os.environ.get("ENABLE_PUBLIC_ACTIVE_USERS_COUNT", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
RESET_CONFIG_ON_START = ( |
|
|
os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
ENABLE_REALTIME_CHAT_SAVE = ( |
|
|
os.environ.get("ENABLE_REALTIME_CHAT_SAVE", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
ENABLE_QUERIES_CACHE = os.environ.get("ENABLE_QUERIES_CACHE", "False").lower() == "true" |
|
|
|
|
|
RAG_SYSTEM_CONTEXT = os.environ.get("RAG_SYSTEM_CONTEXT", "False").lower() == "true" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
REDIS_URL = os.environ.get("REDIS_URL", "") |
|
|
REDIS_CLUSTER = os.environ.get("REDIS_CLUSTER", "False").lower() == "true" |
|
|
|
|
|
REDIS_KEY_PREFIX = os.environ.get("REDIS_KEY_PREFIX", "open-webui") |
|
|
|
|
|
REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "") |
|
|
REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379") |
|
|
|
|
|
|
|
|
REDIS_SENTINEL_MAX_RETRY_COUNT = os.environ.get("REDIS_SENTINEL_MAX_RETRY_COUNT", "2") |
|
|
try: |
|
|
REDIS_SENTINEL_MAX_RETRY_COUNT = int(REDIS_SENTINEL_MAX_RETRY_COUNT) |
|
|
if REDIS_SENTINEL_MAX_RETRY_COUNT < 1: |
|
|
REDIS_SENTINEL_MAX_RETRY_COUNT = 2 |
|
|
except ValueError: |
|
|
REDIS_SENTINEL_MAX_RETRY_COUNT = 2 |
|
|
|
|
|
|
|
|
REDIS_SOCKET_CONNECT_TIMEOUT = os.environ.get("REDIS_SOCKET_CONNECT_TIMEOUT", "") |
|
|
try: |
|
|
REDIS_SOCKET_CONNECT_TIMEOUT = float(REDIS_SOCKET_CONNECT_TIMEOUT) |
|
|
except ValueError: |
|
|
REDIS_SOCKET_CONNECT_TIMEOUT = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UVICORN_WORKERS = os.environ.get("UVICORN_WORKERS", "1") |
|
|
try: |
|
|
UVICORN_WORKERS = int(UVICORN_WORKERS) |
|
|
if UVICORN_WORKERS < 1: |
|
|
UVICORN_WORKERS = 1 |
|
|
except ValueError: |
|
|
UVICORN_WORKERS = 1 |
|
|
log.info(f"Invalid UVICORN_WORKERS value, defaulting to {UVICORN_WORKERS}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true" |
|
|
|
|
|
ENABLE_INITIAL_ADMIN_SIGNUP = ( |
|
|
os.environ.get("ENABLE_INITIAL_ADMIN_SIGNUP", "False").lower() == "true" |
|
|
) |
|
|
ENABLE_SIGNUP_PASSWORD_CONFIRMATION = ( |
|
|
os.environ.get("ENABLE_SIGNUP_PASSWORD_CONFIRMATION", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WEBUI_ADMIN_EMAIL = os.environ.get("WEBUI_ADMIN_EMAIL", "") |
|
|
WEBUI_ADMIN_PASSWORD = os.environ.get("WEBUI_ADMIN_PASSWORD", "") |
|
|
WEBUI_ADMIN_NAME = os.environ.get("WEBUI_ADMIN_NAME", "Admin") |
|
|
|
|
|
WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get( |
|
|
"WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None |
|
|
) |
|
|
WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get("WEBUI_AUTH_TRUSTED_NAME_HEADER", None) |
|
|
WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get( |
|
|
"WEBUI_AUTH_TRUSTED_GROUPS_HEADER", None |
|
|
) |
|
|
|
|
|
|
|
|
ENABLE_PASSWORD_VALIDATION = ( |
|
|
os.environ.get("ENABLE_PASSWORD_VALIDATION", "False").lower() == "true" |
|
|
) |
|
|
PASSWORD_VALIDATION_REGEX_PATTERN = os.environ.get( |
|
|
"PASSWORD_VALIDATION_REGEX_PATTERN", |
|
|
"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$", |
|
|
) |
|
|
|
|
|
|
|
|
try: |
|
|
PASSWORD_VALIDATION_REGEX_PATTERN = rf"{PASSWORD_VALIDATION_REGEX_PATTERN}" |
|
|
PASSWORD_VALIDATION_REGEX_PATTERN = re.compile(PASSWORD_VALIDATION_REGEX_PATTERN) |
|
|
except Exception as e: |
|
|
log.error(f"Invalid PASSWORD_VALIDATION_REGEX_PATTERN: {e}") |
|
|
PASSWORD_VALIDATION_REGEX_PATTERN = re.compile( |
|
|
r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$" |
|
|
) |
|
|
|
|
|
|
|
|
BYPASS_MODEL_ACCESS_CONTROL = ( |
|
|
os.environ.get("BYPASS_MODEL_ACCESS_CONTROL", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
WEBUI_AUTH_SIGNOUT_REDIRECT_URL = os.environ.get( |
|
|
"WEBUI_AUTH_SIGNOUT_REDIRECT_URL", None |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
WEBUI_SECRET_KEY = os.environ.get( |
|
|
"WEBUI_SECRET_KEY", |
|
|
os.environ.get( |
|
|
"WEBUI_JWT_SECRET_KEY", "t0p-s3cr3t" |
|
|
), |
|
|
) |
|
|
|
|
|
WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax") |
|
|
|
|
|
WEBUI_SESSION_COOKIE_SECURE = ( |
|
|
os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true" |
|
|
) |
|
|
|
|
|
WEBUI_AUTH_COOKIE_SAME_SITE = os.environ.get( |
|
|
"WEBUI_AUTH_COOKIE_SAME_SITE", WEBUI_SESSION_COOKIE_SAME_SITE |
|
|
) |
|
|
|
|
|
WEBUI_AUTH_COOKIE_SECURE = ( |
|
|
os.environ.get( |
|
|
"WEBUI_AUTH_COOKIE_SECURE", |
|
|
os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false"), |
|
|
).lower() |
|
|
== "true" |
|
|
) |
|
|
|
|
|
if WEBUI_AUTH and WEBUI_SECRET_KEY == "": |
|
|
raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND) |
|
|
|
|
|
ENABLE_COMPRESSION_MIDDLEWARE = ( |
|
|
os.environ.get("ENABLE_COMPRESSION_MIDDLEWARE", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_OAUTH_EMAIL_FALLBACK = ( |
|
|
os.environ.get("ENABLE_OAUTH_EMAIL_FALLBACK", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
ENABLE_OAUTH_ID_TOKEN_COOKIE = ( |
|
|
os.environ.get("ENABLE_OAUTH_ID_TOKEN_COOKIE", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
OAUTH_CLIENT_INFO_ENCRYPTION_KEY = os.environ.get( |
|
|
"OAUTH_CLIENT_INFO_ENCRYPTION_KEY", WEBUI_SECRET_KEY |
|
|
) |
|
|
|
|
|
OAUTH_SESSION_TOKEN_ENCRYPTION_KEY = os.environ.get( |
|
|
"OAUTH_SESSION_TOKEN_ENCRYPTION_KEY", WEBUI_SECRET_KEY |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_SCIM = ( |
|
|
os.environ.get("ENABLE_SCIM", os.environ.get("SCIM_ENABLED", "False")).lower() |
|
|
== "true" |
|
|
) |
|
|
SCIM_TOKEN = os.environ.get("SCIM_TOKEN", "") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LICENSE_KEY = os.environ.get("LICENSE_KEY", "") |
|
|
|
|
|
LICENSE_BLOB = None |
|
|
LICENSE_BLOB_PATH = os.environ.get("LICENSE_BLOB_PATH", DATA_DIR / "l.data") |
|
|
if LICENSE_BLOB_PATH and os.path.exists(LICENSE_BLOB_PATH): |
|
|
with open(LICENSE_BLOB_PATH, "rb") as f: |
|
|
LICENSE_BLOB = f.read() |
|
|
|
|
|
LICENSE_PUBLIC_KEY = os.environ.get("LICENSE_PUBLIC_KEY", "") |
|
|
|
|
|
pk = None |
|
|
if LICENSE_PUBLIC_KEY: |
|
|
pk = serialization.load_pem_public_key( |
|
|
f""" |
|
|
-----BEGIN PUBLIC KEY----- |
|
|
{LICENSE_PUBLIC_KEY} |
|
|
-----END PUBLIC KEY----- |
|
|
""".encode( |
|
|
"utf-8" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_CUSTOM_MODEL_FALLBACK = ( |
|
|
os.environ.get("ENABLE_CUSTOM_MODEL_FALLBACK", "False").lower() == "true" |
|
|
) |
|
|
|
|
|
MODELS_CACHE_TTL = os.environ.get("MODELS_CACHE_TTL", "1") |
|
|
if MODELS_CACHE_TTL == "": |
|
|
MODELS_CACHE_TTL = None |
|
|
else: |
|
|
try: |
|
|
MODELS_CACHE_TTL = int(MODELS_CACHE_TTL) |
|
|
except Exception: |
|
|
MODELS_CACHE_TTL = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION = ( |
|
|
os.environ.get("ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION", "False").lower() |
|
|
== "true" |
|
|
) |
|
|
|
|
|
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = os.environ.get( |
|
|
"CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE", "1" |
|
|
) |
|
|
|
|
|
if CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE == "": |
|
|
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1 |
|
|
else: |
|
|
try: |
|
|
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = int( |
|
|
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE |
|
|
) |
|
|
except Exception: |
|
|
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1 |
|
|
|
|
|
|
|
|
CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = os.environ.get( |
|
|
"CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES", "30" |
|
|
) |
|
|
|
|
|
if CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES == "": |
|
|
CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = 30 |
|
|
else: |
|
|
try: |
|
|
CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = int(CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES) |
|
|
except Exception: |
|
|
CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = 30 |
|
|
|
|
|
|
|
|
CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE = os.environ.get( |
|
|
"CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE", "" |
|
|
) |
|
|
|
|
|
if CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE == "": |
|
|
CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE = None |
|
|
else: |
|
|
try: |
|
|
CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE = int( |
|
|
CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE |
|
|
) |
|
|
except Exception: |
|
|
CHAT_STREAM_RESPONSE_CHUNK_MAX_BUFFER_SIZE = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_WEBSOCKET_SUPPORT = ( |
|
|
os.environ.get("ENABLE_WEBSOCKET_SUPPORT", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "") |
|
|
|
|
|
WEBSOCKET_REDIS_OPTIONS = os.environ.get("WEBSOCKET_REDIS_OPTIONS", "") |
|
|
|
|
|
|
|
|
if WEBSOCKET_REDIS_OPTIONS == "": |
|
|
if REDIS_SOCKET_CONNECT_TIMEOUT: |
|
|
WEBSOCKET_REDIS_OPTIONS = { |
|
|
"socket_connect_timeout": REDIS_SOCKET_CONNECT_TIMEOUT |
|
|
} |
|
|
else: |
|
|
log.debug("No WEBSOCKET_REDIS_OPTIONS provided, defaulting to None") |
|
|
WEBSOCKET_REDIS_OPTIONS = None |
|
|
else: |
|
|
try: |
|
|
WEBSOCKET_REDIS_OPTIONS = json.loads(WEBSOCKET_REDIS_OPTIONS) |
|
|
except Exception: |
|
|
log.warning("Invalid WEBSOCKET_REDIS_OPTIONS, defaulting to None") |
|
|
WEBSOCKET_REDIS_OPTIONS = None |
|
|
|
|
|
WEBSOCKET_REDIS_URL = os.environ.get("WEBSOCKET_REDIS_URL", REDIS_URL) |
|
|
WEBSOCKET_REDIS_CLUSTER = ( |
|
|
os.environ.get("WEBSOCKET_REDIS_CLUSTER", str(REDIS_CLUSTER)).lower() == "true" |
|
|
) |
|
|
|
|
|
websocket_redis_lock_timeout = os.environ.get("WEBSOCKET_REDIS_LOCK_TIMEOUT", "60") |
|
|
|
|
|
try: |
|
|
WEBSOCKET_REDIS_LOCK_TIMEOUT = int(websocket_redis_lock_timeout) |
|
|
except ValueError: |
|
|
WEBSOCKET_REDIS_LOCK_TIMEOUT = 60 |
|
|
|
|
|
WEBSOCKET_SENTINEL_HOSTS = os.environ.get("WEBSOCKET_SENTINEL_HOSTS", "") |
|
|
WEBSOCKET_SENTINEL_PORT = os.environ.get("WEBSOCKET_SENTINEL_PORT", "26379") |
|
|
WEBSOCKET_SERVER_LOGGING = ( |
|
|
os.environ.get("WEBSOCKET_SERVER_LOGGING", "False").lower() == "true" |
|
|
) |
|
|
WEBSOCKET_SERVER_ENGINEIO_LOGGING = ( |
|
|
os.environ.get("WEBSOCKET_SERVER_LOGGING", "False").lower() == "true" |
|
|
) |
|
|
WEBSOCKET_SERVER_PING_TIMEOUT = os.environ.get("WEBSOCKET_SERVER_PING_TIMEOUT", "20") |
|
|
try: |
|
|
WEBSOCKET_SERVER_PING_TIMEOUT = int(WEBSOCKET_SERVER_PING_TIMEOUT) |
|
|
except ValueError: |
|
|
WEBSOCKET_SERVER_PING_TIMEOUT = 20 |
|
|
|
|
|
WEBSOCKET_SERVER_PING_INTERVAL = os.environ.get("WEBSOCKET_SERVER_PING_INTERVAL", "25") |
|
|
try: |
|
|
WEBSOCKET_SERVER_PING_INTERVAL = int(WEBSOCKET_SERVER_PING_INTERVAL) |
|
|
except ValueError: |
|
|
WEBSOCKET_SERVER_PING_INTERVAL = 25 |
|
|
|
|
|
|
|
|
REQUESTS_VERIFY = os.environ.get("REQUESTS_VERIFY", "True").lower() == "true" |
|
|
|
|
|
AIOHTTP_CLIENT_TIMEOUT = os.environ.get("AIOHTTP_CLIENT_TIMEOUT", "") |
|
|
|
|
|
if AIOHTTP_CLIENT_TIMEOUT == "": |
|
|
AIOHTTP_CLIENT_TIMEOUT = None |
|
|
else: |
|
|
try: |
|
|
AIOHTTP_CLIENT_TIMEOUT = int(AIOHTTP_CLIENT_TIMEOUT) |
|
|
except Exception: |
|
|
AIOHTTP_CLIENT_TIMEOUT = 300 |
|
|
|
|
|
|
|
|
AIOHTTP_CLIENT_SESSION_SSL = ( |
|
|
os.environ.get("AIOHTTP_CLIENT_SESSION_SSL", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = os.environ.get( |
|
|
"AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST", |
|
|
os.environ.get("AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST", "10"), |
|
|
) |
|
|
|
|
|
if AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST == "": |
|
|
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = None |
|
|
else: |
|
|
try: |
|
|
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = int(AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) |
|
|
except Exception: |
|
|
AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = 10 |
|
|
|
|
|
|
|
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = os.environ.get( |
|
|
"AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA", "10" |
|
|
) |
|
|
|
|
|
if AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA == "": |
|
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = None |
|
|
else: |
|
|
try: |
|
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = int( |
|
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA |
|
|
) |
|
|
except Exception: |
|
|
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10 |
|
|
|
|
|
|
|
|
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = ( |
|
|
os.environ.get("AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL", "True").lower() == "true" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SENTENCE_TRANSFORMERS_BACKEND = os.environ.get("SENTENCE_TRANSFORMERS_BACKEND", "") |
|
|
if SENTENCE_TRANSFORMERS_BACKEND == "": |
|
|
SENTENCE_TRANSFORMERS_BACKEND = "torch" |
|
|
|
|
|
|
|
|
SENTENCE_TRANSFORMERS_MODEL_KWARGS = os.environ.get( |
|
|
"SENTENCE_TRANSFORMERS_MODEL_KWARGS", "" |
|
|
) |
|
|
if SENTENCE_TRANSFORMERS_MODEL_KWARGS == "": |
|
|
SENTENCE_TRANSFORMERS_MODEL_KWARGS = None |
|
|
else: |
|
|
try: |
|
|
SENTENCE_TRANSFORMERS_MODEL_KWARGS = json.loads( |
|
|
SENTENCE_TRANSFORMERS_MODEL_KWARGS |
|
|
) |
|
|
except Exception: |
|
|
SENTENCE_TRANSFORMERS_MODEL_KWARGS = None |
|
|
|
|
|
|
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = os.environ.get( |
|
|
"SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND", "" |
|
|
) |
|
|
if SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND == "": |
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = "torch" |
|
|
|
|
|
|
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = os.environ.get( |
|
|
"SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS", "" |
|
|
) |
|
|
if SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS == "": |
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None |
|
|
else: |
|
|
try: |
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = json.loads( |
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS |
|
|
) |
|
|
except Exception: |
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION = ( |
|
|
os.environ.get( |
|
|
"SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION", "True" |
|
|
).lower() |
|
|
== "true" |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_VERSION_UPDATE_CHECK = ( |
|
|
os.environ.get("ENABLE_VERSION_UPDATE_CHECK", "true").lower() == "true" |
|
|
) |
|
|
OFFLINE_MODE = os.environ.get("OFFLINE_MODE", "false").lower() == "true" |
|
|
|
|
|
if OFFLINE_MODE: |
|
|
os.environ["HF_HUB_OFFLINE"] = "1" |
|
|
ENABLE_VERSION_UPDATE_CHECK = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_AUDIT_STDOUT = os.getenv("ENABLE_AUDIT_STDOUT", "False").lower() == "true" |
|
|
ENABLE_AUDIT_LOGS_FILE = os.getenv("ENABLE_AUDIT_LOGS_FILE", "True").lower() == "true" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AUDIT_LOGS_FILE_PATH = os.getenv("AUDIT_LOGS_FILE_PATH", f"{DATA_DIR}/audit.log") |
|
|
|
|
|
AUDIT_LOG_FILE_ROTATION_SIZE = os.getenv("AUDIT_LOG_FILE_ROTATION_SIZE", "10MB") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AUDIT_UVICORN_LOGGER_NAMES = os.getenv( |
|
|
"AUDIT_UVICORN_LOGGER_NAMES", "uvicorn.access" |
|
|
).split(",") |
|
|
|
|
|
|
|
|
AUDIT_LOG_LEVEL = os.getenv("AUDIT_LOG_LEVEL", "NONE").upper() |
|
|
try: |
|
|
MAX_BODY_LOG_SIZE = int(os.environ.get("MAX_BODY_LOG_SIZE") or 2048) |
|
|
except ValueError: |
|
|
MAX_BODY_LOG_SIZE = 2048 |
|
|
|
|
|
|
|
|
AUDIT_EXCLUDED_PATHS = os.getenv("AUDIT_EXCLUDED_PATHS", "/chats,/chat,/folders").split( |
|
|
"," |
|
|
) |
|
|
AUDIT_EXCLUDED_PATHS = [path.strip() for path in AUDIT_EXCLUDED_PATHS] |
|
|
AUDIT_EXCLUDED_PATHS = [path.lstrip("/") for path in AUDIT_EXCLUDED_PATHS] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ENABLE_OTEL = os.environ.get("ENABLE_OTEL", "False").lower() == "true" |
|
|
ENABLE_OTEL_TRACES = os.environ.get("ENABLE_OTEL_TRACES", "False").lower() == "true" |
|
|
ENABLE_OTEL_METRICS = os.environ.get("ENABLE_OTEL_METRICS", "False").lower() == "true" |
|
|
ENABLE_OTEL_LOGS = os.environ.get("ENABLE_OTEL_LOGS", "False").lower() == "true" |
|
|
|
|
|
OTEL_EXPORTER_OTLP_ENDPOINT = os.environ.get( |
|
|
"OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317" |
|
|
) |
|
|
OTEL_METRICS_EXPORTER_OTLP_ENDPOINT = os.environ.get( |
|
|
"OTEL_METRICS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT |
|
|
) |
|
|
OTEL_LOGS_EXPORTER_OTLP_ENDPOINT = os.environ.get( |
|
|
"OTEL_LOGS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT |
|
|
) |
|
|
OTEL_EXPORTER_OTLP_INSECURE = ( |
|
|
os.environ.get("OTEL_EXPORTER_OTLP_INSECURE", "False").lower() == "true" |
|
|
) |
|
|
OTEL_METRICS_EXPORTER_OTLP_INSECURE = ( |
|
|
os.environ.get( |
|
|
"OTEL_METRICS_EXPORTER_OTLP_INSECURE", str(OTEL_EXPORTER_OTLP_INSECURE) |
|
|
).lower() |
|
|
== "true" |
|
|
) |
|
|
OTEL_LOGS_EXPORTER_OTLP_INSECURE = ( |
|
|
os.environ.get( |
|
|
"OTEL_LOGS_EXPORTER_OTLP_INSECURE", str(OTEL_EXPORTER_OTLP_INSECURE) |
|
|
).lower() |
|
|
== "true" |
|
|
) |
|
|
OTEL_SERVICE_NAME = os.environ.get("OTEL_SERVICE_NAME", "open-webui") |
|
|
OTEL_RESOURCE_ATTRIBUTES = os.environ.get( |
|
|
"OTEL_RESOURCE_ATTRIBUTES", "" |
|
|
) |
|
|
OTEL_TRACES_SAMPLER = os.environ.get( |
|
|
"OTEL_TRACES_SAMPLER", "parentbased_always_on" |
|
|
).lower() |
|
|
OTEL_BASIC_AUTH_USERNAME = os.environ.get("OTEL_BASIC_AUTH_USERNAME", "") |
|
|
OTEL_BASIC_AUTH_PASSWORD = os.environ.get("OTEL_BASIC_AUTH_PASSWORD", "") |
|
|
|
|
|
OTEL_METRICS_BASIC_AUTH_USERNAME = os.environ.get( |
|
|
"OTEL_METRICS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME |
|
|
) |
|
|
OTEL_METRICS_BASIC_AUTH_PASSWORD = os.environ.get( |
|
|
"OTEL_METRICS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD |
|
|
) |
|
|
OTEL_LOGS_BASIC_AUTH_USERNAME = os.environ.get( |
|
|
"OTEL_LOGS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME |
|
|
) |
|
|
OTEL_LOGS_BASIC_AUTH_PASSWORD = os.environ.get( |
|
|
"OTEL_LOGS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD |
|
|
) |
|
|
|
|
|
OTEL_OTLP_SPAN_EXPORTER = os.environ.get( |
|
|
"OTEL_OTLP_SPAN_EXPORTER", "grpc" |
|
|
).lower() |
|
|
|
|
|
OTEL_METRICS_OTLP_SPAN_EXPORTER = os.environ.get( |
|
|
"OTEL_METRICS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER |
|
|
).lower() |
|
|
|
|
|
OTEL_LOGS_OTLP_SPAN_EXPORTER = os.environ.get( |
|
|
"OTEL_LOGS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER |
|
|
).lower() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIP_OPTIONS = os.getenv("PIP_OPTIONS", "").split() |
|
|
PIP_PACKAGE_INDEX_OPTIONS = os.getenv("PIP_PACKAGE_INDEX_OPTIONS", "").split() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EXTERNAL_PWA_MANIFEST_URL = os.environ.get("EXTERNAL_PWA_MANIFEST_URL") |