import os from pathlib import Path from app.configs.runtime_config import get_bool, get_float, get_int, get_str PROJECT_ROOT = Path(__file__).resolve().parents[4] def _local_appdata_root() -> Path: local_appdata = (os.getenv("LOCALAPPDATA") or "").strip() if local_appdata: return Path(local_appdata) return Path.home() / "AppData" / "Local" def _resolve_path(path_value: str, base_dir: Path) -> str: path = Path(path_value) if not path.is_absolute(): path = base_dir / path return str(path.resolve()) APP_NAME = (get_str("APP_NAME", "AiShiliu") or "AiShiliu").strip() or "AiShiliu" APP_DATA_DIR = _resolve_path( get_str("APP_DATA_DIR", "") or get_str("OPENCLAW_APP_DATA_DIR", "") or str(_local_appdata_root() / APP_NAME), PROJECT_ROOT, ) LOG_ROOT_DIR = _resolve_path(get_str("LOG_ROOT_DIR", os.path.join(APP_DATA_DIR, "logs")), PROJECT_ROOT) BACKEND_LOG_DIR = _resolve_path(get_str("BACKEND_LOG_DIR", os.path.join(LOG_ROOT_DIR, "backend")), PROJECT_ROOT) FRONTEND_LOG_DIR = _resolve_path(get_str("FRONTEND_LOG_DIR", os.path.join(LOG_ROOT_DIR, "frontend")), PROJECT_ROOT) BACKEND_PYTHON_LOG_FILE = _resolve_path( get_str("BACKEND_PYTHON_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "python", "backend.log")), PROJECT_ROOT, ) BOT_LOG_FILE = _resolve_path( get_str("BOT_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "bot", "bot.log")), PROJECT_ROOT, ) BOT_SESSION_LIST_LOG_FILE = _resolve_path( get_str("BOT_SESSION_LIST_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "bot", "session_list.log")), PROJECT_ROOT, ) BOT_SESSION_DETAIL_LOG_FILE = _resolve_path( get_str("BOT_SESSION_DETAIL_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "bot", "session_detail.log")), PROJECT_ROOT, ) OCR_LOG_FILE = _resolve_path( get_str("OCR_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "ocr", "ocr.log")), PROJECT_ROOT, ) OCR_BAIDU_LOG_FILE = _resolve_path( get_str("OCR_BAIDU_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "ocr", "baidu.log")), PROJECT_ROOT, ) OCR_RAPID_LOG_FILE = _resolve_path( get_str("OCR_RAPID_LOG_FILE", os.path.join(BACKEND_LOG_DIR, "ocr", "rapid.log")), PROJECT_ROOT, ) TAURI_LOG_FILE = _resolve_path( get_str("TAURI_LOG_FILE", os.path.join(FRONTEND_LOG_DIR, "tauri", "tauri.log")), PROJECT_ROOT, ) VUE_LOG_FILE = _resolve_path( get_str("VUE_LOG_FILE", os.path.join(FRONTEND_LOG_DIR, "vue", "vue.log")), PROJECT_ROOT, ) OCR_SAVE_DIR = _resolve_path(get_str("OCR_SAVE_DIR", os.path.join(BACKEND_LOG_DIR, "ocr_debug_images")), PROJECT_ROOT) BLOCKED_ROW_CACHE_FILE = _resolve_path( get_str("BLOCKED_ROW_CACHE_FILE", os.path.join(BACKEND_LOG_DIR, "state", "blocked_rows.json")), PROJECT_ROOT, ) BAIDU_API_KEY = get_str("BAIDU_API_KEY", "") BAIDU_SECRET_KEY = get_str("BAIDU_SECRET_KEY", "") OCR_PROVIDER = get_str("OCR_PROVIDER", "baidu").strip().lower() RAPID_OCR_DET_MODEL_PATH = get_str("RAPID_OCR_DET_MODEL_PATH", "app/resources/ocr_models/ch_PP-OCRv4_det.onnx").strip() RAPID_OCR_REC_MODEL_PATH = get_str("RAPID_OCR_REC_MODEL_PATH", "app/resources/ocr_models/ch_PP-OCRv4_rec.onnx").strip() RAPID_OCR_CLS_MODEL_PATH = get_str("RAPID_OCR_CLS_MODEL_PATH", "app/resources/ocr_models/ch_ppocr_mobile_v2.0_cls.onnx").strip() BACKEND_URL = get_str("BACKEND_URL", "http://127.0.0.1:5000/api/messages/receive") LOOP_INTERVAL = get_int("BOT_LOOP_INTERVAL", 3) CLICK_AFTER_DELAY = get_float("BOT_CLICK_AFTER_DELAY", 1.2) TITLE_AFTER_DELAY = get_float("BOT_TITLE_AFTER_DELAY", 1.0) CONTACT_SWITCH_DELAY = get_float("BOT_CONTACT_SWITCH_DELAY", 1.0) LOOP_ERROR_DELAY = get_float("BOT_LOOP_ERROR_DELAY", 3) WECHAT_WINDOW_TARGET_WIDTH = get_int("WECHAT_WINDOW_TARGET_WIDTH", 1080) WECHAT_WINDOW_TARGET_HEIGHT = get_int("WECHAT_WINDOW_TARGET_HEIGHT", 820) WECHAT_WINDOW_TARGET_LEFT = get_int("WECHAT_WINDOW_TARGET_LEFT", 120) WECHAT_WINDOW_TARGET_TOP = get_int("WECHAT_WINDOW_TARGET_TOP", 80) OCR_SAVE_IMAGES = get_bool("OCR_SAVE_IMAGES", True) CONTACT_ROW_HEIGHT = get_int("CONTACT_ROW_HEIGHT", 64) CONTACT_ROW_WIDTH = get_int("CONTACT_ROW_WIDTH", 240) CONTACT_LIST_LEFT_OFFSET = get_int("CONTACT_LIST_LEFT_OFFSET", 68) CONTACT_LIST_TOP_OFFSET = get_int("CONTACT_LIST_TOP_OFFSET", 82) CONTACT_LIST_BOTTOM_OFFSET = get_int("CONTACT_LIST_BOTTOM_OFFSET", 0) SESSION_NAME_LEFT_OFFSET = get_int("SESSION_NAME_LEFT_OFFSET", 56) SESSION_NAME_TOP_OFFSET = get_int("SESSION_NAME_TOP_OFFSET", 8) SESSION_NAME_WIDTH = get_int("SESSION_NAME_WIDTH", 134) SESSION_NAME_HEIGHT = get_int("SESSION_NAME_HEIGHT", 24) SESSION_NAME_OCR_SCALE = get_int("SESSION_NAME_OCR_SCALE", 4) SESSION_NAME_OCR_EXTRA_SCALE = get_int("SESSION_NAME_OCR_EXTRA_SCALE", 6) CHAT_CAPTURE_LEFT_OFFSET = get_int("CHAT_CAPTURE_LEFT_OFFSET", 310) CHAT_CAPTURE_TOP_OFFSET = get_int("CHAT_CAPTURE_TOP_OFFSET", 70) CHAT_CAPTURE_WIDTH = get_int("CHAT_CAPTURE_WIDTH", 750) CHAT_CAPTURE_HEIGHT = get_int("CHAT_CAPTURE_HEIGHT", 550) OCR_TOP_PENALTY_RATIO = get_float("OCR_TOP_PENALTY_RATIO", 0.18) OCR_TOP_PENALTY_BIN_FACTOR = get_float("OCR_TOP_PENALTY_BIN_FACTOR", 2.0) OCR_TOP_PENALTY_COLOR_FACTOR = get_float("OCR_TOP_PENALTY_COLOR_FACTOR", 2.2) TITLE_OCR_AREA_LEFT_OFFSET = get_int("TITLE_OCR_AREA_LEFT_OFFSET", 240) TITLE_OCR_AREA_TOP_OFFSET = get_int("TITLE_OCR_AREA_TOP_OFFSET", 4) TITLE_OCR_AREA_WIDTH = get_int("TITLE_OCR_AREA_WIDTH", 600) TITLE_OCR_AREA_HEIGHT = get_int("TITLE_OCR_AREA_HEIGHT", 64) NO_REPLY_KEYWORDS = [ "谢谢", "好的", "嗯", "哦", "ok", "收到", "[图片]", "[语音]", "[视频]", "[文件]" ] BLOCKED_SESSION_KEYWORDS = [ "服务号", "公众号", "微信公众平台", "文件传输助手" ] UI_NOISE_KEYWORDS = [ "微信", "Weixin", "WeChat", "聊天信息", "搜索", "更多", "表情", "发送", "Message", "Messages" ]