本文はネットユーザーからの投稿です
作者:且听风吟
原文タイトル:FlaUIオートメーション+chatGPTによるWeChat自動返信の実装
原文リンク:https://blog.csdn.net/ftfmatlab/article/details/132589169
1. まず効果画像を見る
WeChat友達リストを取得

自動応答効果

2. 本記事で実装する機能
今回は自動返信を実装する方法を紹介します:
ファイル転送アシスタントを最上部に固定し、マウスクリックをシミュレートします;
セッションリストを常に更新し、新しいメッセージがあれば内容を返信します;
新しいメッセージを更新したとき、対応する会話相手をマウスクリックで選択し、その際にグループチャットか個人かを判断し、グループチャットの場合は返信しません。
メッセージを取得した後、chatGPTに転送し、同時にchatGPTの返信を待ちます。
chatGPTの内容を取得した後、その内容をWeChatのチャットボックスに入力し、マウスクリックで送信ボタンを押します。
マウスクリックでファイル転送アシスタントを選択し、他のメッセージを待ちます。。。。
3. 機能コード
3.1. チャットメッセージの取得と送信
void GetChatInfo()
{
if (!IsInit)
{
return;
}
if (wxWindow == null)
{
return;
}
//wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).AsParallel().FirstOrDefault(s =>s!=null && s.Name == "聊天")?.Click(false);
wxWindow.FindFirstDescendant(cf => cf.ByName("聊天"))?.Click(false);
Task.Run(() =>
{
AutomationElement? assFirst = null;
object obj = new object();
while (true)
{
if (ChatListCancellationToken.IsCancellationRequested)
{
break;
}
try
{
DateTime dateTime3 = DateTime.Now;
var searchTextBox = wxWindow.FindFirstDescendant(cf => cf.ByName("会话")).AsListBoxItem();
if (searchTextBox != null)
{
var list = searchTextBox.FindAllChildren();
if (assFirst == null)
{
assFirst = list.AsParallel().FirstOrDefault(t => t != null && "文件传输助手".Equals(t.Name));// 並列検索---ファイル転送アシスタントを最上部に固定する必要あり
assFirst?.Click();
continue;
}
Parallel.ForEach(list, item =>
{
if (item != null && !string.IsNullOrEmpty(item.Name) && !"折叠置顶聊天".Equals(item.Name)
&& !"腾讯新闻".Equals(item.Name) && !"群聊".Contains(item.Name))
{
DateTime t1= DateTime.Now;
var allText = item.FindAllByXPath(".//Text");// 要素のローカル検索: .//Text; グローバル検索: //*/Text
DateTime t2 = DateTime.Now;
Trace.WriteLine($"allText所用時間:{(t2 - t1).TotalMilliseconds}ms");
// まだ返信していないメッセージリストを返信
if (allText != null && allText.Length >= 4)
{
if (int.TryParse(allText[3].Name, out var count) && count > 0)
{
lock (obj)
{
var name = allText[0].Name;
var time = allText[1].Name;
var content = allText[2].Name;
if (wxWindow.Patterns.Window.PatternOrDefault != null)
{
//WeChatウィンドウをデフォルトのフォーカス状態に設定
wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
}
item.Click();
DateTime t7= DateTime.Now;
var itemFirst = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Text)).AsParallel()
.FirstOrDefault(t =>t!=null && t.Parent.ControlType == ControlType.Pane && !t.IsOffscreen && t.Name.Trim().IsSpecificNumbers());
DateTime t8= DateTime.Now;
Trace.WriteLine($"itemFirst:{(t8 - t7).TotalMilliseconds}ms");
// グループチャットかどうかを判断
if (itemFirst == null)
{
AutoGetMesg(content);
}
assFirst?.Click();
}
}
}
}
});
DateTime dateTime4 = DateTime.Now;
Trace.WriteLine($"タスク888の所要時間:{(dateTime4 - dateTime3).TotalMilliseconds}ms");
}
else
{
Thread.Sleep(10);
continue;
}
//ScrollEvent(-700);
}
catch (Exception ex)
{
continue;
}
finally
{
//await Task.Delay(1);
}
}
}, ChatListCancellationToken);
}
3.2. 自動応答
IChat _chat;
private void AutoGetMesg(string txt)
{
if (_chat == null)
{
_chat = new ChatAchieve();
_chat.RequestContent = GetMessage;
}
Trace.WriteLine($"送信メッセージ:{txt}");
_chat.RequestGPT(txt);
}
private FlaUI.Core.AutomationElements.TextBox _mesText;
public FlaUI.Core.AutomationElements.TextBox MesText
{
get
{
if (_mesText == null)
_mesText = wxWindow.FindFirstDescendant(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Text)).AsTextBox();
return _mesText;
}
}
private AutomationElement? _btnSend;
public AutomationElement? btnSend
{
get
{
if (_btnSend == null)
{
_btnSend = wxWindow.FindFirstDescendant(cf => cf.ByName("sendBtn"));
//_btnSend = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).FirstOrDefault(s => s.Name == "发送(S)");
}
return _btnSend;
}
}
const int _offSize = 300;
private void GetMessage(string mes)
{
SendMes(mes);
Trace.WriteLine($"返信:{mes}");
}
private void SendMes(string mes)
{
if (wxWindow.Patterns.Window.PatternOrDefault != null)
{
//WeChatウィンドウをデフォルトのフォーカス状態に設定
wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
}
int tempLen = 0;
string txt = string.Empty;
try
{
if (!string.IsNullOrWhiteSpace(mes))
{
string[] lines = mes.Split(Environment.NewLine);
foreach (string line in lines)
{
tempLen += line.Length;
txt += line + Environment.NewLine;
if (tempLen > _offSize)
{
MesText.Text = txt;
btnSend?.Click();
tempLen = 0;
txt = string.Empty;
}
}
if (!string.IsNullOrWhiteSpace(txt))
{
MesText.Text = txt;
Thread.Sleep(3);
btnSend?.Click();
}
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message);
MesText.Text = txt;
btnSend?.Click();
}
}
3.3. その他のコード
/// <summary>
/// 起動
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, EventArgs e)
{
InitWechat();
}
private void FrmMain_Load(object sender, EventArgs e)
{
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
this.Dispose();
GC.Collect();
}
private CancellationToken FriendCancellationToken { get; set; }
private CancellationTokenSource FriendTokenSource { get; set; }
private CancellationToken ChatListCancellationToken { get; set; }
private CancellationTokenSource ChatListTokenSource { get; set; }
private CancellationToken GetFriendCancellationToken { get; set; }
private CancellationTokenSource GetFriendTokenSource { get; set; }
/// <summary>
/// WeChatのプロセスID
/// </summary>
private int ProcessId { get; set; }
/// <summary>
/// WeChatウィンドウ
/// </summary>
private Window wxWindow { get; set; }
private bool IsInit { get; set; }
/// <summary>
/// 取得
/// </summary>
void GetWxHandle()
{
var process = Process.GetProcessesByName("Wechat").FirstOrDefault();
if (process != null)
{
ProcessId = process.Id;
}
}
/// <summary>
/// WeChatを読み込み
/// </summary>
void InitWechat()
{
IsInit = true;
GetWxHandle();
GetFriendTokenSource = new CancellationTokenSource();
GetFriendCancellationToken = GetFriendTokenSource.Token;
ChatListTokenSource = new CancellationTokenSource();
ChatListCancellationToken = ChatListTokenSource.Token;
FriendTokenSource = new CancellationTokenSource();
FriendCancellationToken = FriendTokenSource.Token;
//WeChatプロセスIDに基づいてFLAUIをバインド
try
{
var application = FlaUI.Core.Application.Attach(ProcessId);
var automation = new UIA3Automation();
//WeChatウィンドウの自動操作オブジェクトを取得
wxWindow = application.GetMainWindow(automation);
}
catch (Exception ex)
{
if (MessageBox.Show(ex.Message, "異常", MessageBoxButtons.OK, MessageBoxIcon.Error) == DialogResult.OK)
this.Close();
}
// 友達を読み込み
IsListenCronyList = true;
// チャット情報を読み込み
GetChatInfo();
}
/// <summary>
/// 友達リストを取得
/// </summary>
void GetFriends()
{
if (!IsInit)
{
return;
}
if (wxWindow == null)
{
return;
}
if (wxWindow.Patterns.Window.PatternOrDefault != null)
{
//WeChatウィンドウをデフォルトのフォーカス状態に設定
wxWindow.Patterns.Window.Pattern.SetWindowVisualState(FlaUI.Core.Definitions.WindowVisualState.Normal);
}
wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.Button)).AsParallel()
.FirstOrDefault(item => item != null && item.Name == "通讯录")?.Click(false);
string lastName = string.Empty;
var list = new List<AutomationElement>();
var sync = SynchronizationContext.Current;
Task.Run(async () =>
{
while (true)
{
if (GetFriendCancellationToken.IsCancellationRequested)
break;
var all = wxWindow.FindAllDescendants(x => x.ByControlType(FlaUI.Core.Definitions.ControlType.ListItem));
var allItem = all.AsParallel().Where(s => s != null && s.Parent != null && "联系人".Equals(s.Parent?.Name)).ToList();
foreach (var item in allItem)
{
if (!string.IsNullOrWhiteSpace(item.Name) && !listBox1.Items.Contains(item.Name.ToString()))
{
sync.Post(s =>
{
listBox1.Items.Add(s);
}, item.Name.ToString());
}
}
//ScrollEvent(-700);
await Task.Delay(1);
}
}, GetFriendCancellationToken);
}
/// <summary>
/// 友達リストを監視
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnListenCronyList_Click(object sender, EventArgs e)
{
IsListenCronyList = !IsListenCronyList;
}
private bool _isListenCronyList = false;
public bool IsListenCronyList
{
set
{
if (_isListenCronyList == value)
return;
_isListenCronyList = value;
string txt = string.Empty;
if (value)
{
txt = "友達リストの監視を停止";
GetFriends();
}
else
{
txt = "友達リストの監視を開始";
GetFriendTokenSource.Cancel();
}
btnListenCronyList.ExecBeginInvoke(() =>
{
btnListenCronyList.Text = txt;
});
}
get => this._isListenCronyList;
}
3.4. 拡張メソッド
internal static class SystemEx
{
/// <summary>
/// スレッドを越えてコントロールを操作
/// </summary>
/// <param name="con"></param>
/// <param name="action"></param>
public static void ExecBeginInvoke(this Control con, Action action)
{
if (action == null) return;
if (con.InvokeRequired)
{
con.BeginInvoke(new Action(action));
}
else
{
action();
}
}
public static void ExecInvoke(this Control con, Action action)
{
if (action == null) return;
if (con.InvokeRequired)
{
con.Invoke(new Action(action));
}
else
{
action();
}
}
const string PARRERN = @"^\(\d+\)$";
public static bool IsSpecificNumbers(this string txt)
{
return Regex.IsMatch(txt, PARRERN);
}
}
注:ChatAchieveはIChatの実装であり、chatGPTの実装です
public interface IChat
{
Action<string> RequestContent { get; set; }
void RequestGPT(string content);
}
作者は面倒くさがりで、コードをリポジトリに置きたがらないため、ソースコードを直接サイト管理者に渡しました。必要な方はこちらからダウンロードしてください:https://img1.dotnet9.com/2023/08/WeChat.Automation.zip
技術交流のためのQQグループ:771992300
またはサイト管理者の微信(codewf、備考「加群」)をスキャンして微信技術交流グループにご参加ください:
