Skip to content

Commit d5f0e81

Browse files
authored
Merge pull request #3166 from JeffreySu/Developer
Developer
2 parents 65df7a8 + 0445b97 commit d5f0e81

File tree

6 files changed

+196
-54
lines changed

6 files changed

+196
-54
lines changed

Samples/All/Senparc.Weixin.Sample.CommonService/AI/MessageHandlers/ChatStore.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
88
创建标识:Senparc - 20240524
99
10+
修改标识:Wang Qian - 20250728
11+
修改描述:为长对话模式的支持新增了LastStoredMemory、LastStoredPrompt、UseLongChat属性
12+
1013
----------------------------------------------------------------*/
1114

12-
using Microsoft.Extensions.AI;
1315
using Microsoft.SemanticKernel.ChatCompletion;
1416
using Senparc.AI.Kernel.Handlers;
1517
using System.Collections.Generic;
@@ -41,11 +43,27 @@ public class ChatStore
4143
/// </summary>
4244
public bool UseMarkdown { get; set; }
4345

46+
/// <summary>
47+
/// 是否使用长对话模式
48+
/// </summary>
49+
public bool UseLongChat { get; set; }
50+
51+
/// <summary>
52+
/// 上一次保存的记忆
53+
/// </summary>
54+
public string LastStoredMemory { get; set; }
55+
56+
/// <summary>
57+
/// 上一次提问的prompt
58+
/// </summary>
59+
public string LastStoredPrompt { get; set; }
60+
4461
public ChatStore()
4562
{
4663
Status = ChatStatus.None;
4764
MultimodelType = MultimodelType.None;
4865
UseMarkdown = true;
66+
UseLongChat = false;
4967
}
5068

5169
public ChatHistory GetChatHistory()
@@ -60,7 +78,7 @@ public ChatHistory GetChatHistory()
6078

6179
public void SetChatHistory(ChatHistory chatHistory)
6280
{
63-
if (chatHistory==null)
81+
if (chatHistory == null)
6482
{
6583
ClearHistory();
6684
}
@@ -126,4 +144,5 @@ public enum MultimodelType
126144
SimpleChat,
127145
ChatAndImage
128146
}
147+
129148
}

Samples/All/Senparc.Weixin.Sample.CommonService/AI/MessageHandlers/CustomMessageHandler_AI.cs

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
88
创建标识:Senparc - 20240524
99
10+
修改标识:Wang Qian - 20250728
11+
修改描述:新增AI对话功能增强特性:
12+
1. 新增"lc"命令:支持长对话模式,当对话达到10轮后自动整理记忆并清空历史
13+
2. 新增记忆整理功能:在长对话模式下,AI会自动总结对话内容并保存为记忆
14+
3. 优化欢迎消息:更新了功能说明,包含新增的命令使用说明
15+
1016
----------------------------------------------------------------*/
1117

1218
using System;
@@ -45,6 +51,7 @@ public partial class CustomMessageHandler
4551
输入“t”可以从多模态进入纯文本对话模式
4652
输入“img 文字”可以强制生成图片,例如:img 一只猫
4753
输入“dm”可以关闭Markdown格式输出,使用纯文本回复
54+
输入“lc”可以开启长对话模式,开启后,对话每到达最大历史对话轮数(默认10轮)后,会自动整理对话记忆,并清空对话历史,以支持长对话
4855
4956
[结果由 AI 生成,仅供参考]";
5057

