PC端从零搭建微信自动回复机器人(一)基础框架搭建及源码

由于工作需要,最近一年一直在研究和使用C#,加上最近工作上有做微信机器人的需要,在已经对接、调试稳定之后,将项目的源码分享给大家,传递开源精神。

一、环境依赖

1、开发工具:Vistual Studio 2022
2、NetFramework版本:6.0及以上
3、微信版本:WeChatSetup_3.7.0.30.exe (找不到可以私信我)

二、支持功能

目前该组件自身支持很多功能,如下所示:

  • 获取通讯录
  • 获取所有群成员基础信息(含wxid,群昵称,微信昵称)
  • 发送文本、图片、文件、xml文章、名片、群艾特消息
  • 根据wxid查询好友信息
  • 根据群ID获取所有群成员WXID / 同时获取一个微信群内所有成员的群昵称
  • 检测好友状态(是否好友、被删除、被拉黑)
  • 接收各类消息,可写回调函数进行处理
  • 群管理
  • 微信多开
  • 自动合并短的文本、艾特信息(可设定单条信息最大长度)
  • 自动分割过长的单条信息

在这些功能的基础上我们可以结合自身的使用场景进行定制化开发和调用。目前我主要根据群聊中@和私聊这两个场景进行一些封装,我将代码进行了删减,仅保留基础部分。

三、项目结构及如何运行

1、项目结构

项目整体有三个部分构成。如下图所示:
在这里插入图片描述
ConsoleApp1用于自定义逻辑和启动类都写在中。–自行创建
RS.Snail.JJJ.Wechat是底层依赖组件。–可参考我上传的附件
Segments是自带中文分词器的一个组件,用于对用户问题与问题列表进行分词匹配。–下篇文章详解

2、自定义逻辑实现

启动类实现代码 Program.cs 代码如下

// See https://aka.ms/new-console-template for more information
using ConsoleApp1;
using Newtonsoft.Json.Linq;
using RS.Snail.JJJ.Wechat;
using static ConsoleApp1.MessageHandler;

Console.WriteLine("Hello, World!");
var wechat = new RS.Snail.JJJ.Wechat.Service();
String mSelf_WXID = "wxid_m2khoia398xh22";//登录
bool v = wechat.Init(
                    // new List<string> { "wxid_1234_" },
                    new List<string> { mSelf_WXID },
                    new Func<dynamic, Task>((msg) => {

                        Console.Write(msg);
   

                                          ;
                        //CDATA[,wxid_8qfg0x0do56t22
                        MessageParam mMessageParam = new MessageParam(mSelf_WXID,wechat, (JObject)msg);         
                       
                        if (mMessageParam.isAtSelf())//判断是否是群聊@微信机器人
                        {
                            List<String> atPersons = mMessageParam.getAtList();
                            String mTemp = ((JObject)msg).GetValue("message").ToString();
                            foreach (String mItem in atPersons) {
                                String mOld = "@" + wechat.ChatroomGetMemberNick(mSelf_WXID, ((JObject)msg).GetValue("sender").ToString(), mItem);
                                mTemp = mTemp.Replace("@微信客服", "").Trim();//注意,这里需要与自身微信昵称保持一致
                            }
                            ThreadParam mThreadParam = new ThreadParam() {
                                ObjParam = wechat,Msg=msg, MTemp=mTemp, Self_WXID=mSelf_WXID
                            };
                          
                            new Thread(new ParameterizedThreadStart((Obj) =>
                            {
                                new MessageHandler().sendAnswer((ThreadParam)Obj);

                            })).Start(mThreadParam);

                        }
                        else {
                            String mTemp = ((JObject)msg).GetValue("message").ToString();
                         
                                List<String> atPersons = mMessageParam.getAtList();
                                ThreadParam mThreadParam = new ThreadParam()
                                {
                                    ObjParam = wechat,
                                    Msg = msg,
                                    MTemp = mTemp,
                                    Self_WXID = mSelf_WXID
                                };
                                new Thread(new ParameterizedThreadStart((Obj) =>
                                {
                                    new MessageHandler().transferAnser((ThreadParam)Obj);

                                })).Start(mThreadParam);
                        }
               
                        return new Task(new Action(() => {
                                                   }));
                    
                    })


                    //msg =>  Console.Write(msg)
                    ) ;
