from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import field_validator class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") # 应用 debug: bool = False log_level: str = "INFO" # 数据库 database_url: str = "postgresql+asyncpg://gx-gp-notify:password@localhost:5432/gx-gp-notify" # 爬虫 crawler_base_url: str = "https://zfcg.gxzf.gov.cn" crawler_keywords: list[str] = ["大化"] crawler_max_pages: int = 10 crawler_timeout: int = 30 crawler_page_size: int = 100 # 企业微信 wechat_enabled: bool = True wechat_corp_id: str = "" wechat_agent_id: str = "" wechat_secret: str = "" wechat_token: str = "" wechat_encoding_aes_key: str = "" wechat_port: int = 18001 wechat_host: str = "0.0.0.0" wechat_api_base_url: str = "https://qyapi.weixin.qq.com" # 定时任务 scheduler_enabled: bool = True scheduler_cron: str = "0 8-21 * * *" # LogHive 日志系统 loghive_endpoint: str = "http://10.10.10.14:8000" loghive_project: str = "gx-gp-notify" loghive_api_key: str = "" # AI 分析 (DeepSeek) ai_enabled: bool = False ai_whitelist: str = "" ai_api_key: str = "" ai_base_url: str = "https://api.deepseek.com/v1" ai_model: str = "deepseek-chat" ai_timeout: int = 30 ai_analysis_title: str = "🔔 中国电信可承接项目" ai_prompt_template: str = ( "你是一个政府采购项目分析师,专门帮助中国电信识别可以承接的项目。\n\n" "可承接范围包括但不限于:\n" "- 通信工程、光缆建设、基站建设\n" "- 信息化系统建设、系统集成\n" "- 云计算、大数据、政务云\n" "- 物联网、智慧城市、智慧园区\n" "- 安防监控、视频会议、应急通信\n" "- 网络运维、网络优化、IDC 服务\n" "- 5G 应用、专线服务\n\n" "--- 公告信息 ---\n" "标题:{title}\n" "采购人:{purchase_name}\n" "公告类型:{announcement_type}\n\n" "--- 公告正文 ---\n" "{content}\n\n" "请用 JSON 格式回答:\n" '{{"is_relevant": true/false, "reason": "简要判断理由", "business_type": "业务分类"}}' ) @field_validator("ai_prompt_template", mode="before") @classmethod def convert_newlines(cls, v: str) -> str: """将 .env 中字面 \\n 转换为真实换行""" if isinstance(v, str) and "\\n" in v: return v.replace("\\n", "\n") return v # 公告来源(JSON 字符串,从环境变量读取) announcement_sources: str = '{"ZcyAnnouncement1":{"category_id":66485,"name":"采购公告","type":"purchase"},"ZcyAnnouncement2":{"category_id":66485,"name":"结果公告","type":"result"},"ZcyAnnouncement3":{"category_id":66485,"name":"合同公告","type":"contract"},"ZcyAnnouncement4":{"category_id":66485,"name":"更正公告","type":"correction"},"ZcyAnnouncement5":{"category_id":66485,"name":"招标文件预公示","type":"pre_announcement"},"ZcyAnnouncement6":{"category_id":66485,"name":"单一来源公示","type":"single_source"},"ZcyAnnouncement7":{"category_id":66485,"name":"电子卖场公示","type":"electronic_market"},"ZcyAnnouncement10":{"category_id":66485,"name":"履约验收公示","type":"acceptance"},"ZcyAnnouncement11":{"category_id":66485,"name":"工程类公告","type":"engineering"},"ZcyAnnouncement20":{"category_id":66485,"name":"框架协议征集公告","type":"framework_agreement"},"ZcyAnnouncement21":{"category_id":66485,"name":"框架协议入围结果公告","type":"framework_result"},"ZcyAnnouncement23":{"category_id":66485,"name":"框架协议成交结果汇总公告","type":"framework_summary"},"61-266648":{"category_id":66485,"name":"采购意向公开","type":"intention"}}' # noqa: E501 settings = Settings()