Files
ai-shiliu/app/configs/runtime_config.py
figmar 81115dc23d 初始提交:识流 AI 助手项目
微信自动回复机器人,基于截图+OCR识别消息,支持关键词规则和 AI(OpenAI/DeepSeek/Dify)自动回复。
技术栈:PySide6 + Flask + Vue3 + RapidOCR + SQLite

注:OCR大模型文件(.onnx / .pdiparams)不纳入版本控制,需单独下载。

🤖 Generated with [Qoder][https://qoder.com]
2026-05-30 15:09:40 +08:00

188 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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