//图片保存钩子
//wechat.MsgStartImageHook(mSelf_WXID, "D:\\image");


wechat.StartReceive();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();
Console.ReadKey();

自定义问答逻辑类MessageParam.cs 代码如下:


using JiebaNet.Segmenter.PosSeg;
using Newtonsoft.Json.Linq;
using RS.Snail.JJJ.Wechat;
using System.Diagnostics;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Segments;

namespace ConsoleApp1
{

    public class MessageParam
    {
        private RS.Snail.JJJ.Wechat.Service wechat;
        private JObject msg;
        private String self_WXID;
        public Service Wechat { get => wechat; set => wechat = value; }
        public JObject Msg { get => msg; set => msg = value; }
        public string Self_WXID { get => self_WXID; set => self_WXID = value; }

        public MessageParam(String self_WXID, RS.Snail.JJJ.Wechat.Service wechat, JObject msg) {
          this.self_WXID = self_WXID;
          this.wechat= wechat;
          this.msg = msg;
        }

        public bool isAtSelf() {
            String mextrainfo = ((JObject)msg).GetValue("message").ToString();
            if (mextrainfo.Contains("@微信客服"))//注意,这里需要与自身微信昵称保持一致
            {
                return true;
            }
            else {
                return false;
            }
        }

        public List<String> getAtList() {
            String mextrainfo = ((JObject)msg).GetValue("extrainfo").ToString();
            List<String> mStrs = new List<String>();
            try
            {
                mStrs = mextrainfo.Split(new String[] { "<atuserlist><![CDATA[", "]]></atuserlist>" }, StringSplitOptions.None)[1].Split(",").ToList();
            }
            catch (Exception ex) {
                mStrs = new List<String>();
            }

            try
            {
                if (mStrs.Count == 0) {
                    mStrs = mextrainfo.Split(new String[] { "<atuserlist>", "</atuserlist>" }, StringSplitOptions.None)[1].Split(",").ToList();
                }
               
            }
            catch (Exception ex)
            {
                mStrs = new List<String>();
            }

           
            return mStrs;
        }

    }
    public  class MessageHandler
    {
        public void sendAnswer(ThreadParam mThreadParam)
        {

            Object Obj = mThreadParam.ObjParam;
            String mSelf_WXID = mThreadParam.Self_WXID;
            Object msg = mThreadParam.Msg;
            String mTemp = mThreadParam.MTemp.Replace("@智能客服", "").Trim();//注意,这里需要与自身微信昵称保持一致
            String roomName = getChatRoomName(mSelf_WXID, Obj, msg);
            String roomId = ((JObject)msg).GetValue("sender").ToString();
            Service wechat = (Service)Obj;
            String sendStr = "";
            String similarity = "1";
         if (mTemp.Equals("智能客服")|| mTemp.Trim().Equals(""))
            {
                sendStr = "@" + wechat.ChatroomGetMemberNick(mSelf_WXID, ((JObject)msg).GetValue("sender").ToString(),
                                                                 ((JObject)msg).GetValue("wxid").ToString()) + "您好,我是微信客服。有什么问题可以直接向我提问哦~ 提问方式请参考下方模板\r\n【常见问题搜索】请输入报错码/错误关键字,例如:96000322/系统异常,请您稍后再试\r\n";
                ((Service)Obj).MsgSendAt(
                                                                 mSelf_WXID,
                                                                 ((JObject)msg).GetValue("sender").ToString(),
                                                                 new List<string> { ((JObject)msg).GetValue("wxid").ToString() },
                                                                 sendStr, false);
            }else
            {

            //调用分词匹配进行初筛
            List<JObject> resList = Segments.Segments.selectQuestion(mTemp,CommonUtils.parseErrorList());
            similarity = resList.Count.ToString();
            //调用搜索接口
            //List<JObject> resList = CommonUtils.QueryMsg(mTemp);
            if (resList.Count == 0)//未查询到答案信息
            {
                sendStr = "@" + wechat.ChatroomGetMemberNick(mSelf_WXID, ((JObject)msg).GetValue("sender").ToString(),
                                                  ((JObject)msg).GetValue("wxid").ToString()) + " 您发送了:" + mTemp + ",未找到相应答案,请用报错码/报错信息直接进行提问。或者@群内技术推广老师进行咨询";
                ((Service)Obj).MsgSendAt(
                                                  mSelf_WXID,
                                                  ((JObject)msg).GetValue("sender").ToString(),
                                                  new List<string> { ((JObject)msg).GetValue("wxid").ToString() },
                                                  sendStr, false);
             
            }
            else
            {
               
                StringBuilder sb = new StringBuilder();
                sb.AppendLine( " 您发送了:" + mTemp + ",为您匹配到了:" + resList.Count + "条解答,详情如下:");
                List<JObject> imgList = new List<JObject>();
                for (int i = 0; i < resList.Count; i++)
                {
                    String errorDetail = resList[i]["errorDetail"].ToString();
                    String isImg = resList[i]["isImg"].ToString();
                    String errorType = CommonUtils.getErrorType(resList[i]["errorType"].ToString());

                    //如果isImg为1,则下载并发送图片
                    if (isImg.Equals("1"))
                    {
                        imgList.Add(resList[i]);
                    }
                    else
                    {
                        String solution = resList[i]["errorSolution"].ToString();
                        String errorCode = resList[i]["errorCode"].ToString();
                        sb.AppendLine("错误码:"+errorCode);
                        sb.AppendLine("错误类型:"+ errorType);
                        sb.AppendLine("错误描述:"+ errorDetail);
                        sb.AppendLine("解决方案:"+ solution);
                        sb.AppendLine("=====================");
                    }
                }
                sendStr = "@" + wechat.ChatroomGetMemberNick(mSelf_WXID, ((JObject)msg).GetValue("sender").ToString(),
                        ((JObject)msg).GetValue("wxid").ToString()) + sb.ToString();
                 ((Service)Obj).MsgSendAt(
                        mSelf_WXID,
                        ((JObject)msg).GetValue("sender").ToString(),
                        new List<string> { ((JObject)msg).GetValue("wxid").ToString() },
                       sendStr, false);

            }
            }

        }


