config.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. from __future__ import annotations
  2. from functools import lru_cache
  3. from pathlib import Path
  4. from urllib.parse import quote_plus
  5. from pydantic_settings import BaseSettings, SettingsConfigDict
  6. PROJECT_ROOT = Path(__file__).resolve().parents[2]
  7. class Settings(BaseSettings):
  8. model_config = SettingsConfigDict(
  9. env_file=PROJECT_ROOT / ".env",
  10. env_file_encoding="utf-8",
  11. case_sensitive=False,
  12. extra="ignore",
  13. )
  14. app_name: str = "矿山通防智能管控平台"
  15. app_env: str = "development"
  16. debug: bool = True
  17. api_v1_prefix: str = "/api/v1"
  18. secret_key: str = "change-me-in-production"
  19. host: str = "0.0.0.0"
  20. port: int = 8090
  21. log_level: str = "INFO"
  22. database_dialect: str = "sqlite"
  23. sqlite_path: str = "data/vent_platform.sqlite"
  24. mysql_host: str = "127.0.0.1"
  25. mysql_port: int = 3306
  26. mysql_user: str = "root"
  27. mysql_password: str = ""
  28. mysql_database: str = "vent_platform"
  29. database_echo: bool = False
  30. openai_api_key: str = ""
  31. openai_base_url: str = "https://api.deepseek.com"
  32. deepagent_model: str = "deepseek-flash"
  33. deepagent_thinking: str = "off"
  34. openai_timeout: int = 180
  35. mineru_api_base: str = "https://mineru.net"
  36. mineru_token: str = ""
  37. mineru_timeout: int = 900
  38. mineru_poll_interval: float = 2.0
  39. document_extraction_max_chars: int = 80000
  40. knowledge_service_base: str = ""
  41. knowledge_service_api_key: str = ""
  42. knowledge_service_timeout: float = 30.0
  43. knowledge_catalog_cache_ttl: int = 300
  44. knowledge_search_mode: str = "keyword"
  45. knowledge_search_top_k: int = 5
  46. knowledge_search_min_score: float = 0.0
  47. knowledge_search_min_match_ratio: float = 0.0
  48. knowledge_rag_context_max_chars: int = 12000
  49. knowledge_rag_source_max_chars: int = 2800
  50. cors_origins: str = (
  51. "http://127.0.0.1:5173,http://localhost:5173,"
  52. "http://127.0.0.1:8080,http://localhost:8080"
  53. )
  54. default_mine_code: str = "shangwan"
  55. upload_dir: str = "data/uploads"
  56. storage_capacity_gb: float = 1024.0
  57. seed_demo_data: bool = False
  58. request_trace_header: str = "X-Trace-Id"
  59. @property
  60. def cors_origin_list(self) -> list[str]:
  61. return [item.strip() for item in self.cors_origins.split(",") if item.strip()]
  62. @property
  63. def sqlite_file(self) -> Path:
  64. path = Path(self.sqlite_path)
  65. return path if path.is_absolute() else PROJECT_ROOT / path
  66. @property
  67. def database_url(self) -> str:
  68. dialect = self.database_dialect.strip().lower()
  69. if dialect == "sqlite":
  70. return f"sqlite:///{self.sqlite_file.as_posix()}"
  71. if dialect in {"mysql", "mysql+pymysql"}:
  72. user = quote_plus(self.mysql_user)
  73. password = quote_plus(self.mysql_password)
  74. return (
  75. f"mysql+pymysql://{user}:{password}@"
  76. f"{self.mysql_host}:{self.mysql_port}/{self.mysql_database}"
  77. "?charset=utf8mb4"
  78. )
  79. raise ValueError("DATABASE_DIALECT 仅支持 sqlite 或 mysql")
  80. @property
  81. def upload_path(self) -> Path:
  82. path = Path(self.upload_dir)
  83. return path if path.is_absolute() else PROJECT_ROOT / path
  84. @property
  85. def model_configured(self) -> bool:
  86. return bool(self.openai_api_key)
  87. @property
  88. def knowledge_service_configured(self) -> bool:
  89. return bool(self.knowledge_service_base.strip())
  90. @lru_cache(maxsize=1)
  91. def get_settings() -> Settings:
  92. return Settings()
  93. settings = get_settings()