diff --git a/WeiXin/Screenshots/T6_debug_view.jpg b/WeiXin/Screenshots/T6_debug_view.jpg deleted file mode 100644 index add8743..0000000 Binary files a/WeiXin/Screenshots/T6_debug_view.jpg and /dev/null differ diff --git a/WeiXin/Screenshots/t4_temp_history_check.jpg b/WeiXin/Screenshots/t4_temp_history_check.jpg deleted file mode 100644 index 95b3dfc..0000000 Binary files a/WeiXin/Screenshots/t4_temp_history_check.jpg and /dev/null differ diff --git a/WeiXin/Screenshots/t6_live_shot.jpg b/WeiXin/Screenshots/t6_live_shot.jpg deleted file mode 100644 index a7cf5e8..0000000 Binary files a/WeiXin/Screenshots/t6_live_shot.jpg and /dev/null differ diff --git a/WeiXin/Screenshots/temp_menu_shot.jpg b/WeiXin/Screenshots/temp_menu_shot.jpg deleted file mode 100644 index 4f2f787..0000000 Binary files a/WeiXin/Screenshots/temp_menu_shot.jpg and /dev/null differ diff --git a/WeiXin/T1_OpenChat.py b/WeiXin/T1_OpenChat.py index 0c63174..eed01c6 100644 --- a/WeiXin/T1_OpenChat.py +++ b/WeiXin/T1_OpenChat.py @@ -12,7 +12,7 @@ if project_root not in sys.path: sys.path.append(project_root) # 配置日志 -log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs") +log_dir = WxUtil.LOG_DIR if not os.path.exists(log_dir): os.makedirs(log_dir) @@ -27,6 +27,9 @@ logging.basicConfig( logger = logging.getLogger("T1_OpenChat") def open_chat(target_name="糖豆爸爸"): + # 运行前清理 Logs 和 Output + WxUtil.setup_script_environment() + logger.info(f"开始执行 T1: 打开微信并进入 '{target_name}' 的对话框...") # 连接设备 diff --git a/WeiXin/T2_GetHistory.py b/WeiXin/T2_GetHistory.py index a3e4da0..dde5acd 100644 --- a/WeiXin/T2_GetHistory.py +++ b/WeiXin/T2_GetHistory.py @@ -13,7 +13,7 @@ from WeiXin import WxUtil from WeiXin.WxUtil import analyze_chat_image # 配置日志 -log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs") +log_dir = WxUtil.LOG_DIR if not os.path.exists(log_dir): os.makedirs(log_dir) @@ -28,6 +28,9 @@ logging.basicConfig( logger = logging.getLogger("T2_GetHistory") async def get_history(target_name="对方"): + # 运行前清理 Logs 和 Output + WxUtil.setup_script_environment() + logger.info("开始执行 T2: 获取当前屏幕对话历史...") d = WxUtil.connect_device() @@ -35,7 +38,7 @@ async def get_history(target_name="对方"): return # 截图 - screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots") + screenshot_dir = WxUtil.OUTPUT_DIR if not os.path.exists(screenshot_dir): os.makedirs(screenshot_dir) diff --git a/WeiXin/T3_InputLlmText.py b/WeiXin/T3_InputLlmText.py index 1c15863..b831944 100644 --- a/WeiXin/T3_InputLlmText.py +++ b/WeiXin/T3_InputLlmText.py @@ -15,7 +15,7 @@ from WeiXin.WxUtil import find_input_box_center, perform_input_action, analyze_c from Util.LlmUtil import get_llm_response # 配置日志 -log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs") +log_dir = WxUtil.LOG_DIR if not os.path.exists(log_dir): os.makedirs(log_dir) @@ -30,10 +30,10 @@ logging.basicConfig( logger = logging.getLogger("T3_InputLlmText") async def generate_and_input(): - logger.info("开始执行 T3: 生成 LLM 回复并输入...") + # 运行前清理 Logs 和 Output + WxUtil.setup_script_environment() - # 0. 清除旧截图 - clean_screenshots_dir() + logger.info("开始执行 T3: 生成 LLM 回复并输入...") try: # 1. 连接设备 @@ -42,9 +42,7 @@ async def generate_and_input(): return # 2. 截图并识别对话历史 - screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots") - if not os.path.exists(screenshot_dir): - os.makedirs(screenshot_dir) + screenshot_dir = WxUtil.OUTPUT_DIR tmp_shot = os.path.join(screenshot_dir, "t4_temp_history_check.jpg") analyzed_shot = os.path.join(screenshot_dir, "t4_temp_history_analyzed.jpg") diff --git a/WeiXin/T4_CV_Voice_Debug.py b/WeiXin/T4_CV_Voice_Debug.py index 3218c66..ebe565b 100644 --- a/WeiXin/T4_CV_Voice_Debug.py +++ b/WeiXin/T4_CV_Voice_Debug.py @@ -3,98 +3,116 @@ import os import sys import time -import cv2 - -# 添加项目根目录到 sys.path -project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -if project_root not in sys.path: - sys.path.append(project_root) - -from WeiXin import WxUtil -from WeiXin.WxUtil import find_all_template_matches - - -def run_cv_debug(): - # 1. 拍照 (获取当前设备屏幕) - print("📸 正在连接设备并截取屏幕...") - d = WxUtil.connect_device() - if not d: - return - - try: - screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots") - if not os.path.exists(screenshot_dir): - os.makedirs(screenshot_dir) - - image_path = os.path.join(screenshot_dir, "t4_live_shot.jpg") - output_path = os.path.join(screenshot_dir, "T4_debug_view.jpg") - - d.screenshot(image_path) - print(f"✅ 截图已保存: {image_path}") - except Exception as e: - print(f"❌ 拍照失败: {e}") - return - - print(f"🔍 正在分析实时图片...") - - # 模板路径 - audio_template = r"d:\dsWork\aiData\WeiXin\Templates\audio.jpg" - red_point_template = r"d:\dsWork\aiData\WeiXin\Templates\red_point.jpg" - - if not os.path.exists(audio_template) or not os.path.exists(red_point_template): - print("错误: 模板文件不存在") - return - - # 2. 识别逻辑 - audio_matches = find_all_template_matches(image_path, audio_template, threshold=0.8) - red_points = find_all_template_matches(image_path, red_point_template, threshold=0.8) - - print(f"发现语音图标数量: {len(audio_matches)}") - print(f"发现红点数量: {len(red_points)}") - - # 3. 读取图片并绘制 - img = cv2.imread(image_path) - if img is None: - print("错误: 无法读取图片") - return - - for ax, ay in audio_matches: - # 排除顶部标题栏和底部输入区 (假设 300-1800 为有效区) - if ay < 300 or ay > 1800: - continue - - sender = "对方" if ax < 500 else "我" - - # --- 1. 先判断是否未读 (寻找附近的红点) --- - is_unread = False - for rx, ry in red_points: - if abs(ry - ay) < 50 and rx > ax: - is_unread = True - break - - # --- 2. 根据状态选择颜色 --- - # BGR 格式: 红色 (0, 0, 255), 绿色 (0, 255, 0) - color = (0, 0, 255) if is_unread else (0, 255, 0) - status_text = "未读" if is_unread else "已读" - - # --- 3. 绘制标注 --- - # 语音图标框 (加粗) - cv2.rectangle(img, (int(ax-35), int(ay-35)), (int(ax+35), int(ay+35)), color, 3) - - # 中心点击位置 (实心圆) - cv2.circle(img, (int(ax), int(ay)), 15, color, -1) - - # 如果是未读,把原本识别到的红点也再次标出 - if is_unread: - for rx, ry in red_points: - if abs(ry - ay) < 50 and rx > ax: - cv2.circle(img, (int(rx), int(ry)), 12, (0, 0, 255), -1) - - print(f"标注语音消息: ({ax}, {ay}), 发送者: {sender}, 状态: {status_text}") - - # 保存结果 - cv2.imwrite(output_path, img) - print(f"✅ 调试图片已保存至: {output_path}") +import cv2 +import logging + +# 添加项目根目录到 sys.path +project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if project_root not in sys.path: + sys.path.append(project_root) + +from WeiXin import WxUtil +from WeiXin.WxUtil import find_all_template_matches + +# 配置日志 +log_dir = WxUtil.LOG_DIR +if not os.path.exists(log_dir): + os.makedirs(log_dir) + +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.FileHandler(os.path.join(log_dir, "T4_CV_Voice_Debug.log"), encoding='utf-8'), + logging.StreamHandler() + ] +) +logger = logging.getLogger("T4_CV_Voice_Debug") + + +def run_cv_debug(): + # 运行前清理 Logs 和 Output + WxUtil.setup_script_environment() + + # 1. 拍照 (获取当前设备屏幕) + logger.info("📸 正在连接设备并截取屏幕...") + d = WxUtil.connect_device() + if not d: + return + + try: + screenshot_dir = WxUtil.OUTPUT_DIR + + image_path = os.path.join(screenshot_dir, "t4_live_shot.jpg") + output_path = os.path.join(screenshot_dir, "T4_debug_view.jpg") + + d.screenshot(image_path) + logger.info(f"✅ 截图已保存: {image_path}") + except Exception as e: + logger.error(f"❌ 拍照失败: {e}") + return + + logger.info(f"🔍 正在分析实时图片...") + + # 模板路径 + template_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Templates") + audio_template = os.path.join(template_dir, "audio.jpg") + red_point_template = os.path.join(template_dir, "red_point.jpg") + + if not os.path.exists(audio_template) or not os.path.exists(red_point_template): + logger.error("错误: 模板文件不存在") + return + + # 2. 识别逻辑 + audio_matches = find_all_template_matches(image_path, audio_template, threshold=0.8) + red_points = find_all_template_matches(image_path, red_point_template, threshold=0.8) + + logger.info(f"发现语音图标数量: {len(audio_matches)}") + logger.info(f"发现红点数量: {len(red_points)}") + + # 3. 读取图片并绘制 + img = cv2.imread(image_path) + if img is None: + logger.error("错误: 无法读取图片") + return + + for ax, ay in audio_matches: + # 排除顶部标题栏和底部输入区 (假设 300-1800 为有效区) + if ay < 300 or ay > 1800: + continue + + sender = "对方" if ax < 500 else "我" + + # --- 1. 先判断是否未读 (寻找附近的红点) --- + is_unread = False + for rx, ry in red_points: + if abs(ry - ay) < 50 and rx > ax: + is_unread = True + break + + # --- 2. 根据状态选择颜色 --- + # BGR 格式: 红色 (0, 0, 255), 绿色 (0, 255, 0) + color = (0, 0, 255) if is_unread else (0, 255, 0) + status_text = "未读" if is_unread else "已读" + + # --- 3. 绘制标注 --- + # 语音图标框 (加粗) + cv2.rectangle(img, (int(ax-35), int(ay-35)), (int(ax+35), int(ay+35)), color, 3) + + # 中心点击位置 (实心圆) + cv2.circle(img, (int(ax), int(ay)), 15, color, -1) + + # 如果是未读,把原本识别到的红点也再次标出 + if is_unread: + for rx, ry in red_points: + if abs(ry - ay) < 50 and rx > ax: + cv2.circle(img, (int(rx), int(ry)), 12, (0, 0, 255), -1) + + logger.info(f"标注语音消息: ({ax}, {ay}), 发送者: {sender}, 状态: {status_text}") + + # 保存结果 + cv2.imwrite(output_path, img) + logger.info(f"✅ 调试图片已保存至: {output_path}") if __name__ == "__main__": run_cv_debug() diff --git a/WeiXin/T5_AutoChatMonitor.py b/WeiXin/T5_AutoChatMonitor.py index a43ba5c..9027a43 100644 --- a/WeiXin/T5_AutoChatMonitor.py +++ b/WeiXin/T5_AutoChatMonitor.py @@ -19,12 +19,12 @@ from Util.LlmUtil import get_llm_response from Util.EasyOcrKit import EasyOcrKit # 配置日志 -log_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Logs") +log_dir = WxUtil.LOG_DIR if not os.path.exists(log_dir): os.makedirs(log_dir) # 设置 logger -logger = logging.getLogger("T6_AutoChatMonitor") +logger = logging.getLogger("T5_AutoChatMonitor") logger.setLevel(logging.INFO) # 清除现有的 handlers,防止重复打印或配置冲突 @@ -32,7 +32,7 @@ if logger.hasHandlers(): logger.handlers.clear() # 创建 FileHandler -log_file_path = os.path.join(log_dir, "T6_AutoChatMonitor.log") +log_file_path = os.path.join(log_dir, "T5_AutoChatMonitor.log") file_handler = logging.FileHandler(log_file_path, encoding='utf-8', mode='w') file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(file_handler) @@ -50,17 +50,19 @@ logger.info(f"日志文件路径: {log_file_path}") # 配置参数 CHECK_INTERVAL = 5 # 检查频率 (秒) +TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Templates") class ChatBot: def __init__(self): + # 运行前清理 Logs 和 Output + WxUtil.setup_script_environment() + self.d = WxUtil.connect_device() if not self.d: raise Exception("无法连接到设备,任务终止") self.last_message_text = "" - self.last_processed_msg = None # 记录上一条已处理/回复过的对方消息内容 - self.screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots") - if not os.path.exists(self.screenshot_dir): - os.makedirs(self.screenshot_dir) + self.last_processed_msg_id = None # 记录上一条已处理的消息标识 (文本+坐标) + self.screenshot_dir = WxUtil.OUTPUT_DIR self.ocr_kit = EasyOcrKit(gpu=True) @@ -121,7 +123,7 @@ class ChatBot: logger.info(f"📸 截取菜单图: {menu_shot_path}") self.d.screenshot(menu_shot_path) - convert_template = r"d:\dsWork\aiData\WeiXin\Templates\zhun_wen_zi.jpg" + convert_template = os.path.join(TEMPLATE_DIR, "zhun_wen_zi.jpg") logger.info(f"🔍 寻找模板: {convert_template}") convert_btn = find_template_match(menu_shot_path, convert_template, threshold=0.6) @@ -234,7 +236,7 @@ class ChatBot: menu_shot_path_cancel = os.path.join(self.screenshot_dir, "t6_menu_shot_cancel.jpg") self.d.screenshot(menu_shot_path_cancel) - cancel_template = r"d:\dsWork\aiData\WeiXin\Templates\cancel_zhuan_wen_zi.jpg" + cancel_template = os.path.join(TEMPLATE_DIR, "cancel_zhuan_wen_zi.jpg") cancel_btn = find_template_match(menu_shot_path_cancel, cancel_template, threshold=0.6) if cancel_btn: @@ -249,9 +251,6 @@ class ChatBot: async def run(self): logger.info("🚀 大张老师自动巡课系统启动...") - # 0. 清除旧截图 - clean_screenshots_dir() - last_screen_md5 = None while True: @@ -279,8 +278,8 @@ class ChatBot: logger.info("�️ 正在进行本地视觉扫描...") # A. 寻找语音图标 (audio.jpg) 和 红点 (red_point.jpg) - audio_template = r"d:\dsWork\aiData\WeiXin\Templates\audio.jpg" - red_point_template = r"d:\dsWork\aiData\WeiXin\Templates\red_point.jpg" + audio_template = os.path.join(TEMPLATE_DIR, "audio.jpg") + red_point_template = os.path.join(TEMPLATE_DIR, "red_point.jpg") audio_matches = find_all_template_matches(tmp_shot, audio_template, threshold=0.8) red_points = find_all_template_matches(tmp_shot, red_point_template, threshold=0.8) @@ -353,7 +352,8 @@ class ChatBot: "y": ay, "text": f"{sender}: [语音] {duration_text}", "is_voice": True, - "id": f"voice_{ax}_{ay}" + "id": f"voice_{ax}_{ay}", + "v_msg": v_msg }) # 处理剩余的 OCR 文字块 (普通文本) @@ -391,7 +391,7 @@ class ChatBot: logger.info(f"🎨 已保存视觉调试图: {debug_shot_path}") # C. 寻找输入框 (CV 模板匹配) - input_template = r"d:\dsWork\aiData\WeiXin\Templates\input_box.jpg" # 假设有这个模板 + input_template = os.path.join(TEMPLATE_DIR, "input_box.jpg") # 假设有这个模板 input_center = find_template_match(tmp_shot, input_template, threshold=0.6) if not input_center: # 几何兜底:屏幕底部 88% 处 @@ -401,81 +401,65 @@ class ChatBot: input_center = [w // 2, int(h * 0.88)] logger.info(f"� 使用几何兜底输入框坐标: {input_center}") - # 4. 语音处理逻辑 - processed_voice_content = None + # 4. & 5. 统一处理最后一条消息逻辑 (只看最后一条) + should_reply = False input_y = input_center[1] if input_center else None - # 只有未读的才处理 - for v_msg in voice_messages: - if v_msg.get("is_unread") or self.is_first_run: - logger.info(f"🔴 发现未读/待处理语音: {v_msg['content']}") - # 找到 OCR 结果中的下一条作为边界 - idx = -1 - # 这里简化逻辑,直接处理 - text = await self.process_single_voice(v_msg, None, input_y) - if text: - # 更新 log 中的内容 - for item in dialogue_log: - if item.get("is_voice") and f"[语音] {v_msg['content']}" in item["text"]: - item["text"] = item["text"].replace("[语音]", f"[语音转文字: {text}]") - break - - self.is_first_run = False - - # 5. LLM 回复逻辑 - final_dialogue_texts = [item['text'] for item in dialogue_log] - history_text = "\n".join(final_dialogue_texts) - - # 判断是否需要回复: - # 核心规则:只有当最后一条消息是“对方”说的,且内容未处理过,才回复。 - - should_reply = False - current_last_content = "" - if dialogue_log: last_item = dialogue_log[-1] - last_log = last_item["text"] + last_text = last_item["text"] + # 构造唯一标识符:文本内容 + 坐标 (Y坐标取整到10像素以容纳轻微位移) + current_msg_id = f"{last_text}_{int(last_item['y']/10)*10}" - # 检查最后一条消息的发送者 - if last_log.startswith("对方"): - parts = last_log.split(":", 1) - if len(parts) > 1: - current_last_content = parts[1].strip() - else: - current_last_content = last_log - - if current_last_content != self.last_processed_msg: - logger.info(f"💡 发现新消息,准备回复。内容: {current_last_content}") - should_reply = True - else: - # logger.info(f"⚪ 消息已回复过,跳过: {current_last_content}") - should_reply = False + # 核心规则:只有当最后一条消息是“对方”说的,且内容未处理过,才回复。 + if last_text.startswith("对方"): + if current_msg_id != self.last_processed_msg_id: + logger.info(f"💡 发现新消息: {last_text}") + + # 如果是语音,且需要回复,则先转换 + if last_item.get("is_voice"): + v_msg = last_item.get("v_msg") + if v_msg: + logger.info(f"🎤 最后一条是语音,开始转换: {v_msg['content']}") + converted_text = await self.process_single_voice(v_msg, None, input_y) + if converted_text: + # 更新文本内容以便 LLM 理解 + last_item["text"] = f"对方: [语音转文字: {converted_text}]" + logger.info(f"✅ 语音转换成功: {converted_text}") + else: + logger.warning("⚠️ 语音转换未提取到文字,将尝试直接回复或跳过。") + + should_reply = True + else: + # 消息已处理过 + should_reply = False else: - # logger.info(f"⚪ 最后一条消息是我发送的,无需回复。") - should_reply = False - # 如果最后一条是我发的,重置 last_processed_msg - self.last_processed_msg = None - + # 最后一条是我发送的,或者是系统消息 + should_reply = False + # 记录一下,避免在没有新消息时重复进入逻辑 + if current_msg_id != self.last_processed_msg_id: + self.last_processed_msg_id = current_msg_id + logger.info(f"⚪ 最后一条消息非对方发送,无需回复: {last_text}") + if should_reply: logger.info("🤖 准备调用 LLM 生成回复...") - # 立即更新状态,防止在回复生成期间(如果耗时)重复触发 - self.last_processed_msg = current_last_content + # 立即更新状态,防止在回复生成期间重复触发 + self.last_processed_msg_id = current_msg_id + + # 构建完整历史用于上下文 + final_dialogue_texts = [item['text'] for item in dialogue_log] + history_text = "\n".join(final_dialogue_texts) reply = await self.get_reply(history_text) if reply: logger.info(f"💡 LLM 回复: {reply}") - if input_center: - # 输入并发送 perform_input_action(self.d, input_center, reply) - # 发送后,为了防止下一轮 OCR 识别到自己的回复片段并误判为对方消息 - # 我们把 last_processed_msg 设置为一个特殊的占位符,直到下一次真正识别到对方的新消息 - # 或者更简单:在下一轮循环开始前稍微多等一下,让消息气泡完全显示 - time.sleep(1) - # 将最后处理的消息内容标记为已处理,防止 LLM 回复逻辑在下一轮立即触发 - # 注意:这里的 current_last_content 是对方的最后一条 + time.sleep(1) # 等待发送完成 else: logger.warning("⚠️ LLM 未生成有效回复。") + + self.is_first_run = False # 休眠 await asyncio.sleep(CHECK_INTERVAL) diff --git a/WeiXin/WxUtil.py b/WeiXin/WxUtil.py index 645e5c0..dba0de1 100644 --- a/WeiXin/WxUtil.py +++ b/WeiXin/WxUtil.py @@ -25,6 +25,35 @@ ocr_kit = EasyOcrKit() logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger("WxUtil") +# 目录配置 +BASE_DATA_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +LOG_DIR = os.path.join(BASE_DATA_DIR, "Logs") +OUTPUT_DIR = os.path.join(BASE_DATA_DIR, "Output") +TEMPLATE_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Templates") + +def clear_directory(dir_path): + """清理指定目录下的所有文件""" + if not os.path.exists(dir_path): + os.makedirs(dir_path) + return + + import shutil + for filename in os.listdir(dir_path): + file_path = os.path.join(dir_path, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + except Exception as e: + logger.warning(f"Failed to delete {file_path}. Reason: {e}") + +def setup_script_environment(): + """运行前清理日志和输出目录""" + logger.info("清理运行环境: Logs 和 Output 目录...") + clear_directory(LOG_DIR) + clear_directory(OUTPUT_DIR) + def connect_device(): """ 连接设备并返回设备对象,同时打印详细的设备信息 @@ -328,15 +357,14 @@ async def analyze_chat_image(image_path, output_path, device=None, target_name=" def clean_screenshots_dir(): """清理截图目录""" - screenshot_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "Screenshots") - if not os.path.exists(screenshot_dir): - os.makedirs(screenshot_dir) + if not os.path.exists(OUTPUT_DIR): + os.makedirs(OUTPUT_DIR) return - for f in os.listdir(screenshot_dir): + for f in os.listdir(OUTPUT_DIR): if f.lower().endswith(('.jpg', '.png', '.jpeg')): try: - os.remove(os.path.join(screenshot_dir, f)) + os.remove(os.path.join(OUTPUT_DIR, f)) except Exception as e: logger.warning(f"Failed to delete {f}: {e}") @@ -475,11 +503,11 @@ def perform_input_action(d, center_point, text, auto_send=True): try: # --- 新增逻辑:确保处于文字输入模式 --- logger.info("正在检查输入模式...") - tmp_check_shot = os.path.join(os.path.dirname(os.path.abspath(__file__)), "temp_input_check.jpg") + tmp_check_shot = os.path.join(OUTPUT_DIR, "temp_input_check.jpg") d.screenshot(tmp_check_shot) - wen_zi_template = r"d:\dsWork\aiData\WeiXin\Templates\wen_zi_input.jpg" - input_text_template = r"d:\dsWork\aiData\WeiXin\Templates\input_text.jpg" + wen_zi_template = os.path.join(TEMPLATE_DIR, "wen_zi_input.jpg") + input_text_template = os.path.join(TEMPLATE_DIR, "input_text.jpg") # 1. 检查是否存在 '切换到文字' 图标 (表示当前是语音模式) # 注意:这里假设 wen_zi_input.jpg 是那个“键盘”图标 @@ -548,8 +576,8 @@ def perform_input_action(d, center_point, text, auto_send=True): tmp_screen = os.path.join(os.path.dirname(os.path.abspath(__file__)), "temp_send_check.jpg") d.screenshot(tmp_screen) - # 使用绝对路径 - template_path = r"d:\dsWork\aiData\WeiXin\Templates\send.jpg" + # 使用相对路径 + template_path = os.path.join(TEMPLATE_DIR, "send.jpg") send_btn_pos = find_template_match(tmp_screen, template_path, threshold=0.7) # 稍微降低阈值以提高召回 if send_btn_pos: diff --git a/WeiXin/__pycache__/WxUtil.cpython-310.pyc b/WeiXin/__pycache__/WxUtil.cpython-310.pyc index f5a9f12..fea7f1f 100644 Binary files a/WeiXin/__pycache__/WxUtil.cpython-310.pyc and b/WeiXin/__pycache__/WxUtil.cpython-310.pyc differ