        //   查询群名称
        public String getChatRoomName(String mSelf_WXID,Object Obj,Object msg)
        {
            //获取数据库句柄
            JArray obj = ((Service)Obj).DatabaseGetHandles(mSelf_WXID);
            //查询群名称
            String sql = "select NickName from Contact where UserName = '" + ((JObject)msg).GetValue("sender").ToString() + "'";
            JObject first = obj.First() as JObject;
            obj = ((Service)Obj).DatabaseQuery(mSelf_WXID, (uint)first["handle"], sql);
            return obj[1][0].ToString();
        }

        public void transferAnser(ThreadParam mThreadParam)
        {
           //自定义逻辑            
        }
     }

    public class ThreadParam {
        Object mObj; 
        String self_WXID;
        Object msg;
        String mTemp;

        public object ObjParam { get => mObj; set => mObj = value; }
        public string Self_WXID { get => self_WXID; set => self_WXID = value; }
        public object Msg { get => msg; set => msg = value; }
        public string MTemp { get => mTemp; set => mTemp = value; }
    }

}

CommonUtils.cs由于都是一些发送http请求的方法,就不放源码了,大家自行实现。

3、项目启动演示

首先需要配置启动项,我们需要将ConsoleApp1配置为启动项。
在这里插入图片描述
启动项目后会自动打开一个控制台,同时唤醒微信客户端。在这里插入图片描述
需要扫码登录后,在控制台中输入大写的Y,即可完成登录。
这里由于我的微信自动升级了版本,就不演示了。
当你在群聊中@微信机器人时,就会按照代码中的实现逻辑自动回复你了。这其中的语料库可以自己通过查库,本地读取,或者直接接入目前主流的各类大语言模型(chatGPT,文心一言,通义千问,科大星火等等),发挥自己的想象力,尽情的尝试吧。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/188581.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java学习part11继承

