import os from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent def load_dotenv(dotenv_path: Path) -> None: """ 读取根目录 `.env` 并注入进程环境。 这里使用极简解析逻辑,目的是减少额外依赖, 同时让本地 `runserver`、`pytest` 与 Docker Compose 共用一套配置文件。 """ if not dotenv_path.exists(): return for raw_line in dotenv_path.read_text(encoding="utf-8").splitlines(): line = raw_line.strip() if not line or line.startswith("#") or "=" not in line: continue key, value = line.split("=", 1) key = key.strip() value = value.strip().strip('"').strip("'") os.environ.setdefault(key, value) load_dotenv(BASE_DIR / ".env") def env_bool(name: str, default: bool = False) -> bool: """将常见的字符串布尔值转换为 Python bool。""" value = os.environ.get(name) if value is None: return default return value.lower() in {"1", "true", "yes", "on"} # Django 核心运行参数。 SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "dev-secret-key") DEBUG = env_bool("DJANGO_DEBUG", True) ALLOWED_HOSTS = [ host.strip() for host in os.environ.get("DJANGO_ALLOWED_HOSTS", "*").split(",") if host.strip() ] INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", "apps.scenarios", "apps.documents", "apps.chat", "apps.audit", "apps.platform_ui", ] MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", ] ROOT_URLCONF = "config.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ] WSGI_APPLICATION = "config.wsgi.application" # V1 默认使用 SQLite,确保本地演示零外部依赖。 DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "data" / "db.sqlite3", } } LANGUAGE_CODE = "zh-hans" TIME_ZONE = "Asia/Shanghai" USE_I18N = True USE_TZ = True STATIC_URL = "static/" STATICFILES_DIRS = [BASE_DIR / "static"] MEDIA_URL = "media/" # 上传根目录可通过环境变量覆盖,便于 Docker 挂载到持久化目录。 MEDIA_ROOT = Path(os.environ.get("UPLOAD_ROOT", BASE_DIR / "data" / "uploads")) # 配置目录和 Chroma 数据目录都允许外部覆盖,方便复试现场快速切换。 SCENARIO_CONFIG_DIR = Path(os.environ.get("SCENARIO_CONFIG_DIR", BASE_DIR / "configs")) GOVERNANCE_CONFIG_PATH = Path( os.environ.get("GOVERNANCE_CONFIG_PATH", BASE_DIR / "configs" / "governance.yaml") ) CHROMA_PATH = Path(os.environ.get("CHROMA_PATH", BASE_DIR / "data" / "chroma")) # LLM 与 Embedding 默认遵循“尽量少配置也能跑”的策略: # Embedding 未单独配置时自动复用 LLM 的 Key 和 Base URL。 LLM_API_KEY = os.environ.get("LLM_API_KEY", "") LLM_BASE_URL = os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1") LLM_MODEL = os.environ.get("LLM_MODEL", "gpt-4.1-mini") EMBEDDING_API_KEY = os.environ.get("EMBEDDING_API_KEY", LLM_API_KEY) EMBEDDING_BASE_URL = os.environ.get("EMBEDDING_BASE_URL", LLM_BASE_URL) EMBEDDING_MODEL = os.environ.get("EMBEDDING_MODEL", "text-embedding-3-small") DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"