使用文字识别构建的微信群聊天机器人

2023-11-01 09:10

本文主要是介绍使用文字识别构建的微信群聊天机器人,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 摘要
  • 实现思路
    • 实现代码
    • 遇到问题
      • pymouse报错缺少windows和win32api
      • module 'PIL.Image' has no attribute 'ANTIALIAS'
      • 获取openai api key
      • pip install CnOcr提示需要c++编译环境
    • 总结

摘要

本文实现了一种使用文字识别的方法来构建的微信群聊机器人,调用openai来实现智能聊天。众所周知,微信机器人的项目现在由于网页版微信被ban,大部分都已经不可用了。我的常用微信号和小号都无法登录网页版微信,于是寻找能够通过pc端来实现微信机器人的方法,找到诸如wechaty等项目。这些项目通过dll注入的方式调用微信客户端的内部方法来接受和发送消息。但可惜的是这些项目都是收费的,本身这就是个伪需求,只是做着玩的,要花钱就不太值当了。既然找不到现成的框架,那么试试自己能不能实现吧!本身我也没学过逆向,想要破解微信来实现dll注入对我来说太过困难。而且就算凭我的三脚猫功夫能实现需求,估计不超过一周就能被封号😥。只能想个更安全的方式了,就是使用模拟操作来直接操作微信客户端,当然这种方式实现的功能有着非常大的局限性,不过只是做着玩的话也勉强可以用。

实现思路

使用python来实现,有着强大的第三方库的支持,避免自己造轮子。

  1. 我们首先需要能够监听到群里发送的消息。使用pyautogui库的screenshot()方法对屏幕进行截图。
  2. 之后要从截图中获得最后一条消息框的位置,并对消息框进行截图。可知消息框的左边界是固定的位置(只要你不缩放微信界面)。那就从这条线最底下往上找rgb为(255,255,255)白色的坐标。就可以获得消息框左下角坐标。在从该坐标分别向上找和向右找白色的部分,就可以得到消息框的大小了。
    获得消息框3. 获得消息框的截图后,对其使用文字识别吧。一开始使用了tesseract来进行文字识别,但其中文的识别不出正确文字,不知到是我配置有问题吗?当把图片放大8倍的时候好歹能识别出几个字了😑。总之又换成了CnOcr来进行文字识别了,虽然有时候也识别错误,但也足够用了。
    识别图片
    识别文字
    4. 获得新消息后,调用openai的api来获得要回复的文本。在用pyperclipcopy()方法复制文字进剪切板,pyautogui来实现ctrl+v粘贴,alt+s发送消息。

实现代码

废话不多说了,这个代码是花了两天写的,仍有很多不足,但小心点使用还是可以的。

