mirror of
https://github.com/open-webui/open-webui
synced 2024-11-07 00:59:52 +00:00
74169b0320
Previously, the `DATA_DIR` environment variable was always overridden by defaulting to `OPEN_WEBUI_DIR / "data"`, which ignored user-defined `DATA_DIR` values. Additionally, when `DATA_DIR` and `NEW_DATA_DIR` were the same, the script attempted to copy files into themselves, leading to errors or redundant operations. This commit ensures that: 1. The `DATA_DIR` environment variable is respected and not overridden. 2. Copy operations between `DATA_DIR` and `NEW_DATA_DIR` are only performed if the directories are different, preventing errors when they point to the same location. These changes resolve potential file copy errors and preserve user configurations.
283 lines
7.6 KiB
Python
283 lines
7.6 KiB
Python
import importlib.metadata
|
|
import json
|
|
import logging
|
|
import os
|
|
import pkgutil
|
|
import sys
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
import markdown
|
|
from bs4 import BeautifulSoup
|
|
from open_webui.constants import ERROR_MESSAGES
|
|
|
|
####################################
|
|
# Load .env file
|
|
####################################
|
|
|
|
OPEN_WEBUI_DIR = Path(__file__).parent # the path containing this file
|
|
print(OPEN_WEBUI_DIR)
|
|
|
|
BACKEND_DIR = OPEN_WEBUI_DIR.parent # the path containing this file
|
|
BASE_DIR = BACKEND_DIR.parent # the path containing the backend/
|
|
|
|
print(BACKEND_DIR)
|
|
print(BASE_DIR)
|
|
|
|
try:
|
|
from dotenv import find_dotenv, load_dotenv
|
|
|
|
load_dotenv(find_dotenv(str(BASE_DIR / ".env")))
|
|
except ImportError:
|
|
print("dotenv not installed, skipping...")
|
|
|
|
|
|
####################################
|
|
# LOGGING
|
|
####################################
|
|
|
|
log_levels = ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"]
|
|
|
|
GLOBAL_LOG_LEVEL = os.environ.get("GLOBAL_LOG_LEVEL", "").upper()
|
|
if GLOBAL_LOG_LEVEL in log_levels:
|
|
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}")
|
|
|
|
log_sources = [
|
|
"AUDIO",
|
|
"COMFYUI",
|
|
"CONFIG",
|
|
"DB",
|
|
"IMAGES",
|
|
"MAIN",
|
|
"MODELS",
|
|
"OLLAMA",
|
|
"OPENAI",
|
|
"RAG",
|
|
"WEBHOOK",
|
|
]
|
|
|
|
SRC_LOG_LEVELS = {}
|
|
|
|
for source in log_sources:
|
|
log_env_var = source + "_LOG_LEVEL"
|
|
SRC_LOG_LEVELS[source] = os.environ.get(log_env_var, "").upper()
|
|
if SRC_LOG_LEVELS[source] not in log_levels:
|
|
SRC_LOG_LEVELS[source] = GLOBAL_LOG_LEVEL
|
|
log.info(f"{log_env_var}: {SRC_LOG_LEVELS[source]}")
|
|
|
|
log.setLevel(SRC_LOG_LEVELS["CONFIG"])
|
|
|
|
|
|
WEBUI_NAME = os.environ.get("WEBUI_NAME", "Open WebUI")
|
|
if WEBUI_NAME != "Open WebUI":
|
|
WEBUI_NAME += " (Open WebUI)"
|
|
|
|
WEBUI_URL = os.environ.get("WEBUI_URL", "http://localhost:3000")
|
|
|
|
WEBUI_FAVICON_URL = "https://openwebui.com/favicon.png"
|
|
|
|
|
|
####################################
|
|
# ENV (dev,test,prod)
|
|
####################################
|
|
|
|
ENV = os.environ.get("ENV", "dev")
|
|
|
|
PIP_INSTALL = False
|
|
try:
|
|
importlib.metadata.version("open-webui")
|
|
PIP_INSTALL = True
|
|
except importlib.metadata.PackageNotFoundError:
|
|
pass
|
|
|
|
|
|
PIP_INSTALL = (
|
|
os.environ.get("PIP_INSTALL") if os.environ.get("PIP_INSTALL") else PIP_INSTALL
|
|
)
|
|
|
|
if PIP_INSTALL:
|
|
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"]
|
|
|
|
|
|
# Function to parse each section
|
|
def parse_section(section):
|
|
items = []
|
|
for li in section.find_all("li"):
|
|
# Extract raw HTML string
|
|
raw_html = str(li)
|
|
|
|
# Extract text without HTML tags
|
|
text = li.get_text(separator=" ", strip=True)
|
|
|
|
# Split into title and content
|
|
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()
|
|
|
|
|
|
# Convert markdown content to HTML
|
|
html_content = markdown.markdown(changelog_content)
|
|
|
|
# Parse the HTML content
|
|
soup = BeautifulSoup(html_content, "html.parser")
|
|
|
|
# Initialize JSON structure
|
|
changelog_json = {}
|
|
|
|
# Iterate over each version
|
|
for version in soup.find_all("h2"):
|
|
version_number = version.get_text().strip().split(" - ")[0][1:-1] # Remove brackets
|
|
date = version.get_text().strip().split(" - ")[1]
|
|
|
|
version_data = {"date": date}
|
|
|
|
# Find the next sibling that is a h3 tag (section title)
|
|
current = version.find_next_sibling()
|
|
|
|
while current and current.name != "h2":
|
|
if current.name == "h3":
|
|
section_title = current.get_text().lower() # e.g., "added", "fixed"
|
|
section_items = parse_section(current.find_next_sibling("ul"))
|
|
version_data[section_title] = section_items
|
|
|
|
# Move to the next element
|
|
current = current.find_next_sibling()
|
|
|
|
changelog_json[version_number] = version_data
|
|
|
|
|
|
CHANGELOG = changelog_json
|
|
|
|
####################################
|
|
# SAFE_MODE
|
|
####################################
|
|
|
|
SAFE_MODE = os.environ.get("SAFE_MODE", "false").lower() == "true"
|
|
|
|
####################################
|
|
# WEBUI_BUILD_HASH
|
|
####################################
|
|
|
|
WEBUI_BUILD_HASH = os.environ.get("WEBUI_BUILD_HASH", "dev-build")
|
|
|
|
####################################
|
|
# DATA/FRONTEND BUILD DIR
|
|
####################################
|
|
|
|
DATA_DIR = Path(os.getenv("DATA_DIR", BACKEND_DIR / "data")).resolve()
|
|
|
|
if PIP_INSTALL:
|
|
NEW_DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data")).resolve()
|
|
NEW_DATA_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Check if the data directory exists in the package directory
|
|
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)
|
|
|
|
DATA_DIR = Path(os.getenv("DATA_DIR", OPEN_WEBUI_DIR / "data"))
|
|
|
|
|
|
FRONTEND_BUILD_DIR = Path(os.getenv("FRONTEND_BUILD_DIR", BASE_DIR / "build")).resolve()
|
|
if PIP_INSTALL:
|
|
FRONTEND_BUILD_DIR = Path(
|
|
os.getenv("FRONTEND_BUILD_DIR", OPEN_WEBUI_DIR / "frontend")
|
|
).resolve()
|
|
|
|
|
|
RESET_CONFIG_ON_START = (
|
|
os.environ.get("RESET_CONFIG_ON_START", "False").lower() == "true"
|
|
)
|
|
|
|
if RESET_CONFIG_ON_START:
|
|
try:
|
|
os.remove(f"{DATA_DIR}/config.json")
|
|
with open(f"{DATA_DIR}/config.json", "w") as f:
|
|
f.write("{}")
|
|
except Exception:
|
|
pass
|
|
|
|
####################################
|
|
# Database
|
|
####################################
|
|
|
|
# Check if the file exists
|
|
if os.path.exists(f"{DATA_DIR}/ollama.db"):
|
|
# Rename the file
|
|
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")
|
|
|
|
# Replace the postgres:// with postgresql://
|
|
if "postgres://" in DATABASE_URL:
|
|
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")
|
|
|
|
|
|
####################################
|
|
# WEBUI_AUTH (Required for security)
|
|
####################################
|
|
|
|
WEBUI_AUTH = os.environ.get("WEBUI_AUTH", "True").lower() == "true"
|
|
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_SECRET_KEY
|
|
####################################
|
|
|
|
WEBUI_SECRET_KEY = os.environ.get(
|
|
"WEBUI_SECRET_KEY",
|
|
os.environ.get(
|
|
"WEBUI_JWT_SECRET_KEY", "t0p-s3cr3t"
|
|
), # DEPRECATED: remove at next major version
|
|
)
|
|
|
|
WEBUI_SESSION_COOKIE_SAME_SITE = os.environ.get(
|
|
"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",
|
|
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)
|