SiddhJagani commited on
Commit
e18a215
·
verified ·
1 Parent(s): 8a3068e

Create env.py

Browse files
Files changed (1) hide show
  1. env.py +815 -0
env.py ADDED
@@ -0,0 +1,815 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.primitives import serialization
11
+
12
+ import markdown
13
+ from bs4 import BeautifulSoup
14
+ from open_webui.constants import ERROR_MESSAGES
15
+
16
+ ####################################
17
+ # Load .env file
18
+ ####################################
19
+
20
+ # Use .resolve() to get the canonical path, removing any '..' or '.' components
21
+ ENV_FILE_PATH = Path(__file__).resolve()
22
+
23
+ # OPEN_WEBUI_DIR should be the directory where env.py resides (open_webui/)
24
+ OPEN_WEBUI_DIR = ENV_FILE_PATH.parent
25
+
26
+ # BACKEND_DIR is the parent of OPEN_WEBUI_DIR (backend/)
27
+ BACKEND_DIR = OPEN_WEBUI_DIR.parent
28
+
29
+ # BASE_DIR is the parent of BACKEND_DIR (open-webui-dev/)
30
+ BASE_DIR = BACKEND_DIR.parent
31
+
32
+ try:
33
+ from dotenv import find_dotenv, load_dotenv
34
+
35
+ load_dotenv(find_dotenv(str(BASE_DIR / ".env")))
36
+ except ImportError:
37
+ print("dotenv not installed, skipping...")
38
+
39
+ DOCKER = os.environ.get("DOCKER", "False").lower() == "true"
40
+
41
+ # device type embedding models - "cpu" (default), "cuda" (nvidia gpu required) or "mps" (apple silicon) - choosing this right can lead to better performance
42
+ USE_CUDA = os.environ.get("USE_CUDA_DOCKER", "false")
43
+
44
+ if USE_CUDA.lower() == "true":
45
+ try:
46
+ import torch
47
+
48
+ assert torch.cuda.is_available(), "CUDA not available"
49
+ DEVICE_TYPE = "cuda"
50
+ except Exception as e:
51
+ cuda_error = (
52
+ "Error when testing CUDA but USE_CUDA_DOCKER is true. "
53
+ f"Resetting USE_CUDA_DOCKER to false: {e}"
54
+ )
55
+ os.environ["USE_CUDA_DOCKER"] = "false"
56
+ USE_CUDA = "false"
57
+ DEVICE_TYPE = "cpu"
58
+ else:
59
+ DEVICE_TYPE = "cpu"
60
+
61
+ try:
62
+ import torch
63
+
64
+ if torch.backends.mps.is_available() and torch.backends.mps.is_built():
65
+ DEVICE_TYPE = "mps"
66
+ except Exception:
67
+ pass
68
+
69
+ ####################################
70
+ # LOGGING
71
+ ####################################
72
+
73
+ GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper()
74
+ if GLOBAL_LOG_LEVEL in logging.getLevelNamesMapping():
75
+ logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True)
76
+ else:
77
+ GLOBAL_LOG_LEVEL = "INFO"
78
+
79
+ log = logging.getLogger(__name__)
80
+ log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}")
81
+
82
+ if "cuda_error" in locals():
83
+ log.exception(cuda_error)
84
+ del cuda_error
85
+
86
+ log_sources = [
87
+ "AUDIO",
88
+ "COMFYUI",
89
+ "CONFIG",
90
+ "DB",
91
+ "IMAGES",
92
+ "MAIN",
93
+ "MODELS",
94
+ "OLLAMA",
95
+ "OPENAI",
96
+ "RAG",
97
+ "WEBHOOK",
98
+ "SOCKET",
99
+ "OAUTH",
100
+ ]
101
+
102
+ SRC_LOG_LEVELS = {}
103
+
104
+ for source in log_sources:
105
+ log_env_var = source + "_LOG_LEVEL"
106
+ SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper()
107
+ if SRC_LOG_LEVELS[source] not in logging.getLevelNamesMapping():
108
+ SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL
109
+ log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}")
110
+
111
+ log.setLevel(SRC_LOG_LEVELS["CONFIG"])
112
+
113
+ WEBUI_NAME = os.environ.get("WEBUI_NAME", "UltimateGPT")
114
+ if WEBUI_NAME != "UltimateGPT":
115
+ WEBUI_NAME += ""
116
+
117
+ WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png"
118
+
119
+ TRUSTED_SIGNATURE_KEY = os.environ.get("TRUSTED_SIGNATURE_KEY", "")
120
+
121
+ ####################################
122
+ # ENV (dev,test,prod)
123
+ ####################################
124
+
125
+ ENV = os.environ.get("ENV", "dev")
126
+
127
+ FROM_INIT_PY = os.environ.get("FROM_INIT_PY", "False").lower() == "true"
128
+
129
+ if FROM_INIT_PY:
130
+ PACKAGE_DATA = {"version": importlib.metadata.version("open-webui")}
131
+ else:
132
+ try:
133
+ PACKAGE_DATA = json.loads((BASE_DIR / "package.json").read_text())
134
+ except Exception:
135
+ PACKAGE_DATA = {"version": "0.0.0"}
136
+
137
+ VERSION = PACKAGE_DATA["version"]
138
+ INSTANCE_ID = os.environ.get("INSTANCE_ID", str(uuid4()))
139
+
140
+
141
+ # Function to parse each section
142
+ def parse_section(section):
143
+ items = []
144
+ for li in section.find_all("li"):
145
+ # Extract raw HTML string
146
+ raw_html = str(li)
147
+
148
+ # Extract text without HTML tags
149
+ text = li.get_text(separator=" ", strip=True)
150
+
151
+ # Split into title and content
152
+ parts = text.split(": ", 1)
153
+ title = parts[0].strip() if len(parts) > 1 else ""
154
+ content = parts[1].strip() if len(parts) > 1 else text
155
+
156
+ items.append({"title": title, "content": content, "raw": raw_html})
157
+ return items
158
+
159
+
160
+ try:
161
+ changelog_path = BASE_DIR / "CHANGELOG.md"
162
+ with open(str(changelog_path.absolute()), "r", encoding="utf8") as file:
163
+ changelog_content = file.read()
164
+
165
+ except Exception:
166
+ changelog_content = (pkgutil.get_data("open_webui", "CHANGELOG.md") or b"").decode()
167
+
168
+ # Convert markdown content to HTML
169
+ html_content = markdown.markdown(changelog_content)
170
+
171
+ # Parse the HTML content
172
+ soup = BeautifulSoup(html_content, "html.parser")
173
+
174
+ # Initialize JSON structure
175
+ changelog_json = {}
176
+
177
+ # Iterate over each version
178
+ for version in soup.find_all("h2"):
179
+ version_number = version.get_text().strip().split(" - ")[0][1:-1] # Remove brackets
180
+ date = version.get_text().strip().split(" - ")[1]
181
+
182
+ version_data = {"date": date}
183
+
184
+ # Find the next sibling that is a h3 tag (section title)
185
+ current = version.find_next_sibling()
186
+
187
+ while current and current.name != "h2":
188
+ if current.name == "h3":
189
+ section_title = current.get_text().lower() # e.g., "added", "fixed"
190
+ section_items = parse_section(current.find_next_sibling("ul"))
191
+ version_data[section_title] = section_items
192
+
193
+ # Move to the next element
194
+ current = current.find_next_sibling()
195
+
196
+ changelog_json[version_number] = version_data
197
+
198
+ CHANGELOG = changelog_json
199
+
200
+ ####################################
201
+ # SAFE_MODE
202
+ ####################################
203
+
204
+ SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
205
+
206
+
207
+ ####################################
208
+ # ENABLE_FORWARD_USER_INFO_HEADERS
209
+ ####################################
210
+
211
+ ENABLE_FORWARD_USER_INFO_HEADERS = (
212
+ os.environ.get("ENABLE_FORWARD_USER_INFO_HEADERS", "False").lower() == "true"
213
+ )
214
+
215
+ # Experimental feature, may be removed in future
216
+ ENABLE_STAR_SESSIONS_MIDDLEWARE = (
217
+ os.environ.get("ENABLE_STAR_SESSIONS_MIDDLEWARE", "False").lower() == "true"
218
+ )
219
+
220
+ ####################################
221
+ # WEBUI_BUILD_HASH
222
+ ####################################
223
+
224
+ WEBUI_BUILD_HASH = os.environ.get("WEBUI_BUILD_HASH", "dev-build")
225
+
226
+ ####################################
227
+ # DATA/FRONTEND BUILD DIR
228
+ ####################################
229
+
230
+ DATA_DIR = Path(os.getenv("DATA_DIR", BACKEND_DIR / "data")).resolve()
231
+
232
+ if FROM_INIT_PY:
233
+ NEW_DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data")).resolve()
234
+ NEW_DATA_DIR.mkdir(parents=True, exist_ok=True)
235
+
236
+ # Check if the data directory exists in the package directory
237
+ if DATA_DIR.exists() and DATA_DIR != NEW_DATA_DIR:
238
+ log.info(f"Moving {DATA_DIR} to {NEW_DATA_DIR}")
239
+ for item in DATA_DIR.iterdir():
240
+ dest = NEW_DATA_DIR / item.name
241
+ if item.is_dir():
242
+ shutil.copytree(item, dest, dirs_exist_ok=True)
243
+ else:
244
+ shutil.copy2(item, dest)
245
+
246
+ # Zip the data directory
247
+ shutil.make_archive(DATA_DIR.parent / "open_webui_data", "zip", DATA_DIR)
248
+
249
+ # Remove the old data directory
250
+ shutil.rmtree(DATA_DIR)
251
+
252
+ DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data"))
253
+
254
+ STATIC_DIR = Path(os.getenv("STATIC_DIR", OPEN_WEBUI_DIR / "static"))
255
+
256
+ FONTS_DIR = Path(os.getenv("FONTS_DIR", OPEN_WEBUI_DIR / "static" / "fonts"))
257
+
258
+ FRONTEND_BUILD_DIR = Path(os.getenv("FRONTEND_BUILD_DIR", BASE_DIR / "build")).resolve()
259
+
260
+ if FROM_INIT_PY:
261
+ FRONTEND_BUILD_DIR = Path(
262
+ os.getenv("FRONTEND_BUILD_DIR", OPEN_WEBUI_DIR / "frontend")
263
+ ).resolve()
264
+
265
+ ####################################
266
+ # Database
267
+ ####################################
268
+
269
+ # Check if the file exists
270
+ if os.path.exists(f"{DATA_DIR}/ollama.db"):
271
+ # Rename the file
272
+ os.rename(f"{DATA_DIR}/ollama.db", f"{DATA_DIR}/webui.db")
273
+ log.info("Database migrated from Ollama-WebUI successfully.")
274
+ else:
275
+ pass
276
+
277
+ DATABASE_URL = os.environ.get("DATABASE_URL", f"sqlite:///{DATA_DIR}/webui.db")
278
+
279
+ DATABASE_TYPE = os.environ.get("DATABASE_TYPE")
280
+ DATABASE_USER = os.environ.get("DATABASE_USER")
281
+ DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD")
282
+
283
+ DATABASE_CRED = ""
284
+ if DATABASE_USER:
285
+ DATABASE_CRED += f"{DATABASE_USER}"
286
+ if DATABASE_PASSWORD:
287
+ DATABASE_CRED += f":{DATABASE_PASSWORD}"
288
+
289
+ DB_VARS = {
290
+ "db_type": DATABASE_TYPE,
291
+ "db_cred": DATABASE_CRED,
292
+ "db_host": os.environ.get("DATABASE_HOST"),
293
+ "db_port": os.environ.get("DATABASE_PORT"),
294
+ "db_name": os.environ.get("DATABASE_NAME"),
295
+ }
296
+
297
+ if all(DB_VARS.values()):
298
+ DATABASE_URL = f"{DB_VARS['db_type']}://{DB_VARS['db_cred']}@{DB_VARS['db_host']}:{DB_VARS['db_port']}/{DB_VARS['db_name']}"
299
+ elif DATABASE_TYPE == "sqlite+sqlcipher" and not os.environ.get("DATABASE_URL"):
300
+ # Handle SQLCipher with local file when DATABASE_URL wasn't explicitly set
301
+ DATABASE_URL = f"sqlite+sqlcipher:///{DATA_DIR}/webui.db"
302
+
303
+ # Replace the postgres:// with postgresql://
304
+ if "postgres://" in DATABASE_URL:
305
+ DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")
306
+
307
+ DATABASE_SCHEMA = os.environ.get("DATABASE_SCHEMA", None)
308
+
309
+ DATABASE_POOL_SIZE = os.environ.get("DATABASE_POOL_SIZE", None)
310
+
311
+ if DATABASE_POOL_SIZE != None:
312
+ try:
313
+ DATABASE_POOL_SIZE = int(DATABASE_POOL_SIZE)
314
+ except Exception:
315
+ DATABASE_POOL_SIZE = None
316
+
317
+ DATABASE_POOL_MAX_OVERFLOW = os.environ.get("DATABASE_POOL_MAX_OVERFLOW", 0)
318
+
319
+ if DATABASE_POOL_MAX_OVERFLOW == "":
320
+ DATABASE_POOL_MAX_OVERFLOW = 0
321
+ else:
322
+ try:
323
+ DATABASE_POOL_MAX_OVERFLOW = int(DATABASE_POOL_MAX_OVERFLOW)
324
+ except Exception:
325
+ DATABASE_POOL_MAX_OVERFLOW = 0
326
+
327
+ DATABASE_POOL_TIMEOUT = os.environ.get("DATABASE_POOL_TIMEOUT", 30)
328
+
329
+ if DATABASE_POOL_TIMEOUT == "":
330
+ DATABASE_POOL_TIMEOUT = 30
331
+ else:
332
+ try:
333
+ DATABASE_POOL_TIMEOUT = int(DATABASE_POOL_TIMEOUT)
334
+ except Exception:
335
+ DATABASE_POOL_TIMEOUT = 30
336
+
337
+ DATABASE_POOL_RECYCLE = os.environ.get("DATABASE_POOL_RECYCLE", 3600)
338
+
339
+ if DATABASE_POOL_RECYCLE == "":
340
+ DATABASE_POOL_RECYCLE = 3600
341
+ else:
342
+ try:
343
+ DATABASE_POOL_RECYCLE = int(DATABASE_POOL_RECYCLE)
344
+ except Exception:
345
+ DATABASE_POOL_RECYCLE = 3600
346
+
347
+ DATABASE_ENABLE_SQLITE_WAL = (
348
+ os.environ.get("DATABASE_ENABLE_SQLITE_WAL", "False").lower() == "true"
349
+ )
350
+
351
+ DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = os.environ.get(
352
+ "DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL", None
353
+ )
354
+ if DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL is not None:
355
+ try:
356
+ DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = float(
357
+ DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL
358
+ )
359
+ except Exception:
360
+ DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = 0.0
361
+
362
+ RESET_CONFIG_ON_START = (
363
+ os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true"
364
+ )
365
+
366
+ ENABLE_REALTIME_CHAT_SAVE = (
367
+ os.environ.get("ENABLE_REALTIME_CHAT_SAVE", "False").lower() == "true"
368
+ )
369
+
370
+ ENABLE_QUERIES_CACHE = os.environ.get("ENABLE_QUERIES_CACHE", "False").lower() == "true"
371
+
372
+ ####################################
373
+ # REDIS
374
+ ####################################
375
+
376
+ REDIS_URL = os.environ.get("REDIS_URL", "")
377
+ REDIS_CLUSTER = os.environ.get("REDIS_CLUSTER", "False").lower() == "true"
378
+
379
+ REDIS_KEY_PREFIX = os.environ.get("REDIS_KEY_PREFIX", "open-webui")
380
+
381
+ REDIS_SENTINEL_HOSTS = os.environ.get("REDIS_SENTINEL_HOSTS", "")
382
+ REDIS_SENTINEL_PORT = os.environ.get("REDIS_SENTINEL_PORT", "26379")
383
+
384
+ # Maximum number of retries for Redis operations when using Sentinel fail-over
385
+ REDIS_SENTINEL_MAX_RETRY_COUNT = os.environ.get("REDIS_SENTINEL_MAX_RETRY_COUNT", "2")
386
+ try:
387
+ REDIS_SENTINEL_MAX_RETRY_COUNT = int(REDIS_SENTINEL_MAX_RETRY_COUNT)
388
+ if REDIS_SENTINEL_MAX_RETRY_COUNT < 1:
389
+ REDIS_SENTINEL_MAX_RETRY_COUNT = 2
390
+ except ValueError:
391
+ REDIS_SENTINEL_MAX_RETRY_COUNT = 2
392
+
393
+ ####################################
394
+ # UVICORN WORKERS
395
+ ####################################
396
+
397
+ # Number of uvicorn worker processes for handling requests
398
+ UVICORN_WORKERS = os.environ.get("UVICORN_WORKERS", "1")
399
+ try:
400
+ UVICORN_WORKERS = int(UVICORN_WORKERS)
401
+ if UVICORN_WORKERS < 1:
402
+ UVICORN_WORKERS = 1
403
+ except ValueError:
404
+ UVICORN_WORKERS = 1
405
+ log.info(f"Invalid UVICORN_WORKERS value, defaulting to {UVICORN_WORKERS}")
406
+
407
+ ####################################
408
+ # WEBUI_AUTH (Required for security)
409
+ ####################################
410
+
411
+ WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true"
412
+
413
+ ENABLE_INITIAL_ADMIN_SIGNUP = (
414
+ os.environ.get("ENABLE_INITIAL_ADMIN_SIGNUP", "False").lower() == "true"
415
+ )
416
+ ENABLE_SIGNUP_PASSWORD_CONFIRMATION = (
417
+ os.environ.get("ENABLE_SIGNUP_PASSWORD_CONFIRMATION", "False").lower() == "true"
418
+ )
419
+
420
+ WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get(
421
+ "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None
422
+ )
423
+ WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get("WEBUI_AUTH_TRUSTED_NAME_HEADER", None)
424
+ WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get(
425
+ "WEBUI_AUTH_TRUSTED_GROUPS_HEADER", None
426
+ )
427
+
428
+
429
+ BYPASS_MODEL_ACCESS_CONTROL = (
430
+ os.environ.get("BYPASS_MODEL_ACCESS_CONTROL", "False").lower() == "true"
431
+ )
432
+
433
+ WEBUI_AUTH_SIGNOUT_REDIRECT_URL = os.environ.get(
434
+ "WEBUI_AUTH_SIGNOUT_REDIRECT_URL", None
435
+ )
436
+
437
+ ####################################
438
+ # WEBUI_SECRET_KEY
439
+ ####################################
440
+
441
+ WEBUI_SECRET_KEY = os.environ.get(
442
+ "WEBUI_SECRET_KEY",
443
+ os.environ.get(
444
+ "WEBUI_JWT_SECRET_KEY", "t0p-s3cr3t"
445
+ ), # DEPRECATED: remove at next major version
446
+ )
447
+
448
+ WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax")
449
+
450
+ WEBUI_SESSION_COOKIE_SECURE = (
451
+ os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true"
452
+ )
453
+
454
+ WEBUI_AUTH_COOKIE_SAME_SITE = os.environ.get(
455
+ "WEBUI_AUTH_COOKIE_SAME_SITE", WEBUI_SESSION_COOKIE_SAME_SITE
456
+ )
457
+
458
+ WEBUI_AUTH_COOKIE_SECURE = (
459
+ os.environ.get(
460
+ "WEBUI_AUTH_COOKIE_SECURE",
461
+ os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false"),
462
+ ).lower()
463
+ == "true"
464
+ )
465
+
466
+ if WEBUI_AUTH and WEBUI_SECRET_KEY == "":
467
+ raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND)
468
+
469
+ ENABLE_COMPRESSION_MIDDLEWARE = (
470
+ os.environ.get("ENABLE_COMPRESSION_MIDDLEWARE", "True").lower() == "true"
471
+ )
472
+
473
+ ####################################
474
+ # OAUTH Configuration
475
+ ####################################
476
+ ENABLE_OAUTH_EMAIL_FALLBACK = (
477
+ os.environ.get("ENABLE_OAUTH_EMAIL_FALLBACK", "False").lower() == "true"
478
+ )
479
+
480
+ ENABLE_OAUTH_ID_TOKEN_COOKIE = (
481
+ os.environ.get("ENABLE_OAUTH_ID_TOKEN_COOKIE", "True").lower() == "true"
482
+ )
483
+
484
+ OAUTH_CLIENT_INFO_ENCRYPTION_KEY = os.environ.get(
485
+ "OAUTH_CLIENT_INFO_ENCRYPTION_KEY", WEBUI_SECRET_KEY
486
+ )
487
+
488
+ OAUTH_SESSION_TOKEN_ENCRYPTION_KEY = os.environ.get(
489
+ "OAUTH_SESSION_TOKEN_ENCRYPTION_KEY", WEBUI_SECRET_KEY
490
+ )
491
+
492
+ ####################################
493
+ # SCIM Configuration
494
+ ####################################
495
+
496
+ SCIM_ENABLED = os.environ.get("SCIM_ENABLED", "False").lower() == "true"
497
+ SCIM_TOKEN = os.environ.get("SCIM_TOKEN", "")
498
+
499
+ ####################################
500
+ # LICENSE_KEY
501
+ ####################################
502
+
503
+ LICENSE_KEY = os.environ.get("LICENSE_KEY", "")
504
+
505
+ LICENSE_BLOB = None
506
+ LICENSE_BLOB_PATH = os.environ.get("LICENSE_BLOB_PATH", DATA_DIR / "l.data")
507
+ if LICENSE_BLOB_PATH and os.path.exists(LICENSE_BLOB_PATH):
508
+ with open(LICENSE_BLOB_PATH, "rb") as f:
509
+ LICENSE_BLOB = f.read()
510
+
511
+ LICENSE_PUBLIC_KEY = os.environ.get("LICENSE_PUBLIC_KEY", "")
512
+
513
+ pk = None
514
+ if LICENSE_PUBLIC_KEY:
515
+ pk = serialization.load_pem_public_key(
516
+ f"""
517
+ -----BEGIN PUBLIC KEY-----
518
+ {LICENSE_PUBLIC_KEY}
519
+ -----END PUBLIC KEY-----
520
+ """.encode(
521
+ "utf-8"
522
+ )
523
+ )
524
+
525
+
526
+ ####################################
527
+ # MODELS
528
+ ####################################
529
+
530
+ MODELS_CACHE_TTL = os.environ.get("MODELS_CACHE_TTL", "1")
531
+ if MODELS_CACHE_TTL == "":
532
+ MODELS_CACHE_TTL = None
533
+ else:
534
+ try:
535
+ MODELS_CACHE_TTL = int(MODELS_CACHE_TTL)
536
+ except Exception:
537
+ MODELS_CACHE_TTL = 1
538
+
539
+
540
+ ####################################
541
+ # CHAT
542
+ ####################################
543
+
544
+ CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = os.environ.get(
545
+ "CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE", "1"
546
+ )
547
+
548
+ if CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE == "":
549
+ CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1
550
+ else:
551
+ try:
552
+ CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = int(
553
+ CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE
554
+ )
555
+ except Exception:
556
+ CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE = 1
557
+
558
+
559
+ CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = os.environ.get(
560
+ "CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES", "30"
561
+ )
562
+
563
+ if CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES == "":
564
+ CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = 30
565
+ else:
566
+ try:
567
+ CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = int(CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES)
568
+ except Exception:
569
+ CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES = 30
570
+
571
+
572
+ ####################################
573
+ # WEBSOCKET SUPPORT
574
+ ####################################
575
+
576
+ ENABLE_WEBSOCKET_SUPPORT = (
577
+ os.environ.get("ENABLE_WEBSOCKET_SUPPORT", "True").lower() == "true"
578
+ )
579
+
580
+
581
+ WEBSOCKET_MANAGER = os.environ.get("WEBSOCKET_MANAGER", "")
582
+
583
+ WEBSOCKET_REDIS_URL = os.environ.get("WEBSOCKET_REDIS_URL", REDIS_URL)
584
+ WEBSOCKET_REDIS_CLUSTER = (
585
+ os.environ.get("WEBSOCKET_REDIS_CLUSTER", str(REDIS_CLUSTER)).lower() == "true"
586
+ )
587
+
588
+ websocket_redis_lock_timeout = os.environ.get("WEBSOCKET_REDIS_LOCK_TIMEOUT", "60")
589
+
590
+ try:
591
+ WEBSOCKET_REDIS_LOCK_TIMEOUT = int(websocket_redis_lock_timeout)
592
+ except ValueError:
593
+ WEBSOCKET_REDIS_LOCK_TIMEOUT = 60
594
+
595
+ WEBSOCKET_SENTINEL_HOSTS = os.environ.get("WEBSOCKET_SENTINEL_HOSTS", "")
596
+ WEBSOCKET_SENTINEL_PORT = os.environ.get("WEBSOCKET_SENTINEL_PORT", "26379")
597
+
598
+
599
+ AIOHTTP_CLIENT_TIMEOUT = os.environ.get("AIOHTTP_CLIENT_TIMEOUT", "")
600
+
601
+ if AIOHTTP_CLIENT_TIMEOUT == "":
602
+ AIOHTTP_CLIENT_TIMEOUT = None
603
+ else:
604
+ try:
605
+ AIOHTTP_CLIENT_TIMEOUT = int(AIOHTTP_CLIENT_TIMEOUT)
606
+ except Exception:
607
+ AIOHTTP_CLIENT_TIMEOUT = 300
608
+
609
+
610
+ AIOHTTP_CLIENT_SESSION_SSL = (
611
+ os.environ.get("AIOHTTP_CLIENT_SESSION_SSL", "True").lower() == "true"
612
+ )
613
+
614
+ AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = os.environ.get(
615
+ "AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST",
616
+ os.environ.get("AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST", "10"),
617
+ )
618
+
619
+ if AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST == "":
620
+ AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = None
621
+ else:
622
+ try:
623
+ AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = int(AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST)
624
+ except Exception:
625
+ AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST = 10
626
+
627
+
628
+ AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = os.environ.get(
629
+ "AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA", "10"
630
+ )
631
+
632
+ if AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA == "":
633
+ AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = None
634
+ else:
635
+ try:
636
+ AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = int(
637
+ AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA
638
+ )
639
+ except Exception:
640
+ AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA = 10
641
+
642
+
643
+ AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL = (
644
+ os.environ.get("AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL", "True").lower() == "true"
645
+ )
646
+
647
+
648
+ ####################################
649
+ # SENTENCE TRANSFORMERS
650
+ ####################################
651
+
652
+
653
+ SENTENCE_TRANSFORMERS_BACKEND = os.environ.get("SENTENCE_TRANSFORMERS_BACKEND", "")
654
+ if SENTENCE_TRANSFORMERS_BACKEND == "":
655
+ SENTENCE_TRANSFORMERS_BACKEND = "torch"
656
+
657
+
658
+ SENTENCE_TRANSFORMERS_MODEL_KWARGS = os.environ.get(
659
+ "SENTENCE_TRANSFORMERS_MODEL_KWARGS", ""
660
+ )
661
+ if SENTENCE_TRANSFORMERS_MODEL_KWARGS == "":
662
+ SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
663
+ else:
664
+ try:
665
+ SENTENCE_TRANSFORMERS_MODEL_KWARGS = json.loads(
666
+ SENTENCE_TRANSFORMERS_MODEL_KWARGS
667
+ )
668
+ except Exception:
669
+ SENTENCE_TRANSFORMERS_MODEL_KWARGS = None
670
+
671
+
672
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = os.environ.get(
673
+ "SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND", ""
674
+ )
675
+ if SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND == "":
676
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND = "torch"
677
+
678
+
679
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = os.environ.get(
680
+ "SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS", ""
681
+ )
682
+ if SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS == "":
683
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
684
+ else:
685
+ try:
686
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = json.loads(
687
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS
688
+ )
689
+ except Exception:
690
+ SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None
691
+
692
+ ####################################
693
+ # OFFLINE_MODE
694
+ ####################################
695
+
696
+ ENABLE_VERSION_UPDATE_CHECK = (
697
+ os.environ.get("ENABLE_VERSION_UPDATE_CHECK", "true").lower() == "true"
698
+ )
699
+ OFFLINE_MODE = os.environ.get("OFFLINE_MODE", "false").lower() == "true"
700
+
701
+ if OFFLINE_MODE:
702
+ os.environ["HF_HUB_OFFLINE"] = "1"
703
+ ENABLE_VERSION_UPDATE_CHECK = False
704
+
705
+ ####################################
706
+ # AUDIT LOGGING
707
+ ####################################
708
+ # Where to store log file
709
+ AUDIT_LOGS_FILE_PATH = f"{DATA_DIR}/audit.log"
710
+ # Maximum size of a file before rotating into a new log file
711
+ AUDIT_LOG_FILE_ROTATION_SIZE = os.getenv("AUDIT_LOG_FILE_ROTATION_SIZE", "10MB")
712
+
713
+ # Comma separated list of logger names to use for audit logging
714
+ # Default is "uvicorn.access" which is the access log for Uvicorn
715
+ # You can add more logger names to this list if you want to capture more logs
716
+ AUDIT_UVICORN_LOGGER_NAMES = os.getenv(
717
+ "AUDIT_UVICORN_LOGGER_NAMES", "uvicorn.access"
718
+ ).split(",")
719
+
720
+ # METADATA | REQUEST | REQUEST_RESPONSE
721
+ AUDIT_LOG_LEVEL = os.getenv("AUDIT_LOG_LEVEL", "NONE").upper()
722
+ try:
723
+ MAX_BODY_LOG_SIZE = int(os.environ.get("MAX_BODY_LOG_SIZE") or 2048)
724
+ except ValueError:
725
+ MAX_BODY_LOG_SIZE = 2048
726
+
727
+ # Comma separated list for urls to exclude from audit
728
+ AUDIT_EXCLUDED_PATHS = os.getenv("AUDIT_EXCLUDED_PATHS", "/chats,/chat,/folders").split(
729
+ ","
730
+ )
731
+ AUDIT_EXCLUDED_PATHS = [path.strip() for path in AUDIT_EXCLUDED_PATHS]
732
+ AUDIT_EXCLUDED_PATHS = [path.lstrip("/") for path in AUDIT_EXCLUDED_PATHS]
733
+
734
+
735
+ ####################################
736
+ # OPENTELEMETRY
737
+ ####################################
738
+
739
+ ENABLE_OTEL = os.environ.get("ENABLE_OTEL", "False").lower() == "true"
740
+ ENABLE_OTEL_TRACES = os.environ.get("ENABLE_OTEL_TRACES", "False").lower() == "true"
741
+ ENABLE_OTEL_METRICS = os.environ.get("ENABLE_OTEL_METRICS", "False").lower() == "true"
742
+ ENABLE_OTEL_LOGS = os.environ.get("ENABLE_OTEL_LOGS", "False").lower() == "true"
743
+
744
+ OTEL_EXPORTER_OTLP_ENDPOINT = os.environ.get(
745
+ "OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"
746
+ )
747
+ OTEL_METRICS_EXPORTER_OTLP_ENDPOINT = os.environ.get(
748
+ "OTEL_METRICS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT
749
+ )
750
+ OTEL_LOGS_EXPORTER_OTLP_ENDPOINT = os.environ.get(
751
+ "OTEL_LOGS_EXPORTER_OTLP_ENDPOINT", OTEL_EXPORTER_OTLP_ENDPOINT
752
+ )
753
+ OTEL_EXPORTER_OTLP_INSECURE = (
754
+ os.environ.get("OTEL_EXPORTER_OTLP_INSECURE", "False").lower() == "true"
755
+ )
756
+ OTEL_METRICS_EXPORTER_OTLP_INSECURE = (
757
+ os.environ.get(
758
+ "OTEL_METRICS_EXPORTER_OTLP_INSECURE", str(OTEL_EXPORTER_OTLP_INSECURE)
759
+ ).lower()
760
+ == "true"
761
+ )
762
+ OTEL_LOGS_EXPORTER_OTLP_INSECURE = (
763
+ os.environ.get(
764
+ "OTEL_LOGS_EXPORTER_OTLP_INSECURE", str(OTEL_EXPORTER_OTLP_INSECURE)
765
+ ).lower()
766
+ == "true"
767
+ )
768
+ OTEL_SERVICE_NAME = os.environ.get("OTEL_SERVICE_NAME", "open-webui")
769
+ OTEL_RESOURCE_ATTRIBUTES = os.environ.get(
770
+ "OTEL_RESOURCE_ATTRIBUTES", ""
771
+ ) # e.g. key1=val1,key2=val2
772
+ OTEL_TRACES_SAMPLER = os.environ.get(
773
+ "OTEL_TRACES_SAMPLER", "parentbased_always_on"
774
+ ).lower()
775
+ OTEL_BASIC_AUTH_USERNAME = os.environ.get("OTEL_BASIC_AUTH_USERNAME", "")
776
+ OTEL_BASIC_AUTH_PASSWORD = os.environ.get("OTEL_BASIC_AUTH_PASSWORD", "")
777
+
778
+ OTEL_METRICS_BASIC_AUTH_USERNAME = os.environ.get(
779
+ "OTEL_METRICS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME
780
+ )
781
+ OTEL_METRICS_BASIC_AUTH_PASSWORD = os.environ.get(
782
+ "OTEL_METRICS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD
783
+ )
784
+ OTEL_LOGS_BASIC_AUTH_USERNAME = os.environ.get(
785
+ "OTEL_LOGS_BASIC_AUTH_USERNAME", OTEL_BASIC_AUTH_USERNAME
786
+ )
787
+ OTEL_LOGS_BASIC_AUTH_PASSWORD = os.environ.get(
788
+ "OTEL_LOGS_BASIC_AUTH_PASSWORD", OTEL_BASIC_AUTH_PASSWORD
789
+ )
790
+
791
+ OTEL_OTLP_SPAN_EXPORTER = os.environ.get(
792
+ "OTEL_OTLP_SPAN_EXPORTER", "grpc"
793
+ ).lower() # grpc or http
794
+
795
+ OTEL_METRICS_OTLP_SPAN_EXPORTER = os.environ.get(
796
+ "OTEL_METRICS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER
797
+ ).lower() # grpc or http
798
+
799
+ OTEL_LOGS_OTLP_SPAN_EXPORTER = os.environ.get(
800
+ "OTEL_LOGS_OTLP_SPAN_EXPORTER", OTEL_OTLP_SPAN_EXPORTER
801
+ ).lower() # grpc or http
802
+
803
+ ####################################
804
+ # TOOLS/FUNCTIONS PIP OPTIONS
805
+ ####################################
806
+
807
+ PIP_OPTIONS = os.getenv("PIP_OPTIONS", "").split()
808
+ PIP_PACKAGE_INDEX_OPTIONS = os.getenv("PIP_PACKAGE_INDEX_OPTIONS", "").split()
809
+
810
+
811
+ ####################################
812
+ # PROGRESSIVE WEB APP OPTIONS
813
+ ####################################
814
+
815
+ EXTERNAL_PWA_MANIFEST_URL = os.environ.get("EXTERNAL_PWA_MANIFEST_URL")