import pyautogui
from pynput.keyboard import Key, Controller
from pyperclip import copy,paste
from PIL import Image, ImageChops
import time
import io
from cnocr import CnOcr
from queue import Queue
import openai
import threading
import logging"""向队列中添加元素,并保持队列元素的个数。args:queue:队列limit:限制队列元素的个数item:要添加的元素
"""
def queue_limit_put(queue,limit,item):queue.put(item)if queue.qsize()>limit:queue.get()def send_msg_on_wechat(message,response):send_msg=message+"\n--------\n"+responsecopy(send_msg)pyautogui.hotkey('ctrl', 'v')pyautogui.hotkey('alt','s')class WeChatRobot:def __init__(self) -> None:self.snap_position=[300,60,980,825]#截图框的位置:left,top,length,heightself.dialog_left=340#消息框的左边界self.ocr=CnOcr()self.message_list=Queue()#新消息队列self.robot_name="%小马"#机器人的唤醒名字self.using_name=True#True时要带机器人名字的消息才会回复,False所有消息都回复self.snap_error_check=True"""对屏幕区域进行截图args:x,y:左上点的坐标m:长度n:高度"""def snap(self,x,y,m,n):try:im=pyautogui.screenshot(region=(x,y,m,n))self.snap_error_check=Trueexcept Exception as e:if self.snap_error_check:self.snap_error_check=False#防止发送太多的崩溃消息send_msg_on_wechat('我崩溃啦!','截图失败了!')return im#对比两张图片相似度def compare_image(self,screenshot1,screenshot2):image1=screenshot1image2=screenshot2diff=ImageChops.difference(image1,image2)diff_image = diff.convert('RGBA')diff_count = diff.getbbox()if diff_count is None:#与上一张截图相同return Falsesimilarity = 1 - ((diff_count[2]-diff_count[0]) * (diff_count[3]-diff_count[1])) / (image1.width * image1.height)if __debug__:print(f"相似度:{similarity}")if similarity>=0.95:#相似度大于0.95判定为相同,低于0.95判定为有新消息return Falsereturn True#寻找对话框的坐下点坐标def find_dialog_leftbott(self,im):x=80y=self.snap_position[3]-1while y>0:if im.getpixel((x,y))==(255,255,255):return (x,y)else:y=y-1return (-1,-1)#寻找对话框的长与高,(x,y)为左下点坐标def find_dialog_lenhei(self,im,x,y):right=xtop=ywhile right<self.snap_position[2]:if im.getpixel((right,y))!=(255,255,255):breakright=right+1while top>0:if im.getpixel((x,top))!=(255,255,255):breaktop=top-1if right==self.snap_position[2] or top==0:return (-1,-1)return (right-x,y-top)# def test_ai_reply(self):#     time.sleep(1)#     for i in range(2):#         self.message_list.put(f"你是谁")def run(self):privous_screenshot=Nonetime.sleep(5)#等我切换到微信页面while True:#对微信界面进行截图作为原始图im=self.snap(self.snap_position[0],self.snap_position[1],self.snap_position[2],self.snap_position[3])#寻找消息框并截图(dialog_x,dialog_y)=self.find_dialog_leftbott(im)if dialog_x==-1 or dialog_y==-1:logger.warning("查找对话框位置失败!")if __debug__:print(f"dialog_x,dialog_y:{dialog_x,dialog_y}")(dialog_len,dialog_hei)=self.find_dialog_lenhei(im,dialog_x,dialog_y)if dialog_len==-1 or dialog_hei==-1:logger.warning("查找对话框长宽失败!")if __debug__:print(f"dialog_len,dialog_hei{dialog_len,dialog_hei}")#根据获得的参数截取对话框的图片dialog_image=im.crop((dialog_x,dialog_y-dialog_hei,dialog_x+dialog_len,dialog_y))hasNews=Falseif privous_screenshot is not None:#与上一张截图进行对比,相似度是否在阈值内#此处只对比了消息框的内容,会导致用户连续发送相同的内容不会认为其是新消息,暂时没解决办法hasNews=self.compare_image(privous_screenshot,dialog_image)if hasNews:#使用cnocr进行识别,部分文字仍识别不正确,但正确率仍可以接受result=self.ocr.ocr(dialog_image)res_text=""for element in result:#拼接识别的文字res_text=res_text+element.get('text')logger.info(f"识别新消息:{res_text}")if self.using_name:if res_text.startswith(self.robot_name):res_text=res_text.replace(self.robot_name,"")#识别出机器人名字,然后从消息中去除机器人名字self.message_list.put(res_text)else:self.message_list.put(res_text)privous_screenshot=dialog_imagetime.sleep(0.5)
class AI_reply:def __init__(self,queue) -> None:self.queue=queueself.api_key='abcdefghijklmnopqrstuvwxyz'#换成你的openai api keyopenai.api_key=self.api_keyopenai.proxy = 'http://127.0.0.1:1234'#设置下代理,否则连不上网络self.model='gpt-3.5-turbo'self.temperature=0.7self.max_tokens=200#设置200回复字数上限,担心我的额度啊self.n=1self.msg_context=Queue()#保存的上下文self.msg_context_limit=5#上下文大小,影响ai能记住几句之前的内容self.keyborad=Controller()# def test_api(self):#     messages = [{ "role": "user", "content": '欢迎使用openai!' }]#     model = 'gpt-3.5-turbo'#     response = openai.ChatCompletion.create(#         model=model,#         messages=messages,#         temperature=self.temperature,#         n=self.n#     )#     queue_limit_put(self.msg_context,self.msg_context_limit,response.choices[0].message)#     if __debug__:#         print(f'\033[31m收到的数据:{response.choices[0].message.content}\033[0m')#制作消息放入上下文中def create_message(self,content):message={"role":"user","content":content}queue_limit_put(self.msg_context,self.msg_context_limit,message)return self.msg_context#请求api,获得返回结果def get_response(self,message):try:response=openai.ChatCompletion.create(model=self.model,messages=message,temperature=self.temperature,max_tokens=self.max_tokens)except openai.APIConnectionError  as e:logger.error(e)return ('error','网络又抽风了,这也是没办法的事。')queue_limit_put(self.msg_context,self.msg_context_limit,response.choices[0].message)#将返回的结果放入上下文中,让ai能记住说了什么logger.info(f"从openai获得回复:{response.choices[0].message.content}")return ('success',response.choices[0].message.content)def run(self):while True:logger.info("等待新消息。")msg=self.queue.get()logger.info(f"获得新消息,正在请求openai:{msg}")self.create_message(msg)logger.info(f"token:{list(self.msg_context.queue)}")(statue,res)=self.get_response(list(self.msg_context.queue))if statue=='success':self.send_msg_on_wechat(msg,res)elif statue=='error':self.send_msg_on_wechat('链接不上openai了',res)logger=logging.getLogger('robot_logger')
logger.setLevel("INFO")
file_handler = logging.FileHandler("C:\\Users\\22308\\Documents\\python file\\log\\robot.txt")
file_handler.setLevel("INFO")
fmt =logging.Formatter('%(filename)s-%(lineno)d-%(asctime)s-%(levelname)s-%(message)s')
file_handler.setFormatter(fmt)
logger.addHandler(file_handler)
logger.info("开始运行!")
robot=WeChatRobot()
ai=AI_reply(robot.message_list)
logger.info("初始化完成")
#创建线程监控是否有新消息,然后请求api
thread = threading.Thread(target=ai.run)
thread.start()
robot.run()
thread.join()
logger.info("运行结束!")

