env.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import importlib.metadata
  2. import json
  3. import logging
  4. import os
  5. import pkgutil
  6. import sys
  7. from pathlib import Path
  8. import markdown
  9. from bs4 import BeautifulSoup
  10. from open_webui.constants import ERROR_MESSAGES
  11. ####################################
  12. # Load .env file
  13. ####################################
  14. OPEN_WEBUI_DIR = Path(__file__).parent # the path containing this file
  15. print(OPEN_WEBUI_DIR)
  16. BACKEND_DIR = OPEN_WEBUI_DIR.parent # the path containing this file
  17. BASE_DIR = BACKEND_DIR.parent # the path containing the backend/
  18. print(BACKEND_DIR)
  19. print(BASE_DIR)
  20. try:
  21. from dotenv import find_dotenv, load_dotenv
  22. load_dotenv(find_dotenv(str(BASE_DIR / ".env")))
  23. except ImportError:
  24. print("dotenv not installed, skipping...")
  25. ####################################
  26. # LOGGING
  27. ####################################
  28. log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]
  29. GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper()
  30. if GLOBAL_LOG_LEVEL in log_levels:
  31. logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL, force=True)
  32. else:
  33. GLOBAL_LOG_LEVEL = "INFO"
  34. log = logging.getLogger(__name__)
  35. log.info(f"GLOBAL_LOG_LEVEL: {GLOBAL_LOG_LEVEL}")
  36. log_sources = [
  37. "AUDIO",
  38. "COMFYUI",
  39. "CONFIG",
  40. "DB",
  41. "IMAGES",
  42. "MAIN",
  43. "MODELS",
  44. "OLLAMA",
  45. "OPENAI",
  46. "RAG",
  47. "WEBHOOK",
  48. ]
  49. SRC_LOG_LEVELS = {}
  50. for source in log_sources:
  51. log_env_var = source + "_LOG_LEVEL"
  52. SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper()
  53. if SRC_LOG_LEVELS[source] not in log_levels:
  54. SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL
  55. log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}")
  56. log.setLevel(SRC_LOG_LEVELS["CONFIG"])
  57. WEBUI_NAME = os.environ.get("WEBUI_NAME", "Open WebUI")
  58. if WEBUI_NAME != "Open WebUI":
  59. WEBUI_NAME += " (Open WebUI)"
  60. WEBUI_URL = os.environ.get("WEBUI_URL", "http://localhost:3000")
  61. WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png"
  62. ####################################
  63. # ENV (dev,test,prod)
  64. ####################################
  65. ENV = os.environ.get("ENV", "dev")
  66. PIP_INSTALL = False
  67. try:
  68. importlib.metadata.version("open-webui")
  69. PIP_INSTALL = True
  70. except importlib.metadata.PackageNotFoundError:
  71. pass
  72. if PIP_INSTALL:
  73. PACKAGE_DATA = {"version": importlib.metadata.version("open-webui")}
  74. else:
  75. try:
  76. PACKAGE_DATA = json.loads((BASE_DIR / "package.json").read_text())
  77. except Exception:
  78. PACKAGE_DATA = {"version": "0.0.0"}
  79. VERSION = PACKAGE_DATA["version"]
  80. # Function to parse each section
  81. def parse_section(section):
  82. items = []
  83. for li in section.find_all("li"):
  84. # Extract raw HTML string
  85. raw_html = str(li)
  86. # Extract text without HTML tags
  87. text = li.get_text(separator=" ", strip=True)
  88. # Split into title and content
  89. parts = text.split(": ", 1)
  90. title = parts[0].strip() if len(parts) > 1 else ""
  91. content = parts[1].strip() if len(parts) > 1 else text
  92. items.append({"title": title, "content": content, "raw": raw_html})
  93. return items
  94. try:
  95. changelog_path = BASE_DIR / "CHANGELOG.md"
  96. with open(str(changelog_path.absolute()), "r", encoding="utf8") as file:
  97. changelog_content = file.read()
  98. except Exception:
  99. changelog_content = (pkgutil.get_data("open_webui", "CHANGELOG.md") or b"").decode()
  100. # Convert markdown content to HTML
  101. html_content = markdown.markdown(changelog_content)
  102. # Parse the HTML content
  103. soup = BeautifulSoup(html_content, "html.parser")
  104. # Initialize JSON structure
  105. changelog_json = {}
  106. # Iterate over each version
  107. for version in soup.find_all("h2"):
  108. version_number = version.get_text().strip().split(" - ")[0][1:-1] # Remove brackets
  109. date = version.get_text().strip().split(" - ")[1]
  110. version_data = {"date": date}
  111. # Find the next sibling that is a h3 tag (section title)
  112. current = version.find_next_sibling()
  113. while current and current.name != "h2":
  114. if current.name == "h3":
  115. section_title = current.get_text().lower() # e.g., "added", "fixed"
  116. section_items = parse_section(current.find_next_sibling("ul"))
  117. version_data[section_title] = section_items
  118. # Move to the next element
  119. current = current.find_next_sibling()
  120. changelog_json[version_number] = version_data
  121. CHANGELOG = changelog_json
  122. ####################################
  123. # SAFE_MODE
  124. ####################################
  125. SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
  126. ####################################
  127. # WEBUI_BUILD_HASH
  128. ####################################
  129. WEBUI_BUILD_HASH = os.environ.get("WEBUI_BUILD_HASH", "dev-build")
  130. ####################################
  131. # DATA/FRONTEND BUILD DIR
  132. ####################################
  133. DATA_DIR = Path(os.getenv("DATA_DIR", BACKEND_DIR / "data")).resolve()
  134. if PIP_INSTALL:
  135. # Check if the data directory exists in the package directory
  136. if DATA_DIR.exists():
  137. log.info(f"Moving {DATA_DIR} to {OPEN_WEBUI_DIR / 'data'}")
  138. DATA_DIR.rename(OPEN_WEBUI_DIR / "data")
  139. DATA_DIR = OPEN_WEBUI_DIR / "data"
  140. FRONTEND_BUILD_DIR = Path(os.getenv("FRONTEND_BUILD_DIR", BASE_DIR / "build")).resolve()
  141. RESET_CONFIG_ON_START = (
  142. os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true"
  143. )
  144. if RESET_CONFIG_ON_START:
  145. try:
  146. os.remove(f"{DATA_DIR}/config.json")
  147. with open(f"{DATA_DIR}/config.json", "w") as f:
  148. f.write("{}")
  149. except Exception:
  150. pass
  151. ####################################
  152. # Database
  153. ####################################
  154. # Check if the file exists
  155. if os.path.exists(f"{DATA_DIR}/ollama.db"):
  156. # Rename the file
  157. os.rename(f"{DATA_DIR}/ollama.db", f"{DATA_DIR}/webui.db")
  158. log.info("Database migrated from Ollama-WebUI successfully.")
  159. else:
  160. pass
  161. DATABASE_URL = os.environ.get("DATABASE_URL", f"sqlite:///{DATA_DIR}/webui.db")
  162. # Replace the postgres:// with postgresql://
  163. if "postgres://" in DATABASE_URL:
  164. DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")
  165. ####################################
  166. # WEBUI_AUTH (Required for security)
  167. ####################################
  168. WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true"
  169. WEBUI_AUTH_TRUSTED_EMAIL_HEADER = os.environ.get(
  170. "WEBUI_AUTH_TRUSTED_EMAIL_HEADER", None
  171. )
  172. WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get("WEBUI_AUTH_TRUSTED_NAME_HEADER", None)
  173. ####################################
  174. # WEBUI_SECRET_KEY
  175. ####################################
  176. WEBUI_SECRET_KEY = os.environ.get(
  177. "WEBUI_SECRET_KEY",
  178. os.environ.get(
  179. "WEBUI_JWT_SECRET_KEY", "t0p-s3cr3t"
  180. ), # DEPRECATED: remove at next major version
  181. )
  182. WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get(
  183. "WEBUI_SESSION_COOKIE_SAME_SITE",
  184. os.environ.get("WEBUI_SESSION_COOKIE_SAME_SITE", "lax"),
  185. )
  186. WEBUI_SESSION_COOKIE_SECURE = os.environ.get(
  187. "WEBUI_SESSION_COOKIE_SECURE",
  188. os.environ.get("WEBUI_SESSION_COOKIE_SECURE", "false").lower() == "true",
  189. )
  190. if WEBUI_AUTH and WEBUI_SECRET_KEY == "":
  191. raise ValueError(ERROR_MESSAGES.ENV_VAR_NOT_FOUND)