当前位置:   article > 正文

牛逼:使用C#组合FlaUI和chatGPT实现微信AI问答

c#ai对话

本文由网友投稿

作者:且听风吟

原文标题:基于FlaUI自动化+chatGPT实现微信自动回复

原文链接:https://blog.csdn.net/ftfmatlab/article/details/132589169

1. 先看效果图

获取微信好友列表

46cce81a427847d7c8d484eefa96b2e5.png

自动问答效果

ddb8c5676f0ff0ce906bf3fe83277d8a.png

2. 本文实现功能

本次主要介绍如何实现自动回复:

  1. 将文件传输助手置顶,模拟鼠标点击文件传输助手;

  2. 一直刷新会话列表,有新的消息就需要回复内容;

  3. 当刷新到新的消息时,模拟鼠标点击到对应的会话人,此时判断是群聊还是人,如果是群聊则不回复。

  4. 获取消息后转发给chatGPT,同时等待chatGPT回复内容。

  5. 获取chatGPT的内容后将内容输入到微信聊天框,并模拟鼠标点击发送按钮。

  6. 模拟鼠标点击文件传输助手,等待其它消息。。。。

3. 功能代码

3.1. 获取聊天消息并发送

  1. void GetChatInfo()
  2. {
  3.      if (!IsInit)
  4.      {
  5.           return;
  6.      }
  7.      if (wxWindow == null)
  8.      {
  9.           return;
  10.      }
  11.      //wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).AsParallel().FirstOrDefault(s =>s!=null && s.Name == "聊天")?.Click(false);
  12.      wxWindow.FindFirstDescendant(cf => cf.ByName("聊天"))?.Click(false);
  13.      Task.Run(() =>
  14.      {
  15.           AutomationElement? assFirst = null;
  16.           object obj = new object();
  17.           while (true)
  18.           {
  19.           if (ChatListCancellationToken.IsCancellationRequested)
  20.           {
  21.                break;
  22.           }
  23.           try
  24.           {
  25.                DateTime dateTime3 = DateTime.Now;
  26.                var searchTextBox = wxWindow.FindFirstDescendant(cf => cf.ByName("会话")).AsListBoxItem();
  27.                if (searchTextBox != null)
  28.                {
  29.                     var list = searchTextBox.FindAllChildren();
  30.                     if (assFirst == null)
  31.                     {
  32.                          assFirst = list.AsParallel().FirstOrDefault(t => t != null && "文件传输助手".Equals(t.Name));// 并行查询---需要将文件传输助手置顶
  33.                          assFirst?.Click();
  34.                          continue;
  35.                     }
  36.                     Parallel.ForEach(list, item =>
  37.                     {
  38.                          if (item != null && !string.IsNullOrEmpty(item.Name) && !"折叠置顶聊天".Equals(item.Name)
  39.                               && !"腾讯新闻".Equals(item.Name) && !"群聊".Contains(item.Name))
  40.                          {
  41.                               DateTime t1= DateTime.Now;
  42.                               var allText = item.FindAllByXPath(".//Text");//   定位元素的局部搜索: .//Text;   全局搜索: //*/Text
  43.                               DateTime t2 = DateTime.Now;
  44.                               Trace.WriteLine($"allText用时:{(t2 - t1).TotalMilliseconds}ms");
  45.                               // 回复消息列表还未回复的
  46.                               if (allText != null && allText.Length >= 4)
  47.                               {
  48.                               if (int.TryParse(allText[3].Name, out var count) && count > 0)
  49.                               {
  50.                                    lock (obj)
  51.                                    {
  52.                                         var name = allText[0].Name;
  53.                                         var time = allText[1].Name;
  54.                                         var content = allText[2].Name;
  55.                                         if (wxWindow.Patterns.Window.PatternOrDefault != null)
  56.                                         {
  57.                                              //将微信窗体设置为默认焦点状态
  58.                                              wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
  59.                                         }
  60.                                         item.Click();
  61.                                         DateTime t7= DateTime.Now;
  62.                                         var itemFirst = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Text)).AsParallel()
  63.                                         .FirstOrDefault(t =>t!=null && t.Parent.ControlType == ControlType.Pane && !t.IsOffscreen && t.Name.Trim().IsSpecificNumbers());
  64.                                         DateTime t8= DateTime.Now;
  65.                                         Trace.WriteLine($"itemFirst:{(t8 - t7).TotalMilliseconds}ms");
  66.                                         // 判断是否为群聊
  67.                                         if (itemFirst == null)
  68.                                         {
  69.                                              AutoGetMesg(content);
  70.                                         }
  71.                                         assFirst?.Click();
  72.                                    }
  73.                               }
  74.                               }
  75.                          }
  76.                     });
  77.                     DateTime dateTime4 = DateTime.Now;
  78.                     Trace.WriteLine($"任务888耗时:{(dateTime4 - dateTime3).TotalMilliseconds}ms");
  79.                }
  80.                else
  81.                {
  82.                     Thread.Sleep(10);
  83.                     continue;
  84.                }
  85.                //ScrollEvent(-700);
  86.           }
  87.           catch (Exception ex)
  88.           {
  89.                continue;
  90.           }
  91.           finally
  92.           {
  93.                //await Task.Delay(1);
  94.           }
  95.           }
  96.      }, ChatListCancellationToken);
  97. }