@@ -118,6 +125,8 @@ private async Task<IResponseMessageBase> AIChatAsync(RequestMessageBase requestM
118125
bool judgeMultimodel = true;
119126
var oldChatStatus = chatStore.Status;
120127

128+
129+
121130
if (requestMessageText.Content.Equals("E", StringComparison.OrdinalIgnoreCase))
122131
{
123132
prompt = $"我即将结束对话,请发送一段文字和我告别,并提醒我:输入“AI”可以再次启动对话。";
@@ -172,12 +181,25 @@ private async Task<IResponseMessageBase> AIChatAsync(RequestMessageBase requestM
172181

173182
//返回提示
174183
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
175-
responseMessage.Content = useMarkdown
184+
responseMessage.Content = useMarkdown
176185
? "已恢复Markdown格式输出,输入dm可关闭Markdown格式输出"
177186
: "已关闭Markdown格式输出,使用纯文本回复,输入md可恢复Markdown格式输出";
178187
return responseMessage;
179188
}
180189

190+
Func<string, bool> longChatFunc = content => requestMessageText.Content.Equals(content, StringComparison.OrdinalIgnoreCase);
191+
192+
// 在对话、暂停状态下、可以切换长对话模式
193+
if (chatStore.Status == oldChatStatus && longChatFunc("LC"))
194+
{
195+
chatStore.UseLongChat = chatStore.UseLongChat ? false : true;
196+
await UpdateMessageContextAsync(currentMessageContext, chatStore);
197+
198+
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
199+
responseMessage.Content = chatStore.UseLongChat ? "已开启长对话模式!AI将在对话每到达最大历史对话轮数(默认10轮)后,会自动整理对话记忆,并清空对话历史,再次输入lc以关闭" : "已关闭长对话模式!AI将不再自动整理对话记忆,并清空对话历史,再次输入lc以开启";
200+
return responseMessage;
201+
}
202+
181203
if (chatStore.Status == oldChatStatus && chatStore.MultimodelType == MultimodelType.SimpleChat)// 在文字对话的状态下,才能切换到多模态对话
182204
{
183205
if (requestMessageText.Content.Equals("M", StringComparison.OrdinalIgnoreCase))
@@ -421,8 +443,16 @@ private async Task TextChatAsync(string prompt, ChatStore chatStore, bool storeH
421443
//最大保存 AI 对话记录数
422444
var maxHistoryCount = 10;
423445

424-
//默认 SystemMessage(可根据自己需要修改)
425-
var systemMessage = Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE;
446+
//如果是长对话模式,那么调用整理记忆函数,如果整理了记忆,那么使用整理后的记忆,则否则使用默认系统消息
447+
//在长对话模式情况下,如果还没有整理过记忆,那么返回值会是null,此时会使用默认系统消息
448+
//默认系统消息可以自己设置,也可以使用Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE
449+
var systemMessage = chatStore.UseLongChat ?
450+
await ConsolidateMemoryAsync(chatStore, chatStore.LastStoredPrompt) ?? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE
451+
:
452+
Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE;
453+
454+
//更新上一次prompt
455+
chatStore.LastStoredPrompt = prompt;
426456

427457
var aiHandler = new SemanticAiHandler(setting);
428458
var iWantToRun = aiHandler.ChatConfig(parameter,
@@ -505,5 +535,70 @@ public async Task<bool> JudgeMultimodel(RequestMessageText requestMessageText, C
505535
}
506536
return false;
507537
}
538+
539+
/// <summary>
540+
/// 整理记忆的方法
541+
/// </summary>
542+
/// <param name="chatStore"></param>
543+
/// <returns></returns>
544+
private async Task<string> ConsolidateMemoryAsync(ChatStore chatStore, string prompt)
545+
{
546+
var assistantMessageCount = chatStore.History.Count(h => h.Role == AuthorRole.Assistant);
547+
548+
//这里不进行是否使用长对话模式判断,因为判断是在TextChatAsync中进行的
549+
//如果AI消息条数大于等于9,则整理记忆,这里是9是因为Senparc.AI的消息最大条数处理逻辑稍有问题,所以暂时设置为9
550+
if (assistantMessageCount >= 9)
551+
{
552+
var memoryPrompt = @"
553+
请用简洁的语言总结:
554+
1. 用户的主要需求或关注点
555+
2. 重要的偏好或习惯
556+
3. 关键的信息点
557+
4. 之前聊天的内容
558+
";
559+
/* 模型配置
560+
* 注意:需要在 appsettings.json 中的 <SenparcAiSetting> 节点配置 AI 模型参数,否则无法使用 AI 能力
561+
*/
562+
var setting = (SenparcAiSetting)Senparc.AI.Config.SenparcAiSetting;//也可以留空,将自动获取
563+
564+
//模型请求参数
565+
var parameter = new PromptConfigParameter()
566+
{
567+
MaxTokens = 2000,
568+
Temperature = 0.3,
569+
TopP = 0.3,
570+
};
571+
572+
//最大保存 AI 对话记录数
573+
var maxHistoryCount = 10;
574+
575+
//使用上一轮的记忆作为SystemMessage
576+
var systemMessage = chatStore.LastStoredMemory == null ? Senparc.AI.DefaultSetting.DEFAULT_SYSTEM_MESSAGE : chatStore.LastStoredMemory;
577+
578+
var aiHandler = new SemanticAiHandler(setting);
579+
var iWantToRun = aiHandler.ChatConfig(parameter,
580+
userId: "Jeffrey",
581+
maxHistoryStore: maxHistoryCount,
582+
chatSystemMessage: systemMessage,
583+
senparcAiSetting: setting);
584+
585+
//注入历史记录(也可以把 iWantToRun 对象缓存起来,其中会自动包含 history,不需要每次读取或者保存)
586+
iWantToRun.StoredAiArguments.Context["history"] = chatStore.GetChatHistory();// AIKernl 的 history 为 ChatHistory 类型
587+
588+
var result = await aiHandler.ChatAsync(iWantToRun, memoryPrompt);
589+
590+
var memory = "用户之前的对话被概括为" + result.OutputString + "\n5.用户最近一次提问的内容是:" + prompt;
591+
592+
//更新chatStore中的上一轮记忆
593+
chatStore.LastStoredMemory = memory;
594+
595+
//清空历史记录
596+
chatStore.ClearHistory();
597+
return memory;
598+
}
599+
else return chatStore.LastStoredMemory;
600+
601+
602+
}
508603
}
509-
}
604+
}

Samples/All/Senparc.Weixin.Sample.CommonService/MessageHandlers/CustomMessageHandler/CustomMessageHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public override async Task<IResponseMessageBase> OnTextRequestAsync(RequestMessa
270270
* 这是一个特殊的过程,此请求通常来自于微微嗨(http://www.weiweihi.com)的“盛派网络小助手”应用请求(https://www.weiweihi.com/User/App/Detail/1),
271271
* 用于演示微微嗨应用商店的处理过程,由于微微嗨的应用内部可以单独设置对话过期时间,所以这里通常不需要考虑对话状态,只要做最简单的响应。
272272
*/
273-
if (defaultResponseMessage.Content == "测试")
273+
if (requestMessage.Content == "测试")
274274
{
275275
//进入APP测试
276276
defaultResponseMessage.Content = "您已经进入【盛派网络小助手】的测试程序,请发送任意信息进行测试。发送文字【退出】退出测试对话。10分钟内无任何交互将自动退出应用对话状态。";

Samples/All/Senparc.Weixin.Sample.CommonService/Senparc.Weixin.Net8SampleForConsole.CommonService.csproj

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
</ItemGroup>
2020

2121
<ItemGroup>
22-
<PackageReference Include="Senparc.AI.Kernel" Version="0.18.0" />
23-
<PackageReference Include="Senparc.NeuChar" Version="2.4.3" />
22+
<PackageReference Include="Senparc.AI.Kernel" Version="0.25.1" />
23+
<PackageReference Include="Senparc.NeuChar" Version="2.5.2" />
2424
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
25-
<PackageReference Include="Senparc.Weixin.TenPay" Version="1.16.3" />
25+
<PackageReference Include="Senparc.Weixin.TenPay" Version="1.17.8" />
2626
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
2727
<PackageReference Include="System.Diagnostics.FileVersionInfo" Version="4.3.0" />
2828
<PackageReference Include="ZXing.Net" Version="0.16.9" />
@@ -31,15 +31,15 @@
3131
<ItemGroup>
3232
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
3333
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
34-
<PackageReference Include="Senparc.WebSocket" Version="1.0.2" />
35-
<PackageReference Include="Senparc.Weixin.Cache.CsRedis" Version="1.0.2" />
36-
<PackageReference Include="Senparc.Weixin.Cache.Memcached" Version="2.17.3" />
37-
<PackageReference Include="Senparc.Weixin.Cache.Redis" Version="2.19.3" />
38-
<PackageReference Include="Senparc.Weixin.MP" Version="16.22.3" />
39-
<PackageReference Include="Senparc.Weixin.Open" Version="4.20.3" />
40-
<PackageReference Include="Senparc.Weixin.TenPayV3" Version="1.6.4" />
41-
<PackageReference Include="Senparc.Weixin.Work" Version="3.23.1" />
42-
<PackageReference Include="Senparc.Weixin.WxOpen" Version="3.20.4" />
34+
<PackageReference Include="Senparc.WebSocket" Version="1.1.8" />
35+
<PackageReference Include="Senparc.Weixin.Cache.CsRedis" Version="1.1.7" />
36+
<PackageReference Include="Senparc.Weixin.Cache.Memcached" Version="2.18.8" />
37+
<PackageReference Include="Senparc.Weixin.Cache.Redis" Version="2.20.8" />
38+
<PackageReference Include="Senparc.Weixin.MP" Version="16.23.8" />
39+
<PackageReference Include="Senparc.Weixin.Open" Version="4.22.1" />
40+
<PackageReference Include="Senparc.Weixin.TenPayV3" Version="2.1.1" />
41+
<PackageReference Include="Senparc.Weixin.Work" Version="3.28.0" />
42+
<PackageReference Include="Senparc.Weixin.WxOpen" Version="3.23.6" />
4343
</ItemGroup>
4444

4545

Samples/All/console/Senparc.Weixin.MP.Sample.Consoles/Program.cs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,29 @@ and limitations under the License.
4343
using Senparc.Weixin.MP;
4444
using Senparc.Weixin.RegisterServices;
4545

46+
var dt_Start = SystemTime.Now;
47+
4648
var builder = new ConfigurationBuilder();
47-
var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "Production";
49+
var environment = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT") ?? "";
4850

4951
builder.AddJsonFile("appsettings.json", false, true);
50-
builder.AddJsonFile($"appsettings.{environment}.json", false, true);
52+
if (environment.IsNullOrEmpty() is false)
53+
{
54+
builder.AddJsonFile($"appsettings.{environment}.json", false, true);
55+
}
5156
Console.WriteLine("完成 appsettings.json 添加");
5257

5358
var config = builder.Build();
5459
Console.WriteLine("完成 ServiceCollection 和 ConfigurationBuilder 初始化");
5560

5661
//更多绑定操作参见:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0
5762
var senparcSetting = config.GetSection("SenparcSetting").Get<SenparcSetting>();
58-
var senparcWeixinSetting = config.GetSection("SenparcWeixinSetting").Get< SenparcWeixinSetting>();
63+
var senparcWeixinSetting = config.GetSection("SenparcWeixinSetting").Get<SenparcWeixinSetting>();
5964

6065
var services = new ServiceCollection();
6166
services.AddMemoryCache();//使用本地缓存必须添加
6267

68+
var dt_AddSdkStart = SystemTime.Now;
6369

6470
#region 添加微信配置(一行代码)
6571

@@ -68,8 +74,13 @@ and limitations under the License.
6874

6975
#endregion
7076

77+
var dt_AddSdkEnd = SystemTime.Now;
78+
79+
7180
var app = builder.Build();
7281

82+
var dt_UseSdkStart = SystemTime.Now;
83+
7384
#region 启用微信配置(一句代码)
7485

7586
//手动获取配置信息可使用以下方法
@@ -88,14 +99,33 @@ and limitations under the License.
8899

89100
#endregion
90101

91-
//可以开始使用
102+
var dt_UseSdkEnd = SystemTime.Now;
103+
92104

105+
/* 开始使用
106+
* 此处可以添加高级接口(如推送消息)等业务逻辑,或添加监听
107+
*/
108+
109+
/*
93110
var weixinSetting = Senparc.Weixin.Config.SenparcWeixinSetting;
94111
95112
Console.WriteLine("## weixinSetting");
96113
Console.WriteLine(weixinSetting.ToJson(true, new Newtonsoft.Json.JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore }));
97114
Console.WriteLine();
98115
Console.WriteLine("## 【盛派网络小助手】公众号");
99116
Console.WriteLine(weixinSetting.Items["【盛派网络小助手】公众号"].ToJson(true));
117+
*/
118+
119+
Console.WriteLine();
120+
var totalMs = (dt_AddSdkEnd - dt_AddSdkStart).TotalMilliseconds + (dt_UseSdkEnd - dt_UseSdkStart).TotalSeconds.ToString("#.##");
121+
Console.WriteLine($"Senparc.Weixin SDK 已启动。");
122+
Console.WriteLine($"程序完整启动时间:{SystemTime.DiffTotalMS(dt_Start).ToString("#.##")}毫秒,其中 Senparc.Weixin SDK 启动总用时:{totalMs}毫秒");
123+
Console.WriteLine();
124+
Console.WriteLine("开源示例地址:https://github.com/JeffreySu/WeiXinMPSDK/tree/master/Samples/All/console");
125+
Console.WriteLine();
126+
Console.WriteLine("输入 exit 退出程序...");
100127

101-
Console.ReadLine();
128+
while (Console.ReadLine() != "exit")
129+
{
130+
continue;
131+
}

0 commit comments

Comments
 (0)