1.类的继承 继承为了让类之间建立联系&#xff0c;同时复用代码。 子类和父类的同名函数构成重写&#xff0c;能覆盖&#xff0c;除非用super.xx()调。 同名属性不会覆盖&#xff0c;而是并存&#xff0c;用super.xx调。 2.子类初始化 子类会自动调用父类无参构造super() 3.重…

RuntimeError: CUDA error: device-side assert triggered

背景&#xff1a; 使用SAGEConv卷积层的图神经网络&#xff0c;网络架构如下 原因&#xff1a; 我在卷积层之前改变了特征矩阵的维度&#xff0c;原本为[172,1,32] 现在改为了 [172,2,32]。导致了特征矩阵x在进行 “x x.squeeze(1)” 操作时并没有将第二向量值去除&#xff08…

国标交流充电桩接口和直流充电桩接口介绍

1、背景 与传统油车相比&#xff0c;纯电车有太多的优势&#xff0c;但是纯电需要考虑充电时间的长短以及电池的使用寿命。然而相比较而言&#xff0c;混动有好多的备选方案比如插电式、增程式等&#xff0c;除了满足比电车较远的续航外&#xff0c;充电等待时间大大缩短。 在…

ElasticSearch01

ElasticSearch 版本&#xff1a;7.8 学习视频&#xff1a;尚硅谷 笔记&#xff1a;https://zgtsky.top/ ElasticSearch介绍 Elaticsearch&#xff0c;简称为es&#xff0c; es是一个开源的高扩展的分布式全文检索引擎&#xff0c;它可以近乎实时的存储、检索数据&#xff1b…

C++实现十大排序算法

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

基于Flutter的图片浏览器的实现

一 效果展示&#xff1a; 1. 图片展示&#xff1a; 2.混色&#xff0c;平铺&#xff0c;拉伸&#xff0c;原图展示 二 实验准备&#xff1a; 1.在包结构中创建images包来存放我们用到的图片&#xff0c;在pubspec.yaml中声明路径&#xff1a; 2. 检查虚拟机是否正常运行&…

数字孪生智慧校园 Web 3D 可视化监测

当今&#xff0c;智慧校园发展阶段亟需推动信息可视化建设与发展&#xff0c;将大数据、云计算、可视化等高新技术相融合&#xff0c;为校园师生创造科学智能的学习环境&#xff0c;并实现教学资源最大化和信息服务智能化。帮助学校更好地应用校园可视化技术&#xff0c;提升校…

rfc4301- IP 安全架构

1. 引言 1.1. 文档内容摘要 本文档规定了符合IPsec标准的系统的基本架构。它描述了如何为IP层的流量提供一组安全服务&#xff0c;同时适用于IPv4 [Pos81a] 和 IPv6 [DH98] 环境。本文档描述了实现IPsec的系统的要求&#xff0c;这些系统的基本元素以及如何将这些元素结合起来…

Jensen不等式

如果是正数&#xff0c;并且它们的和等于1&#xff0c;f是凸函数&#xff0c;那么&#xff1a; 也可表述为&#xff1a; 即x期望的凸函数值小于等于x凸函数值的期望

【数据库】聊聊一颗B+树 可以存储多少数据