3.2. 自动回复

  1. IChat _chat;
  2. private void AutoGetMesg(string txt)
  3. {
  4.      if (_chat == null)
  5.      {
  6.           _chat = new ChatAchieve();
  7.           _chat.RequestContent = GetMessage;
  8.      }
  9.      Trace.WriteLine($"发送消息:{txt}");
  10.      _chat.RequestGPT(txt);
  11. }
  12. private FlaUI.Core.AutomationElements.TextBox _mesText;
  13. public FlaUI.Core.AutomationElements.TextBox MesText
  14. {
  15.      get
  16.      {
  17.           if (_mesText == null)
  18.           _mesText = wxWindow.FindFirstDescendant(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Text)).AsTextBox();
  19.           return _mesText;
  20.      }
  21. }
  22. private AutomationElement? _btnSend;
  23. public AutomationElement? btnSend
  24. {
  25.      get
  26.      {
  27.           if (_btnSend == null)
  28.           {
  29.           _btnSend = wxWindow.FindFirstDescendant(cf => cf.ByName("sendBtn"));
  30.           //_btnSend = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).FirstOrDefault(s => s.Name == "发送(S)");
  31.           }
  32.           return _btnSend;
  33.      }
  34. }
  35. const int _offSize = 300;
  36. private void GetMessage(string mes)
  37. {
  38.      SendMes(mes);
  39.      Trace.WriteLine($"回复:{mes}");
  40. }
  41. private void SendMes(string mes)
  42. {
  43.      if (wxWindow.Patterns.Window.PatternOrDefault != null)
  44.      {
  45.           //将微信窗体设置为默认焦点状态
  46.           wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
  47.      }
  48.      int tempLen = 0;
  49.      string txt = string.Empty;
  50.      try
  51.      {
  52.           if (!string.IsNullOrWhiteSpace(mes))
  53.           {
  54.           string[] lines = mes.Split(Environment.NewLine);
  55.           foreach (string line in lines)
  56.           {
  57.                tempLen += line.Length;
  58.                txt += line + Environment.NewLine;
  59.                if (tempLen > _offSize)
  60.                {
  61.                     MesText.Text = txt;
  62.                     btnSend?.Click();
  63.                     tempLen = 0;
  64.                     txt = string.Empty;
  65.                }
  66.           }
  67.           if (!string.IsNullOrWhiteSpace(txt))
  68.           {
  69.                MesText.Text = txt;
  70.                Thread.Sleep(3);
  71.                btnSend?.Click();
  72.           }
  73.           }
  74.      }
  75.      catch (Exception ex)
  76.      {
  77.           Trace.WriteLine(ex.Message);
  78.           MesText.Text = txt;
  79.           btnSend?.Click();
  80.      }
  81. }

