config.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """集中读取和校验项目配置。
  2. 配置优先从后端目录的 ``.env`` 读取;若某项未配置,则使用字段右侧的默认值。
  3. Pydantic 会自动把环境变量中的字符串转换成声明的 Python 类型。
  4. """
  5. from functools import lru_cache
  6. from pathlib import Path
  7. from typing import Literal
  8. from pydantic import Field, field_validator
  9. from pydantic_settings import BaseSettings, SettingsConfigDict
  10. # 当前文件位于 backend/app/core,向上两级就是后端项目根目录。
  11. BACKEND_ROOT = Path(__file__).resolve().parents[2]
  12. class Settings(BaseSettings):
  13. """应用运行时需要的全部配置及其默认值。"""
  14. model_config = SettingsConfigDict(
  15. env_file=BACKEND_ROOT / ".env",
  16. env_file_encoding="utf-8",
  17. case_sensitive=False,
  18. extra="ignore",
  19. )
  20. # Literal 限制只能使用列出的三种环境名称,拼写错误会在启动时直接报错。
  21. app_env: Literal["development", "test", "production"] = "development"
  22. app_host: str = "127.0.0.1"
  23. app_port: int = 8000
  24. app_timezone: str = "Asia/Shanghai"
  25. app_cors_origins: list[str] = [
  26. "http://127.0.0.1:5173",
  27. "http://127.0.0.1:5174",
  28. ]
  29. mysql_host: str = "127.0.0.1"
  30. mysql_port: int = 3306
  31. mysql_user: str = "zbt_s1"
  32. mysql_password: str = ""
  33. mysql_core_database: str = "insurance_s1_core"
  34. mysql_agent_database: str = "insurance_s1_agent"
  35. mysql_analytics_database: str = "insurance_s1_analytics"
  36. redis_url: str = "redis://127.0.0.1:6379/0"
  37. redis_prefix: str = "ins:s1:"
  38. agent_rate_limit: int = Field(default=20, ge=1, le=1000)
  39. agent_rate_window_seconds: int = Field(default=60, ge=1, le=3600)
  40. agent_hot_state_ttl_seconds: int = Field(default=3600, ge=60, le=86400)
  41. agent_event_ttl_seconds: int = Field(default=1800, ge=60, le=86400)
  42. deepseek_api_key: str = ""
  43. deepseek_base_url: str = "https://api.deepseek.com"
  44. deepseek_model: str = "deepseek-chat"
  45. langsmith_api_key: str = ""
  46. langsmith_endpoint: str = "https://api.smith.langchain.com"
  47. langsmith_project: str = "智保通-第一阶段-智能投保"
  48. langsmith_tracing: bool = True
  49. jwt_access_secret: str = Field(default="development-access-secret-change-me", min_length=32)
  50. jwt_refresh_secret: str = Field(default="development-refresh-secret-change-me", min_length=32)
  51. field_encryption_key: str = Field(default="development-field-key-change-me-now", min_length=32)
  52. dev_fixed_otp: str = Field(default="147258", pattern=r"^\d{6}$")
  53. dev_tools_enabled: bool = True
  54. mock_payment_callback_secret: str = Field(
  55. default="development-mock-payment-secret-change-me",
  56. min_length=32,
  57. )
  58. access_token_minutes: int = 15
  59. refresh_token_days: int = 7
  60. # 以下验证器限制程序只能访问本项目约定的数据库,避免误连或误操作其他库。
  61. @field_validator("mysql_core_database")
  62. @classmethod
  63. def validate_core_database(cls, value: str) -> str:
  64. if value not in {"insurance_s1_core", "insurance_s1_test_core"}:
  65. raise ValueError("第一阶段Core数据库名称不在白名单")
  66. return value
  67. @field_validator("mysql_agent_database")
  68. @classmethod
  69. def validate_agent_database(cls, value: str) -> str:
  70. if value not in {"insurance_s1_agent", "insurance_s1_test_agent"}:
  71. raise ValueError("第一阶段Agent数据库名称不在白名单")
  72. return value
  73. @field_validator("mysql_analytics_database")
  74. @classmethod
  75. def validate_analytics_database(cls, value: str) -> str:
  76. if value not in {"insurance_s1_analytics", "insurance_s1_test_analytics"}:
  77. raise ValueError("第一阶段Analytics数据库名称不在白名单")
  78. return value
  79. @field_validator("redis_prefix")
  80. @classmethod
  81. def validate_redis_prefix(cls, value: str) -> str:
  82. if value != "ins:s1:" and not value.startswith("ins:s1:test:"):
  83. raise ValueError("第一阶段Redis前缀不在白名单")
  84. return value
  85. @lru_cache
  86. def get_settings() -> Settings:
  87. """创建并缓存配置对象,后续调用复用同一个实例。"""
  88. return Settings()