我们知道数据库使用的数据结构是B树&#xff0c;但是B树可以存储多少数据呢&#xff0c;在面试中也是经常会问的问题&#xff0c;所以我们从根上理解这个问题。 操作系统层面 数据都是存储在磁盘中的&#xff0c;而磁盘中的数据都是以最新单位扇区进行分割。一个扇区的大小是…

STM32 CAN协议讲解以及代码

STM32 CAN 文章目录 STM32 CAN前言一、CAN外设1.主控制寄存器CAN_MCR2.位时序寄存器CAN_BTR3.CAN的发送邮箱4.CAN的接收FIFO5.验收筛选器 二、代码配置1.初始化2.发送数据3.接收数据4.main.c 前言 前面学习了CAN的一些理论知识&#xff0c;他在我们的STM32里面是怎么用的呢 前…

vue3+elementPlus之侧边菜单栏功能

选择默认的颜色&#xff0c;将代码拷贝至<el-aside>模块中 稍微把不需要的修改一下。 <template><div class"common-layout"><el-container><el-header class"homeHeader"><div class"headerTitle">Devops…

2023年【安全员-C证】考试试卷及安全员-C证试题及解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证考试试卷是安全生产模拟考试一点通生成的&#xff0c;安全员-C证证模拟考试题库是根据安全员-C证最新版教材汇编出安全员-C证仿真模拟考试。2023年【安全员-C证】考试试卷及安全员-C证试题及解析 1、【多选…

基于uQRCode封装的Vue3二维码生成插件

标题&#xff1a;基于uQRCode封装的Vue3二维码生成插件 摘要&#xff1a;本文介绍了一种基于uQRCode封装的Vue3二维码生成插件&#xff0c;可以在Javascript运行环境下生成二维码并返回图片地址。该插件适用于所有Javascript运行环境&#xff0c;并且支持微信小程序。本文将详…

springboot+vue项目如何集成onlyoffice开源文档组件

一、onlyoffice是什么 ONLYOFFICE 是一个开源的办公套件&#xff0c;适合多人在线协作。由总部位于总部在拉脱维亚的 IT 公司Acensio System SIA 开发。它提供在线协作文档编辑器&#xff08;包括文档、电子表格、演示文稿和表单&#xff09;&#xff0c;适用于 Windows、Linu…

Jenkins用126邮箱发邮件为什么发不出去

1、检查 Jenkins Location中的邮件地址配置与发邮件的地址配置是否一致 Manage Jenkins -》 system 2、检查地址和端口号 3、检查邮箱的登录配置是否正确&#xff08;这个地方的配置方式网上一抓一大把&#xff0c;自己搜一下就好&#xff09; 4、126邮箱发邮件不需要勾选ssl协…

QXDM Filter使用指南

QXDM Filter使用指南 1. QXDM简介2 如何制作和导入Filter2.1 制作Filter2.1.1 制作Windows环境下Filter2.1.2 制作Linux环境下Filter 2.2 Windows环境下导入Filter 3 Filter配置3.1 注册拨号问题3.1.1 LOG Packets(OTA)3.1.2 LOG Packets3.1.3 Event Reports3.1.4 Message Pack…

033.Python面向对象_类补充_生命周期

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

Java学习路径:入门学习、深入学习、核心技术,操作案例和实际代码示例

学习路径&#xff1a;入门学习、深入学习、核心技术&#xff0c; 每个主题都包括很多的操作案例和实际代码示例。 a. 入门学习&#xff1a; 1. 基础语法&#xff1a; 变量和数据类型&#xff1a; // 定义和初始化变量 int age 25;// 不同数据类型的声明 double price 19.99…

智能汽车十大网络安全攻击场景-《智能汽车网络安全权威指南》

引言 大家都很熟悉OWASP Top 10风险报告&#xff0c;这个报告不但总结了Web应用程序最可能、最常见、最危险的10大安全隐患&#xff0c;还包括了如何消除这些隐患的建议&#xff0c;这个“OWASP Top 10“差不多每隔三年更新一次。目前汽车网络安全攻击威胁隐患繁多&#xff0c…
最新文章