feat: 微信自动化客服(wechatauto-replica) 干净历史导入 - AI 自动回复/语音收发/朋友圈发布

This commit is contained in:
2026-09-16 10:12:49 +08:00
commit c3b98f4c4e
69 changed files with 19828 additions and 0 deletions
+147
View File
@@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""微信自动回复接管脚本 v2wechatauto-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()