from pydantic_settings import BaseSettings from functools import lru_cache from pathlib import Path import os def _find_env_file(): candidates = [Path.cwd() / ".env", Path(__file__).resolve().parent.parent.parent.parent / ".env"] for p in candidates: if p.exists(): return str(p) return ".env" class Settings(BaseSettings): app_name: str = "PharmacopoeiaAI" app_env: str = "development" app_debug: bool = True secret_key: str = "change-me" api_prefix: str = "/api/v1" postgres_host: str = "localhost" postgres_port: int = 5432 postgres_db: str = "pharmacopoeia" postgres_user: str = "postgres" postgres_password: str = "postgres" redis_host: str = "localhost" redis_port: int = 6379 redis_password: str = "" redis_db: int = 0 milvus_host: str = "localhost" milvus_port: int = 19530 milvus_collection: str = "drug_entries" llm_provider: str = "qwen" qwen_api_key: str = "" qwen_base_url: str = "https://dashscope.aliyuncs.com/compatible-mode/v1" qwen_model: str = "qwen-max" qwen_max_tokens: int = 4096 qwen_temperature: float = 0.1 qwen_local_base_url: str = "http://localhost:8000/v1" qwen_local_model: str = "Qwen3-35B-A3B" embedding_model: str = "BAAI/bge-m3" embedding_dim: int = 1024 embedding_device: str = "cpu" reranker_model: str = "BAAI/bge-reranker-v2-m3" wechat_appid: str = "" wechat_secret: str = "" rate_limit_per_minute: int = 60 rate_limit_per_hour: int = 1000 log_level: str = "INFO" log_file: str = "logs/app.log" @property def database_url(self) -> str: return ( f"postgresql+asyncpg://{self.postgres_user}:{self.postgres_password}" f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}" ) @property def database_url_sync(self) -> str: return ( f"postgresql://{self.postgres_user}:{self.postgres_password}" f"@{self.postgres_host}:{self.postgres_port}/{self.postgres_db}" ) model_config = {"env_file": _find_env_file(), "case_sensitive": False, "extra": "ignore"} @lru_cache def get_settings() -> Settings: return Settings()