1
+ /*----------------------------------------------------------------
2
+ Copyright (C) 2024 Senparc
3
+
4
+ 文件名:CustomMessageHandler_AI.cs
5
+ 文件功能描述:自定义MessageHandler(AI 方法)
6
+
7
+
8
+ 创建标识:Senparc - 20240524
9
+
10
+ ----------------------------------------------------------------*/
11
+
12
+ using System ;
13
+ using System . Threading . Tasks ;
14
+ using Senparc . AI . Entities ;
15
+ using Senparc . AI . Kernel ;
16
+ using Senparc . CO2NET . Extensions ;
17
+ using Senparc . CO2NET . Helpers ;
18
+ using Senparc . CO2NET . Trace ;
19
+ using Senparc . NeuChar . Entities ;
20
+ using Senparc . Weixin . MP . Entities ;
21
+ using Senparc . Weixin . MP . Sample . CommonService . AI . MessageHandlers ;
22
+
23
+ namespace Senparc . Weixin . Sample . CommonService . CustomMessageHandler
24
+ {
25
+ /// <summary>
26
+ /// 自定义MessageHandler(公众号)
27
+ /// </summary>
28
+ public partial class CustomMessageHandler
29
+ {
30
+
31
+ const string WELCOME_MESSAGE = @"
32
+
33
+ 输入“p”暂停,可以暂时保留记忆
34
+ 输入“e”退出,彻底删除记忆
35
+
36
+ [结果由 AI 生成,仅供参考]" ;
37
+
38
+ /// <summary>
39
+ /// 开始 AI 对话
40
+ /// </summary>
41
+ /// <param name="requestMessage"></param>
42
+ /// <returns></returns>
43
+ private async Task < IResponseMessageBase > StartAIChatAsync ( )
44
+ {
45
+ var currentMessageContext = await base . GetCurrentMessageContext ( ) ;
46
+
47
+
48
+ //新建个人对话缓存(由于使用了 CurrentMessageContext,多用户之前完全隔离,对话不会串)
49
+ var storage = new ChatStore ( )
50
+ {
51
+ Status = ChatStatus . Chat ,
52
+ History = ""
53
+ } ;
54
+
55
+ currentMessageContext . StorageData = storage . ToJson ( ) ; //为了提升兼容性,采用字符格式
56
+
57
+ await GlobalMessageContext . UpdateMessageContextAsync ( currentMessageContext ) ; //储存到缓存
58
+
59
+ var responseMessage = base . CreateResponseMessage < ResponseMessageText > ( ) ;
60
+ responseMessage . Content = "小嗨 Bot 已启动!" + WELCOME_MESSAGE ;
61
+
62
+ return responseMessage ;
63
+ }
64
+
65
+ /// <summary>
66
+ /// 开始 AI 对话
67
+ /// </summary>
68
+ /// <param name="requestMessage"></param>
69
+ /// <returns></returns>
70
+ private async Task < IResponseMessageBase > AIChatAsync ( RequestMessageBase requestMessage )
71
+ {
72
+ var currentMessageContext = await base . GetCurrentMessageContext ( ) ;
73
+
74
+ if ( ! ( currentMessageContext . StorageData is string chatJson ) )
75
+ {
76
+ return null ;
77
+ }
78
+
79
+ ChatStore chatStore ;
80
+
81
+ try
82
+ {
83
+ chatStore = chatJson . GetObject < ChatStore > ( ) ;
84
+ if ( chatStore == null || chatStore . Status == ChatStatus . None || chatStore . History == null )
85
+ {
86
+ return null ;
87
+ }
88
+ }
89
+ catch
90
+ {
91
+ return null ;
92
+ }
93
+
94
+ try
95
+ {
96
+ if ( requestMessage is RequestMessageText requestMessageText )
97
+ {
98
+ string prompt ;
99
+
100
+ if ( requestMessageText . Content . Equals ( "E" , StringComparison . OrdinalIgnoreCase ) )
101
+ {
102
+ prompt = $ "我即将结束对话,请发送一段文字和我告别,并提醒我:输入“AI”可以再次启动对话。";
103
+
104
+ //消除状态记录
105
+ await UpdateMessageContext ( currentMessageContext , null ) ;
106
+ }
107
+ else if ( requestMessageText . Content . Equals ( "P" , StringComparison . OrdinalIgnoreCase ) )
108
+ {
109
+ prompt = $ "我即将临时暂停对话,请发送一段文字和我告别,并提醒我:输入“AI”可以再次启动对话。请记住,下次启动会话时,发送再次欢迎我回来的信息。";
110
+
111
+ // 修改状态记录
112
+ chatStore . Status = ChatStatus . Paused ;
113
+ await UpdateMessageContext ( currentMessageContext , chatStore ) ;
114
+ }
115
+ else if ( chatStore . Status == ChatStatus . Paused )
116
+ {
117
+ if ( requestMessageText . Content . Equals ( "AI" , StringComparison . OrdinalIgnoreCase ) )
118
+ {
119
+ prompt = @"我将重新开始对话,请发送一段欢迎信息,并且在最后提示我(注意保留换行):" + WELCOME_MESSAGE ;
120
+
121
+ // 修改状态记录
122
+ chatStore . Status = ChatStatus . Chat ;
123
+ await UpdateMessageContext ( currentMessageContext , chatStore ) ;
124
+ }
125
+ else
126
+ {
127
+ return null ;
128
+ }
129
+ }
130
+ else
131
+ {
132
+ prompt = requestMessageText . Content ;
133
+ }
134
+
135
+ #region 请求 AI 模型进入 Chat 的经典模式
136
+
137
+ /* 模型配置
138
+ * 注意:需要在 appsettings.json 中的 <SenparcAiSetting> 节点配置 AI 模型参数,否则无法使用 AI 能力
139
+ */
140
+ var setting = ( SenparcAiSetting ) Senparc . AI . Config . SenparcAiSetting ; //也可以留空,将自动获取
141
+
142
+ //模型请求参数
143
+ var parameter = new PromptConfigParameter ( )
144
+ {
145
+ MaxTokens = 2000 ,
146
+ Temperature = 0.7 ,
147
+ TopP = 0.5 ,
148
+ } ;
149
+
150
+ //最大保存 AI 对话记录数
151
+ var maxHistoryCount = 10 ;
152
+
153
+ //默认 SystemMessage(可根据自己需要修改)
154
+ var systemMessage = Senparc . AI . DefaultSetting . DEFAULT_SYSTEM_MESSAGE ;
155
+
156
+ var aiHandler = new SemanticAiHandler ( setting ) ;
157
+ var iWantToRun = aiHandler . ChatConfig ( parameter ,
158
+ userId : "Jeffrey" ,
159
+ maxHistoryStore : maxHistoryCount ,
160
+ chatSystemMessage : systemMessage ,
161
+ senparcAiSetting : setting ) . iWantToRun ;
162
+
163
+ //注入历史记录(也可以把 iWantToRun 对象缓存起来,其中会自动包含 history,不需要每次读取或者保存)
164
+ iWantToRun . StoredAiArguments . Context [ "history" ] = chatStore . History ;
165
+
166
+ //获取请求(注意:因为微信需要一次返回所有文本,所以此处不使用 AI 流行的 Stream(流式)输出
167
+ var result = await aiHandler . ChatAsync ( iWantToRun , prompt ) ;
168
+
169
+ #endregion
170
+
171
+
172
+ //保存历史记录
173
+ chatStore . History = iWantToRun . StoredAiArguments . Context [ "history" ] ? . ToString ( ) ;
174
+ await UpdateMessageContext ( currentMessageContext , chatStore ) ;
175
+
176
+ //组织返回消息
177
+ var responseMessage = base . CreateResponseMessage < ResponseMessageText > ( ) ;
178
+ responseMessage . Content = result . OutputString ;
179
+ return responseMessage ;
180
+ }
181
+ else
182
+ {
183
+ var responseMessage = base . CreateResponseMessage < ResponseMessageText > ( ) ;
184
+ responseMessage . Content = "暂时不支持此数据格式!" ;
185
+ return responseMessage ;
186
+ }
187
+ }
188
+ catch ( Exception ex )
189
+ {
190
+ SenparcTrace . BaseExceptionLog ( ex ) ;
191
+
192
+ var responseMessage = base . CreateResponseMessage < ResponseMessageText > ( ) ;
193
+ responseMessage . Content = "系统忙,请稍后再试!" ;
194
+ return responseMessage ;
195
+ }
196
+
197
+ }
198
+
199
+ private async Task UpdateMessageContext ( CustomMessageContext currentMessageContext , ChatStore chatStore )
200
+ {
201
+ currentMessageContext . StorageData = chatStore == null ? null : chatStore . ToJson ( ) ;
202
+ await GlobalMessageContext . UpdateMessageContextAsync ( currentMessageContext ) ; //储存到缓存
203
+ }
204
+ }
205
+ }
0 commit comments