3.3. 其它代码

  1. /// <summary>
  2. /// 启动
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. private void btnStart_Click(object sender, EventArgs e)
  7. {
  8.      InitWechat();
  9. }
  10. private void FrmMain_Load(object sender, EventArgs e)
  11. {
  12. }
  13. private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
  14. {
  15.      this.Dispose();
  16.      GC.Collect();
  17. }
  18. private CancellationToken FriendCancellationToken { get; set; }
  19. private CancellationTokenSource FriendTokenSource { get; set; }
  20. private CancellationToken ChatListCancellationToken { get; set; }
  21. private CancellationTokenSource ChatListTokenSource { get; set; }
  22. private CancellationToken GetFriendCancellationToken { get; set; }
  23. private CancellationTokenSource GetFriendTokenSource { get; set; }
  24. /// <summary>
  25. /// 微信的进程ID
  26. /// </summary>
  27. private int ProcessId { get; set; }
  28. /// <summary>
  29. /// 微信窗体
  30. /// </summary>
  31. private Window wxWindow { get; set; }
  32. private bool IsInit { get; set; }
  33. /// <summary>
  34. /// 获取
  35. /// </summary>
  36. void GetWxHandle()
  37. {
  38.      var process = Process.GetProcessesByName("Wechat").FirstOrDefault();
  39.      if (process != null)
  40.      {
  41.           ProcessId = process.Id;
  42.      }
  43. }
  44. /// <summary>
  45. /// 加载微信
  46. /// </summary>
  47. void InitWechat()
  48. {
  49.      IsInit = true;
  50.      GetWxHandle();
  51.      GetFriendTokenSource = new CancellationTokenSource();
  52.      GetFriendCancellationToken = GetFriendTokenSource.Token;
  53.      ChatListTokenSource = new CancellationTokenSource();
  54.      ChatListCancellationToken = ChatListTokenSource.Token;
  55.      FriendTokenSource = new CancellationTokenSource();
  56.      FriendCancellationToken = FriendTokenSource.Token;
  57.      //根据微信进程ID绑定FLAUI
  58.      try
  59.      {
  60.           var application = FlaUI.Core.Application.Attach(ProcessId);
  61.           var automation = new UIA3Automation();
  62.           //获取微信window自动化操作对象
  63.           wxWindow = application.GetMainWindow(automation);
  64.      }
  65.      catch (Exception ex)
  66.      {
  67.           if (MessageBox.Show(ex.Message, "异常", MessageBoxButtons.OK, MessageBoxIcon.Error) == DialogResult.OK)
  68.           this.Close();
  69.      }
  70.      // 加载好友
  71.      IsListenCronyList = true;
  72.      // 加载聊天信息
  73.      GetChatInfo();
  74. }
  75. /// <summary>
  76. /// 获取好友列表
  77. /// </summary>
  78. void GetFriends()
  79. {
  80.      if (!IsInit)
  81.      {
  82.           return;
  83.      }
  84.      if (wxWindow == null)
  85.      {
  86.           return;
  87.      }
  88.      if (wxWindow.Patterns.Window.PatternOrDefault != null)
  89.      {
  90.           //将微信窗体设置为默认焦点状态
  91.           wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
  92.      }
  93.      wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).AsParallel()
  94.           .FirstOrDefault(item => item != null && item.Name == "通讯录")?.Click(false);
  95.      string lastName = string.Empty;
  96.      var list = new List<AutomationElement>();
  97.      var sync = SynchronizationContext.Current;
  98.      Task.Run(async () =>
  99.      {
  100.           while (true)
  101.           {
  102.           if (GetFriendCancellationToken.IsCancellationRequested)
  103.                break;
  104.           var all = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.ListItem));
  105.           var allItem = all.AsParallel().Where(s => s != null && s.Parent != null && "联系人".Equals(s.Parent?.Name)).ToList();
  106.           foreach (var item in allItem)
  107.           {
  108.                if (!string.IsNullOrWhiteSpace(item.Name) && !listBox1.Items.Contains(item.Name.ToString()))
  109.                {
  110.                     sync.Post(s =>
  111.                     {
  112.                          listBox1.Items.Add(s);
  113.                     }, item.Name.ToString());
  114.                }
  115.           }
  116.           //ScrollEvent(-700);
  117.           await Task.Delay(1);
  118.           }
  119.      }, GetFriendCancellationToken);
  120. }
  121. /// <summary>
  122. /// 监听好友列表
  123. /// </summary>
  124. /// <param name="sender"></param>
  125. /// <param name="e"></param>
  126. private void btnListenCronyList_Click(object sender, EventArgs e)
  127. {
  128.      IsListenCronyList = !IsListenCronyList;
  129. }
  130. private bool _isListenCronyList = false;
  131. public bool IsListenCronyList
  132. {
  133.      set
  134.      {
  135.           if (_isListenCronyList == value)
  136.           return;
  137.           _isListenCronyList = value;
  138.           string txt = string.Empty;
  139.           if (value)
  140.           {
  141.           txt = "关闭监听好友列表";
  142.           GetFriends();
  143.           }
  144.           else
  145.           {
  146.           txt = "开启监听好友列表";
  147.           GetFriendTokenSource.Cancel();
  148.           }
  149.           btnListenCronyList.ExecBeginInvoke(() =>
  150.           {
  151.           btnListenCronyList.Text = txt;
  152.           });
  153.      }
  154.      get => this._isListenCronyList;
  155. }

3.4. 扩展方法

  1. internal static class SystemEx
  2. {
  3.      /// <summary>
  4.      /// 跨线程操作控件
  5.      /// </summary>
  6.      /// <param name="con"></param>
  7.      /// <param name="action"></param>
  8.      public static void ExecBeginInvoke(this Control con, Action action)
  9.      {
  10.           if (action == null) return;
  11.           if (con.InvokeRequired)
  12.           {
  13.                con.BeginInvoke(new Action(action));
  14.           }
  15.           else
  16.           {
  17.                action();
  18.           }
  19.      }
  20.      public static void ExecInvoke(this Control con, Action action)
  21.      {
  22.           if (action == null) return;
  23.           if (con.InvokeRequired)
  24.           {
  25.                con.Invoke(new Action(action));
  26.           }
  27.           else
  28.           {
  29.                action();
  30.           }
  31.      }
  32.      const string PARRERN = @"^\(\d+\)$";
  33.      public static bool IsSpecificNumbers(this string txt)
  34.      {
  35.           return Regex.IsMatch(txt, PARRERN);
  36.      }
  37. }

注:ChatAchieve是 IChat的实现,是对chatGPT的实现

  1. public interface IChat
  2. {
  3.      Action<string> RequestContent { get; set; }
  4.      void RequestGPT(string content);
  5. }

作者懒,不愿意将代码放仓库,源码直接丢站长了,大家需要直接点击下载:https://img1.dotnet9.com/2023/08/WeChat.Automation.zip

技术交流添加QQ群:771992300

或扫站长微信加入微信技术交流群:

b9819fef5ba539c344376c5cdb8991aa.jpeg
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/352823
推荐阅读
相关标签
  

闽ICP备14008679号