env.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. import importlib.metadata
  2. import json
  3. import logging
  4. import os
  5. import pkgutil
  6. import sys
  7. import shutil
  8. from uuid import uuid4
  9. from pathlib import Path
  10. import markdown
  11. from bs4 import BeautifulSoup
  12. from open_webui.constants import ERROR_MESSAGES
  13. ####################################
  14. # Load .env file
  15. ####################################
  16. OPEN_WEBUI_DIR = Path(__file__).parent # the path containing this file
  17. print(OPEN_WEBUI_DIR)
  18. BACKEND_DIR = OPEN_WEBUI_DIR.parent # the path containing this file
  19. BASE_DIR = BACKEND_DIR.parent # the path containing the backend/
  20. print(BACKEND_DIR)
  21. print(BASE_DIR)
  22. try:
  23. from dotenv import find_dotenv, load_dotenv
  24. load_dotenv(find_dotenv(str(BASE_DIR / ".env")))
  25. except ImportError:
  26. print("dotenv not installed, skipping...")
  27. DOCKER = os.environ.get("DOCKER", "False").lower() == "true"
  28. # device type embedding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance
  29. USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false")
  30. if USE_CUDA.lower() == "true":
  31. try:
  32. import torch
  33. assert torch.cuda.is_available(), "CUDA not available"
  34. DEVICE_TYPE = "cuda"
  35. except Exception as e:
  36. cuda_error = (
  37. "Error when testing CUDA but USE_CUDA_DOCKER is true. "
  38. f"Resetting USE_CUDA_DOCKER to false: {e}"
  39. )
  40. os.environ["USE_CUDA_DOCKER"] = "false"
  41. USE_CUDA = "false"
  42. DEVICE_TYPE = "cpu"
  43. else:
  44. DEVICE_TYPE = "cpu"
  45. try:
  46. import torch
  47. if torch.backends.mps.is_available() and torch.backends.mps.is_built():
  48. DEVICE_TYPE = "mps"
  49. except Exception:
  50. pass
  51. ####################################
  52. # LOGGING
  53. ####################################
  54. GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper()
  55. if GLOBAL_LOG_LEVEL in logging.getLevelNamesMapping():
  56. logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True)
  57. else:
  58. GLOBAL_LOG_LEVEL = "INFO"
  59. log = logging.getLogger(__name__)
  60. log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}")
  61. if "cuda_error" in locals():
  62. log.exception(cuda_error)
  63. del cuda_error
  64. log_sources = [
  65. "AUDIO",
  66. "COMFYUI",
  67. "CONFIG",
  68. "DB",
  69. "IMAGES",
  70. "MAIN",
  71. "MODELS",
  72. "OLLAMA",
  73. "OPENAI",
  74. "RAG",
  75. "WEBHOOK",
  76. "SOCKET",
  77. "OAUTH",
  78. ]
  79. SRC_LOG_LEVELS = {}
  80. for source in log_sources:
  81. log_env_var = source + "_LOG_LEVEL"
  82. SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper()
  83. if SRC_LOG_LEVELS[source] not in logging.getLevelNamesMapping():
  84. SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL
  85. log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}")
  86. log.setLevel(SRC_LOG_LEVELS["CONFIG"])
  87. WEBUI_NAME = os.environ.get("WEBUI_NAME", "Open WebUI")
  88. if WEBUI_NAME != "Open WebUI":
  89. WEBUI_NAME += " (Open WebUI)"
  90. WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png"
  91. TRUSTED_SIGNATURE_KEY = os.environ.get("TRUSTED_SIGNATURE_KEY", "")
  92. ####################################
  93. # ENV (dev,test,prod)
  94. ####################################
  95. ENV = os.environ.get("ENV", "dev")
  96. FROM_INIT_PY = os.environ.get("FROM_INIT_PY", "False").lower() == "true"
  97. if FROM_INIT_PY:
  98. PACKAGE_DATA = {"version": importlib.metadata.version("open-webui")}
  99. else:
  100. try:
  101. PACKAGE_DATA = json.loads((BASE_DIR / "package.json").read_text())
  102. except Exception:
  103. PACKAGE_DATA = {"version": "0.0.0"}
  104. VERSION = PACKAGE_DATA["version"]
  105. INSTANCE_ID = os.environ.get("INSTANCE_ID", str(uuid4()))
  106. # Function to parse each section
  107. def parse_section(section):
  108. items = []
  109. for li in section.find_all("li"):
  110. # Extract raw HTML string
  111. raw_html = str(li)
  112. # Extract text without HTML tags
  113. text = li.get_text(separator=" ", strip=True)
  114. # Split into title and content
  115. parts = text.split(": ", 1)
  116. title = parts[0].strip() if len(parts) > 1 else ""
  117. content = parts[1].strip() if len(parts) > 1 else text
  118. items.append({"title": title, "content": content, "raw": raw_html})
  119. return items
  120. try:
  121. changelog_path = BASE_DIR / "CHANGELOG.md"
  122. with open(str(changelog_path.absolute()), "r", encoding="utf8") as file:
  123. changelog_content = file.read()
  124. except Exception:
  125. changelog_content = (pkgutil.get_data("open_webui", "CHANGELOG.md") or b"").decode()
  126. # Convert markdown content to HTML
  127. html_content = markdown.markdown(changelog_content)
  128. # Parse the HTML content
  129. soup = BeautifulSoup(html_content, "html.parser")
  130. # Initialize JSON structure
  131. changelog_json = {}
  132. # Iterate over each version
  133. for version in soup.find_all("h2"):
  134. version_number = version.get_text().strip().split(" - ")[0][1:-1] # Remove brackets
  135. date = version.get_text().strip().split(" - ")[1]
  136. version_data = {"date": date}
  137. # Find the next sibling that is a h3 tag (section title)
  138. current = version.find_next_sibling()
  139. while current and current.name != "h2":
  140. if current.name == "h3":
  141. section_title = current.get_text().lower() # e.g., "added", "fixed"
  142. section_items = parse_section(current.find_next_sibling("ul"))
  143. version_data[section_title] = section_items
  144. # Move to the next element
  145. current = current.find_next_sibling()
  146. changelog_json[version_number] = version_data
  147. CHANGELOG = changelog_json
  148. ####################################
  149. # SAFE_MODE
  150. ####################################
  151. SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
  152. ####################################
  153. # ENABLE_FORWARD_USER_INFO_HEADERS
  154. ####################################
  155. ENABLE_FORWARD_USER_INFO_HEADERS = (
  156. os.environ.get("ENABLE_FORWARD_USER_INFO_HEADERS", "False").lower() == "true"
  157. )
  158. ####################################
  159. # WEBUI_BUILD_HASH
  160. ####################################
  161. WEBUI_BUILD_HASH = os.environ.get("WEBUI_BUILD_HASH", "dev-build")
  162. ####################################
  163. # DATA/FRONTEND BUILD DIR
  164. ####################################
  165. DATA_DIR = Path(os.getenv("DATA_DIR", BACKEND_DIR / "data")).resolve()
  166. if FROM_INIT_PY:
  167. NEW_DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data")).resolve()
  168. NEW_DATA_DIR.mkdir(parents=True, exist_ok=True)
  169. # Check if the data directory exists in the package directory
  170. if DATA_DIR.exists() and DATA_DIR != NEW_DATA_DIR:
  171. log.info(f"Moving {DATA_DIR} to {NEW_DATA_DIR}")
  172. for item in DATA_DIR.iterdir():
  173. dest = NEW_DATA_DIR / item.name
  174. if item.is_dir():
  175. shutil.copytree(item, dest, dirs_exist_ok=True)
  176. else:
  177. shutil.copy2(item, dest)
  178. # Zip the data directory
  179. shutil.make_archive(DATA_DIR.parent / "open_webui_data", "zip", DATA_DIR)
  180. # Remove the old data directory
  181. shutil.rmtree(DATA_DIR)
  182. DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data"))
  183. STATIC_DIR = Path(os.getenv("STATIC_DIR", OPEN_WEBUI_DIR / "static"))
  184. FONTS_DIR = Path(os.getenv("FONTS_DIR", OPEN_WEBUI_DIR / "static" / "fonts"))
  185. FRONTEND_BUILD_DIR = Path(os.getenv("FRONTEND_BUILD_DIR", BASE_DIR / "build")).resolve()
  186. if FROM_INIT_PY:
  187. FRONTEND_BUILD_DIR = Path(
  188. os.getenv("FRONTEND_BUILD_DIR", OPEN_WEBUI_DIR / "frontend")
  189. ).resolve()
  190. ####################################
  191. # Database
  192. ####################################
  193. # Check if the file exists
  194. if os.path.exists(f"{DATA_DIR}/ollama.db"):
  195. # Rename the file
  196. os.rename(f"{DATA_DIR}/ollama.db", f"{DATA_DIR}/webui.db")
  197. log.info("Database migrated from Ollama-WebUI successfully.")
  198. else:
  199. pass
  200. DATABASE_URL = os.environ.get("DATABASE_URL", f"sqlite:///{DATA_DIR}/webui.db")
  201. DATABASE_TYPE = os.environ.get("DATABASE_TYPE")
  202. DATABASE_USER = os.environ.get("DATABASE_USER")
  203. DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD")
  204. DATABASE_CRED = ""
  205. if DATABASE_USER:
  206. DATABASE_CRED += f"{DATABASE_USER}"
  207. if DATABASE_PASSWORD:
  208. DATABASE_CRED += f":{DATABASE_PASSWORD}"
  209. DB_VARS = {
  210. "db_type": DATABASE_TYPE,
  211. "db_cred": DATABASE_CRED,
  212. "db_host": os.environ.get("DATABASE_HOST"),
  213. "db_port": os.environ.get("DATABASE_PORT"),
  214. "db_name": os.environ.get("DATABASE_NAME"),
  215. }
  216. if all(DB_VARS.values()):
  217. DATABASE_URL = f"{DB_VARS['db_type']}://{DB_VARS['db_cred']}@{DB_VARS['db_host']}:{DB_VARS['db_port']}/{DB_VARS['db_name']}"
  218. # Replace the postgres:// with postgresql://
  219. if "postgres://" in DATABASE_URL:
  220. DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")
  221. DATABASE_SCHEMA = os.environ.get("DATABASE_SCHEMA", None)
  222. DATABASE_POOL_SIZE = os.environ.get("DATABASE_POOL_SIZE", None)
  223. if DATABASE_POOL_SIZE != None:
  224. try:
  225. DATABASE_POOL_SIZE = int(DATABASE_POOL_SIZE)
  226. except Exception:
  227. DATABASE_POOL_SIZE = None
  228. DATABASE_POOL_MAX_OVERFLOW = os.environ.get("DATABASE_POOL_MAX_OVERFLOW", 0)
  229. if DATABASE_POOL_MAX_OVERFLOW == "":
  230. DATABASE_POOL_MAX_OVERFLOW = 0
  231. else:
  232. try:
  233. DATABASE_POOL_MAX_OVERFLOW = int(DATABASE_POOL_MAX_OVERFLOW)
  234. except Exception:
  235. DATABASE_POOL_MAX_OVERFLOW = 0
  236. DATABASE_POOL_TIMEOUT = os.environ.get("DATABASE_POOL_TIMEOUT", 30)
  237. if DATABASE_POOL_TIMEOUT == "":
  238. DATABASE_POOL_TIMEOUT = 30
  239. else:
  240. try:
  241. DATABASE_POOL_TIMEOUT = int(DATABASE_POOL_TIMEOUT)
  242. except Exception:
  243. DATABASE_POOL_TIMEOUT = 30
  244. DATABASE_POOL_RECYCLE = os.environ.get("DATABASE_POOL_RECYCLE", 3600)
  245. if DATABASE_POOL_RECYCLE == "":
  246. DATABASE_POOL_RECYCLE = 3600
  247. else:
  248. try:
  249. DATABASE_POOL_RECYCLE = int(DATABASE_POOL_RECYCLE)
  250. except Exception:
  251. DATABASE_POOL_RECYCLE = 3600
  252. RESET_CONFIG_ON_START = (
  253. os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true"
  254. )
  255. ENABLE_REALTIME_CHAT_SAVE = (
  256. os.environ.get("ENABLE_REALTIME_CHAT_SAVE", "False").lower() == "true"
  257. )
  258. ####################################
  259. # REDIS
  260. ####################################
  261. REDIS_URL = os.environ.get("REDIS_URL", "")
  262. REDIS_KEY_PREFIX = os.environ.get("REDIS_KEY_PREFIX", "open-webui")
  263. REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "")
  264. REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379")
  265. # Maximum number of retries for Redis operations when using Sentinel fail-over
  266. REDIS_SENTINEL_MAX_RETRY_COUNT = os.environ.get("REDIS_SENTINEL_MAX_RETRY_COUNT", "2")
  267. try:
  268. REDIS_SENTINEL_MAX_RETRY_COUNT = int(REDIS_SENTINEL_MAX_RETRY_COUNT)
  269. if REDIS_SENTINEL_MAX_RETRY_COUNT < 1:
  270. REDIS_SENTINEL_MAX_RETRY_COUNT = 2
  271. except ValueError:
  272. REDIS_SENTINEL_MAX_RETRY_COUNT = 2
  273. ####################################
  274. # UVICORN WORKERS
  275. ####################################
  276. # Number of uvicorn worker processes for handling requests
  277. UVICORN_WORKERS = os.environ.get("UVICORN_WORKERS", "1")
  278. try:
  279. UVICORN_WORKERS = int(UVICORN_WORKERS)
  280. if UVICORN_WORKERS < 1:
  281. UVICORN_WORKERS = 1
  282. except ValueError:
  283. UVICORN_WORKERS = 1
  284. log.info(f"Invalid UVICORN_WORKERS value, defaulting to {UVICORN_WORKERS}")
  285. ####################################
  286. # WEBUI_AUTH (Required for security)
  287. ####################################
  288. WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true"
  289. WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get(
  290. "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None
  291. )
  292. WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get("WEBUI_AUTH_TRUSTED_NAME_HEADER", None)
  293. WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get(
  294. "WEBUI_AUTH_TRUSTED_GROUPS_HEADER", None
  295. )
  296. BYPASS_MODEL_ACCESS_CONTROL = (
  297. os.environ.get("BYPASS_MODEL_ACCESS_CONTROL", "False").lower() == "true"
  298. )
  299. WEBUI_AUTH_SIGNOUT_REDIRECT_URL = os.environ.get(
  300. "WEBUI_AUTH_SIGNOUT_REDIRECT_URL", None
  301. )
  302. ####################################
  303. # WEBUI_SECRET_KEY
  304. ####################################
  305. WEBUI_SECRET_KEY = os.environ.get(
  306. "WEBUI_SECRET_KEY",
  307. os.environ.get(
  308. "WEBUI_JWT_SECRET_KEY", "t0p-s3cr3t"
  309. ), # DEPRECATED: remove at next major version
  310. )
  311. WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax")
  312. WEBUI_SESSION_COOKIE_SECURE = (
  313. os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true"
  314. )
  315. WEBUI_AUTH_COOKIE_SAME_SITE = os.environ.get(
  316. "WEBUI_AUTH_COOKIE_SAME_SITE", WEBUI_SESSION_COOKIE_SAME_SITE
  317. )
  318. WEBUI_AUTH_COOKIE_SECURE = (
  319. os.environ.get(
  320. "WEBUI_AUTH_COOKIE_SECURE",
  321. os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false"),
  322. ).lower()
  323. == "true"
  324. )
  325. if WEBUI_AUTH and WEBUI_SECRET_KEY == "":
  326. raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND)
  327. ENABLE_COMPRESSION_MIDDLEWARE = (
  328. os.environ.get("ENABLE_COMPRESSION_MIDDLEWARE", "True").lower() == "true"
  329. )
  330. ####################################
  331. # MODELS
  332. ####################################
  333. MODELS_CACHE_TTL = os.environ.get("MODELS_CACHE_TTL", "1")
  334. if MODELS_CACHE_TTL == "":
  335. MODELS_CACHE_TTL = None
  336. else:
  337. try:
  338. MODELS_CACHE_TTL = int(MODELS_CACHE_TTL)
  339. except Exception:
  340. MODELS_CACHE_TTL = 1
  341. ####################################
  342. # WEBSOCKET SUPPORT
  343. ####################################
  344. ENABLE_WEBSOCKET_SUPPORT = (
  345. os.environ.get("ENABLE_WEBSOCKET_SUPPORT", "True").lower() == "true"
  346. )
  347. WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "")
  348. WEBSOCKET_REDIS_URL = os.environ.get("WEBSOCKET_REDIS_URL", REDIS_URL)
  349. websocket_redis_lock_timeout = os.environ.get("WEBSOCKET_REDIS_LOCK_TIMEOUT", "60")
  350. try:
  351. WEBSOCKET_REDIS_LOCK_TIMEOUT = int(websocket_redis_lock_timeout)
  352. except ValueError:
  353. WEBSOCKET_REDIS_LOCK_TIMEOUT = 60
  354. WEBSOCKET_SENTINEL_HOSTS = os.environ.get("WEBSOCKET_SENTINEL_HOSTS", "")
  355. WEBSOCKET_SENTINEL_PORT = os.environ.get("WEBSOCKET_SENTINEL_PORT", "26379")
  356. AIOHTTP_CLIENT_TIMEOUT = os.environ.get("AIOHTTP_CLIENT_TIMEOUT", "")
  357. if AIOHTTP_CLIENT_TIMEOUT == "":
  358. AIOHTTP_CLIENT_TIMEOUT = None
  359. else:
  360. try:
  361. AIOHTTP_CLIENT_TIMEOUT = int(AIOHTTP_CLIENT_TIMEOUT)
  362. except Exception:
  363. AIOHTTP_CLIENT_TIMEOUT = 300
  364. AIOHTTP_CLIENT_SESSION_SSL = (
  365. os.environ.get("AIOHTTP_CLIENT_SESSION_SSL", "True").lower() == "true"
  366. )
  367. AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = os.environ.get(
  368. "AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST",
  369. os.environ.get("AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST", "10"),
  370. )
  371. if AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST == "":
  372. AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = None
  373. else:
  374. try:
  375. AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = int(AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST)
  376. except Exception:
  377. AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = 10
  378. AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = os.environ.get(
  379. "AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA", "10"
  380. )
  381. if AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA == "":
  382. AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = None
  383. else:
  384. try:
  385. AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = int(
  386. AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA
  387. )
  388. except Exception:
  389. AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
  390. AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = (
  391. os.environ.get("AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL", "True").lower() == "true"
  392. )
  393. ####################################
  394. # SENTENCE TRANSFORMERS
  395. ####################################
  396. SENTENCE_TRANSFORMERS_BACKEND = os.environ.get("SENTENCE_TRANSFORMERS_BACKEND", "")
  397. if SENTENCE_TRANSFORMERS_BACKEND == "":
  398. SENTENCE_TRANSFORMERS_BACKEND = "torch"
  399. SENTENCE_TRANSFORMERS_MODEL_KWARGS = os.environ.get(
  400. "SENTENCE_TRANSFORMERS_MODEL_KWARGS", ""
  401. )
  402. if SENTENCE_TRANSFORMERS_MODEL_KWARGS == "":
  403. SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
  404. else:
  405. try:
  406. SENTENCE_TRANSFORMERS_MODEL_KWARGS = json.loads(
  407. SENTENCE_TRANSFORMERS_MODEL_KWARGS
  408. )
  409. except Exception:
  410. SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
  411. SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = os.environ.get(
  412. "SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND", ""
  413. )
  414. if SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND == "":
  415. SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = "torch"
  416. SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = os.environ.get(
  417. "SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS", ""
  418. )
  419. if SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS == "":
  420. SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
  421. else:
  422. try:
  423. SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = json.loads(
  424. SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS
  425. )
  426. except Exception:
  427. SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
  428. ####################################
  429. # OFFLINE_MODE
  430. ####################################
  431. ENABLE_VERSION_UPDATE_CHECK = (
  432. os.environ.get("ENABLE_VERSION_UPDATE_CHECK", "true").lower() == "true"
  433. )
  434. OFFLINE_MODE = os.environ.get("OFFLINE_MODE", "false").lower() == "true"
  435. if OFFLINE_MODE:
  436. os.environ["HF_HUB_OFFLINE"] = "1"
  437. ENABLE_VERSION_UPDATE_CHECK = False
  438. ####################################
  439. # AUDIT LOGGING
  440. ####################################
  441. # Where to store log file
  442. AUDIT_LOGS_FILE_PATH = f"{DATA_DIR}/audit.log"
  443. # Maximum size of a file before rotating into a new log file
  444. AUDIT_LOG_FILE_ROTATION_SIZE = os.getenv("AUDIT_LOG_FILE_ROTATION_SIZE", "10MB")
  445. # Comma separated list of logger names to use for audit logging
  446. # Default is "uvicorn.access" which is the access log for Uvicorn
  447. # You can add more logger names to this list if you want to capture more logs
  448. AUDIT_UVICORN_LOGGER_NAMES = os.getenv(
  449. "AUDIT_UVICORN_LOGGER_NAMES", "uvicorn.access"
  450. ).split(",")
  451. # METADATA | REQUEST | REQUEST_RESPONSE
  452. AUDIT_LOG_LEVEL = os.getenv("AUDIT_LOG_LEVEL", "NONE").upper()
  453. try:
  454. MAX_BODY_LOG_SIZE = int(os.environ.get("MAX_BODY_LOG_SIZE") or 2048)
  455. except ValueError:
  456. MAX_BODY_LOG_SIZE = 2048
  457. # Comma separated list for urls to exclude from audit
  458. AUDIT_EXCLUDED_PATHS = os.getenv("AUDIT_EXCLUDED_PATHS", "/chats,/chat,/folders").split(
  459. ","
  460. )
  461. AUDIT_EXCLUDED_PATHS = [path.strip() for path in AUDIT_EXCLUDED_PATHS]
  462. AUDIT_EXCLUDED_PATHS = [path.lstrip("/") for path in AUDIT_EXCLUDED_PATHS]
  463. ####################################
  464. # OPENTELEMETRY
  465. ####################################
  466. ENABLE_OTEL = os.environ.get("ENABLE_OTEL", "False").lower() == "true"
  467. ENABLE_OTEL_METRICS = os.environ.get("ENABLE_OTEL_METRICS", "False").lower() == "true"
  468. OTEL_EXPORTER_OTLP_ENDPOINT = os.environ.get(
  469. "OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"
  470. )
  471. OTEL_EXPORTER_OTLP_INSECURE = (
  472. os.environ.get("OTEL_EXPORTER_OTLP_INSECURE", "False").lower() == "true"
  473. )
  474. OTEL_SERVICE_NAME = os.environ.get("OTEL_SERVICE_NAME", "open-webui")
  475. OTEL_RESOURCE_ATTRIBUTES = os.environ.get(
  476. "OTEL_RESOURCE_ATTRIBUTES", ""
  477. ) # e.g. key1=val1,key2=val2
  478. OTEL_TRACES_SAMPLER = os.environ.get(
  479. "OTEL_TRACES_SAMPLER", "parentbased_always_on"
  480. ).lower()
  481. OTEL_BASIC_AUTH_USERNAME = os.environ.get("OTEL_BASIC_AUTH_USERNAME", "")
  482. OTEL_BASIC_AUTH_PASSWORD = os.environ.get("OTEL_BASIC_AUTH_PASSWORD", "")
  483. OTEL_OTLP_SPAN_EXPORTER = os.environ.get(
  484. "OTEL_OTLP_SPAN_EXPORTER", "grpc"
  485. ).lower() # grpc or http
  486. ####################################
  487. # TOOLS/FUNCTIONS PIP OPTIONS
  488. ####################################
  489. PIP_OPTIONS = os.getenv("PIP_OPTIONS", "").split()
  490. PIP_PACKAGE_INDEX_OPTIONS = os.getenv("PIP_PACKAGE_INDEX_OPTIONS", "").split()
  491. ####################################
  492. # PROGRESSIVE WEB APP OPTIONS
  493. ####################################
  494. EXTERNAL_PWA_MANIFEST_URL = os.environ.get("EXTERNAL_PWA_MANIFEST_URL")