config.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. """配置管理 — 密钥全部来自环境变量,禁止硬编码。"""
  2. import os
  3. from pathlib import Path
  4. from typing import List, Optional, Tuple
  5. from dotenv import load_dotenv
  6. from pydantic_settings import BaseSettings, SettingsConfigDict
  7. # 优先加载 backend/.env
  8. _env_path = Path(__file__).resolve().parent.parent / ".env"
  9. load_dotenv(_env_path)
  10. load_dotenv() # 兼容从仓库根目录启动
  11. class Settings(BaseSettings):
  12. """应用配置(pydantic-settings)"""
  13. model_config = SettingsConfigDict(
  14. env_file=str(_env_path),
  15. env_file_encoding="utf-8",
  16. case_sensitive=False,
  17. extra="ignore",
  18. )
  19. app_name: str = "LLM 电影推荐助手"
  20. app_version: str = "0.1.0"
  21. debug: bool = False
  22. host: str = "0.0.0.0"
  23. port: int = 8000
  24. # 逗号分隔,代码中再拆成列表
  25. cors_origins: str = (
  26. "http://localhost:5173,http://127.0.0.1:5173,"
  27. "http://localhost:3000,http://127.0.0.1:3000"
  28. )
  29. # TMDB:二选一即可(Access Token 优先)
  30. tmdb_access_token: str = ""
  31. tmdb_api_key: str = ""
  32. tmdb_language: str = "zh-CN"
  33. tmdb_include_adult: bool = False
  34. tmdb_image_base_url: str = "https://image.tmdb.org/t/p/w500"
  35. # LLM 也可由 HelloAgents 直接读 LLM_* 环境变量;此处仅作展示/兜底
  36. llm_api_key: str = ""
  37. llm_base_url: str = ""
  38. llm_model_id: str = ""
  39. log_level: str = "INFO"
  40. # HelloAgents Trace(写入 memory/traces;调试时再开)
  41. trace_enabled: bool = False
  42. trace_dir: str = "memory/traces"
  43. def get_cors_origins_list(self) -> List[str]:
  44. return [o.strip() for o in self.cors_origins.split(",") if o.strip()]
  45. def has_tmdb_credentials(self) -> bool:
  46. return bool(self.tmdb_access_token or self.tmdb_api_key)
  47. def resolve_tmdb_credentials(self) -> Tuple[Optional[str], Optional[str]]:
  48. """返回 (access_token, api_key);Access Token 优先用于 Bearer 鉴权。"""
  49. token = (self.tmdb_access_token or "").strip() or None
  50. api_key = (self.tmdb_api_key or "").strip() or None
  51. return token, api_key
  52. settings = Settings()
  53. def get_settings() -> Settings:
  54. return settings
  55. def validate_config() -> bool:
  56. """startup 校验:本回合仅警告,不阻断启动(便于先跑 /health)。"""
  57. warnings: list[str] = []
  58. if not settings.has_tmdb_credentials():
  59. warnings.append("TMDB_ACCESS_TOKEN / TMDB_API_KEY 未配置,片库接口稍后不可用")
  60. llm_key = (
  61. os.getenv("LLM_API_KEY")
  62. or settings.llm_api_key
  63. or os.getenv("OPENAI_API_KEY")
  64. )
  65. if not llm_key:
  66. warnings.append("LLM_API_KEY 未配置,多智能体推荐稍后可能无法调用模型")
  67. if warnings:
  68. print("\n⚠️ 配置警告:")
  69. for w in warnings:
  70. print(f" - {w}")
  71. return True
  72. def print_config() -> None:
  73. llm_key = (
  74. os.getenv("LLM_API_KEY")
  75. or settings.llm_api_key
  76. or os.getenv("OPENAI_API_KEY")
  77. )
  78. llm_base = os.getenv("LLM_BASE_URL") or settings.llm_base_url or "(默认)"
  79. llm_model = os.getenv("LLM_MODEL_ID") or settings.llm_model_id or "(默认)"
  80. print(f"应用名称: {settings.app_name}")
  81. print(f"版本: {settings.app_version}")
  82. print(f"服务器: {settings.host}:{settings.port}")
  83. print(f"TMDB: {'已配置' if settings.has_tmdb_credentials() else '未配置'}")
  84. print(f"LLM API Key: {'已配置' if llm_key else '未配置'}")
  85. print(f"LLM Base URL: {llm_base}")
  86. print(f"LLM Model: {llm_model}")
  87. print(f"日志级别: {settings.log_level}")
  88. print(f"Agent Trace: {'开启' if settings.trace_enabled else '关闭'} ({settings.trace_dir})")