from pydantic_settings import BaseSettings from pydantic import ConfigDict, field_validator from functools import lru_cache from urllib.parse import quote_plus class Settings(BaseSettings): # Application APP_NAME: str = "ERP AI Assistant" APP_ENV: str = "development" DEBUG: bool = True SECRET_KEY: str # Database DB_DRIVER: str DB_SERVER: str DB_PORT: int = 1433 DB_NAME: str DB_USER: str DB_PASSWORD: str # Claude API ANTHROPIC_API_KEY: str ANTHROPIC_BASE_URL: str | None = None # Optional custom base URL for proxy/self-hosted CLAUDE_MODEL: str = "claude-sonnet-4-6" CLAUDE_MAX_TOKENS: int = 8192 CLAUDE_TEMPERATURE: float = 0.7 # Knowledge Base KNOWLEDGE_BASE_PATH: str = "./knowledge_base" CHROMA_DB_PATH: str = "./knowledge_base/chroma_db" EMBEDDING_MODEL: str = "all-MiniLM-L6-v2" CHUNK_SIZE: int = 500 CHUNK_OVERLAP: int = 50 # HuggingFace HF_ENDPOINT: str | None = None # Optional: HuggingFace mirror endpoint @property def DATABASE_URL(self) -> str: """构建数据库连接 URL(密码安全编码)""" password = quote_plus(self.DB_PASSWORD) return ( f"mssql+pyodbc://{self.DB_USER}:{password}" f"@{self.DB_SERVER}:{self.DB_PORT}/{self.DB_NAME}" f"?driver={quote_plus(self.DB_DRIVER)}" ) @field_validator('CLAUDE_TEMPERATURE') @classmethod def validate_temperature(cls, v): if not 0 <= v <= 2: raise ValueError('CLAUDE_TEMPERATURE must be between 0 and 2') return v @field_validator('CHUNK_OVERLAP') @classmethod def validate_chunk_overlap(cls, v, info): chunk_size = info.data.get('CHUNK_SIZE', 500) if v >= chunk_size: raise ValueError('CHUNK_OVERLAP must be less than CHUNK_SIZE') return v model_config = ConfigDict(env_file=".env", case_sensitive=True) @lru_cache() def get_settings() -> Settings: """获取配置单例""" return Settings()