遇到问题

写一下遇到的一些小问题吧。

pymouse报错缺少windows和win32api

虽然最后也没用到这个库,但遇到了就写一下吧。
缺少windows:

pip install PyUserinput

缺少win32api:

pip install pypiwin32

module ‘PIL.Image’ has no attribute ‘ANTIALIAS’

在pillow的10.0.0版本中,ANTIALIAS方法被删除了,改为10.0版本许可的参数即可。

  • 方案一,修改ddddocr的_init_.py文件,将其中的ANTIALIAS替换为新方法:

    image = image.resize((int(image.size[0] * (64 / image.size[1])), 64), Image.LANCZOS).convert('L')
    
  • 方案二,降级Pillow的版本

    pip uninstall -y Pillow

    pip install Pillow==9.5.0

获取openai api key

在openai的官网上注册好后,到API文档中激活api key,每个月有5美刀的额度,持续三个月。不幸的是我的key不知道怎么回事已经申请过了,现在已经过期了😅。只好去买一个账号了,好在也不贵。

pip install CnOcr提示需要c++编译环境

找解决方法时有说安装anaconda可以,安装visual cpp build tool的。但总有地方卡住我。最后还是直接安装了virtual sudio,下了6个G😅。

总结

除了接入chatgpt以外,其实还可以使用一些固定指令来实现天气,咨询等内容,有了框架后这些也好写了。现在这些内容放到相亲相爱一家人里装个逼足够了。当然如果大家有更好用的技术或者其他建议的话欢迎告诉我。最后放一下我老婆。
老婆!

这篇关于使用文字识别构建的微信群聊天机器人的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/321954

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]