#!/usr/bin/env python # -*- coding: utf-8 -*- """微信自动回复接管脚本 v2(wechatauto-replica) 功能:监听微信新消息,当【真实好友】发来私聊消息时,自动回复。 规则: - 只回复 wxid_ 开头的真实好友(公众号 gh_、群聊 @chatroom、 文件传输助手 filehelper、特殊号 @openim/@placeholder/brandsessionholder 一律不碰) - 跳过自己发出去的消息(sender_id == 2) - 同一好友 COOLDOWN_SEC 秒内只回一次(防刷屏) - GUI 发送全局串行(多个好友同时来消息不会抢窗口) 用法(项目目录下,独立 venv): .venv\\Scripts\\python.exe wechat_daemon.py 前置:微信 4.x 已登录、桌面未锁屏、管理员权限(提密钥)。 """ import sys import os import time import threading try: os.system("chcp 65001 >nul 2>&1") except Exception: pass try: sys.stdout.reconfigure(encoding="utf-8", errors="replace") except AttributeError: pass from wechatauto.db import WeChatDB, Listener from wechatauto.guia import WeChatGUI # ==================== 自动回复配置(改这里) ==================== AUTO_REPLY = True # 总开关 DEFAULT_REPLY = "【自动回复】已收到您的消息,稍后回复您。" # 关键词规则:消息命中关键词时用对应话术回复;未命中则用 DEFAULT_REPLY KEYWORD_RULES = { # "你好": "你好呀,请问有什么可以帮您?", # "价格": "具体价格您可以看下我发给您的报价单。", } # 只回复这些前缀的会话(真实好友)。留空 = 不限制前缀 REPLY_ONLY_PREFIX = ("wxid_",) # 防抖:同一会话内多少秒内不重复自动回复 COOLDOWN_SEC = 30 # 黑名单会话(精确匹配 username,绝不自动回复) BLOCKLIST = {"filehelper"} # ============================================================== _gui = None _gui_lock = threading.Lock() _last_reply = {} # username -> 上次回复时间戳 _send_lock = threading.Lock() def get_gui(): global _gui with _gui_lock: if _gui is None: _gui = WeChatGUI() return _gui def should_reply(username: str) -> bool: """是否对某会话启用自动回复。""" if not AUTO_REPLY: return False if username in BLOCKLIST: return False if username.endswith("@chatroom"): return False if not REPLY_ONLY_PREFIX: return True return username.startswith(REPLY_ONLY_PREFIX) def pick_reply(content: str) -> str: for kw, reply in KEYWORD_RULES.items(): if kw in content: return reply return DEFAULT_REPLY def on_message(msg: dict, lst: Listener): username = msg.get("username", "") sender_id = msg.get("sender_id", "") content = str(msg.get("content", "")) # 跳过自己发出去的消息(避免回复自己的回复 → 死循环) if str(sender_id) == "2": return if not should_reply(username): return # 防抖 now = time.time() last = _last_reply.get(username, 0) if now - last < COOLDOWN_SEC: return _last_reply[username] = now reply = pick_reply(content) nick = _last_reply.get("_db") and _last_reply["_db"].get_nickname(username) or username # 全局串行发送,避免多个会话并发抢同一微信窗口 with _send_lock: try: r = get_gui().send_msg(reply, who=username, verify=True) print(f"[自动回复] {username} ({nick}) <- {reply} | ok={r.is_success} {r['message']}", flush=True) except Exception as e: # noqa: BLE001 print(f"[自动回复失败] {username}: {e!r}", flush=True) def main(): db = WeChatDB() info = db.get_self_info() nick = info.get("nick_name") or info.get("username") _last_reply["_db"] = db print(f"已接管微信: {nick} ({info.get('username')})", flush=True) print(f"自动回复: {'开' if AUTO_REPLY else '关'} | 默认话术: {DEFAULT_REPLY} | " f"只回前缀: {REPLY_ONLY_PREFIX} | 防抖 {COOLDOWN_SEC}s", flush=True) lst = Listener(db, interval=1.0) # add_all:监听所有已有会话 + 自动发现新会话 lst.add_all(on_message) print("自动回复监听已启动(真实好友发消息即自动回复,公众号/群聊不碰),Ctrl+C 退出...", flush=True) lst.start() try: while True: time.sleep(1) except KeyboardInterrupt: pass finally: lst.stop() print("已停止监听。", flush=True) if __name__ == "__main__": main()