import os from typing import Any DEFAULT_CONFIG: dict[str, Any] = { # 应用展示名称,同时作为 AppData 默认目录名的一部分 "APP_NAME": "AiShiliu", # Flask 后端监听地址 "APP_HOST": "127.0.0.1", # Flask 后端监听端口 "APP_PORT": 5000, # 应用默认时区 "APP_TIMEZONE": "Asia/Shanghai", # 已构建前端静态资源目录,留空时自动回退到项目默认目录 "FRONTEND_STATIC_DIR": "", # 日志总开关 "LOG_ENABLED": True, # 日志级别 "LOG_LEVEL": "INFO", # 是否写文本日志 "LOG_TEXT_ENABLED": True, # 是否写JSON日志 "LOG_JSON_ENABLED": True, # 单文件滚动大小(MB) "LOG_ROTATE_MB": 5, # 滚动保留份数 "LOG_BACKUP_COUNT": 7, # MySQL 主机地址(预留给后续鉴权等在线能力) "DB_HOST": "127.0.0.1", # MySQL 端口(预留) "DB_PORT": 3306, # MySQL 数据库名(预留) "DB_NAME": "ai_shiliu", # MySQL 用户名(预留) "DB_USER": "ai_shiliu", # MySQL 密码(预留) "DB_PASS": "", # MySQL 字符集(预留) "DB_CHARSET": "utf8mb4", # AI 提供方(openai/deepseek/dify) "AI_PROVIDER": "dify", # OpenAI 接口密钥 "OPENAI_API_KEY": "YOUR_OPENAI_API_KEY_HERE", # OpenAI API 基础地址 "OPENAI_API_BASE": "https://api.openai.com/v1", # OpenAI 默认模型 "OPENAI_MODEL": "gpt-4.1-mini", # DeepSeek 接口密钥 "DEEPSEEK_API_KEY": "", # DeepSeek API 基础地址 "DEEPSEEK_API_BASE": "https://api.deepseek.com", # DeepSeek 默认模型 "DEEPSEEK_MODEL": "deepseek-chat", # Dify 接口密钥 "DIFY_API_KEY": "app-a9dofsiQi4e157uDYTx8Lrja", # Dify API 基础地址 "DIFY_API_BASE": "http://47.92.48.126/v1", # Dify 用户标识 "DIFY_USER": "wechat_user", # 百度 OCR API Key "BAIDU_API_KEY": "ElIQN30iAqpEGi9zv0VlrtQX", # 百度 OCR Secret Key "BAIDU_SECRET_KEY": "7wrO2wDTx7FehuelgG0NCBDFOklnqSz0", # OCR 引擎(baidu/rapid) "OCR_PROVIDER": "rapid", # 微信机器人上报后端消息接口 "BACKEND_URL": "http://127.0.0.1:5000/api/messages/receive", # 轮询主循环间隔(秒) "BOT_LOOP_INTERVAL": 3, # 点击联系人后等待(秒) "BOT_CLICK_AFTER_DELAY": 1.2, # 切换会话后读取标题等待(秒) "BOT_TITLE_AFTER_DELAY": 1.0, # 联系人切换节流等待(秒) "BOT_CONTACT_SWITCH_DELAY": 1.0, # 主循环异常后的重试等待(秒) "BOT_LOOP_ERROR_DELAY": 3.0, # 微信窗口目标宽度 "WECHAT_WINDOW_TARGET_WIDTH": 1080, # 微信窗口目标高度 "WECHAT_WINDOW_TARGET_HEIGHT": 820, # 微信窗口目标左侧坐标 "WECHAT_WINDOW_TARGET_LEFT": 120, # 微信窗口目标顶部坐标 "WECHAT_WINDOW_TARGET_TOP": 80, # 是否保存 OCR 调试截图 "OCR_SAVE_IMAGES": True, # 联系人行高(用于定位) "CONTACT_ROW_HEIGHT": 64, # 联系人列宽(用于定位) "CONTACT_ROW_WIDTH": 240, # 联系人列表左偏移 "CONTACT_LIST_LEFT_OFFSET": 68, # 联系人列表上偏移 "CONTACT_LIST_TOP_OFFSET": 82, # 联系人列表下偏移 "CONTACT_LIST_BOTTOM_OFFSET": 0, # 会话名区域左偏移 "SESSION_NAME_LEFT_OFFSET": 48, # 会话名区域上偏移 "SESSION_NAME_TOP_OFFSET": 8, # 会话名区域宽度 "SESSION_NAME_WIDTH": 140, # 会话名区域高度 "SESSION_NAME_HEIGHT": 24, # 会话名 OCR 放大倍数 "SESSION_NAME_OCR_SCALE": 4, # 会话名 OCR 额外放大倍数 "SESSION_NAME_OCR_EXTRA_SCALE": 6, # 聊天区截图左偏移 "CHAT_CAPTURE_LEFT_OFFSET": 310, # 聊天区截图上偏移 "CHAT_CAPTURE_TOP_OFFSET": 70, # 聊天区截图宽度 "CHAT_CAPTURE_WIDTH": 750, # 聊天区截图高度 "CHAT_CAPTURE_HEIGHT": 550, # 顶部惩罚权重比例 "OCR_TOP_PENALTY_RATIO": 0.18, # 顶部惩罚二值化系数 "OCR_TOP_PENALTY_BIN_FACTOR": 2.0, # 顶部惩罚颜色系数 "OCR_TOP_PENALTY_COLOR_FACTOR": 2.2, # 标题 OCR 区域左偏移(保留较大的方案) "TITLE_OCR_AREA_LEFT_OFFSET": 310, # 标题 OCR 区域上偏移(保留较大的方案) "TITLE_OCR_AREA_TOP_OFFSET": 0, # 标题 OCR 区域宽度(保留较大的方案) "TITLE_OCR_AREA_WIDTH": 600, # 标题 OCR 区域高度(保留较大的方案) "TITLE_OCR_AREA_HEIGHT": 70, } def _raw_value(key: str) -> Any: env_value = os.getenv(key) if env_value is not None: return env_value return DEFAULT_CONFIG.get(key) def get_str(key: str, default: str = "") -> str: value = _raw_value(key) if value is None: return default return str(value) def get_int(key: str, default: int = 0) -> int: value = _raw_value(key) if value is None or value == "": return default return int(value) def get_float(key: str, default: float = 0.0) -> float: value = _raw_value(key) if value is None or value == "": return default return float(value) def get_bool(key: str, default: bool = False) -> bool: value = _raw_value(key) if value is None: return default if isinstance(value, bool): return value normalized = str(value).strip().lower() if normalized in {"1", "true", "yes", "on"}: return True if normalized in {"0", "false", "no", "off"}: return False return default