Merge pull request #41 from AIDotNet/feature_chathistory

Feature chathistory
This commit is contained in:
zyxucp
2024-03-24 23:12:45 +08:00
committed by GitHub
8 changed files with 81 additions and 110 deletions

View File

@@ -104,7 +104,7 @@
避免模型重复加载,本地缓存
</summary>
</member>
<member name="M:AntSK.Domain.Domain.Service.ChatService.SendChatByAppAsync(AntSK.Domain.Repositories.Apps,System.String,System.String)">
<member name="M:AntSK.Domain.Domain.Service.ChatService.SendChatByAppAsync(AntSK.Domain.Repositories.Apps,System.String,Microsoft.SemanticKernel.ChatCompletion.ChatHistory)">
<summary>
发送消息
</summary>

View File

@@ -1,6 +1,8 @@
using AntSK.Domain.Domain.Model.Dto;
using AntSK.Domain.Domain.Model;
using AntSK.Domain.Domain.Model.Dto;
using AntSK.Domain.Repositories;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,8 +13,10 @@ namespace AntSK.Domain.Domain.Interface
{
public interface IChatService
{
IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, string history);
IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, ChatHistory history);
IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, string history, string filePath, List<RelevantSource> relevantSources = null);
IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null);
Task<ChatHistory> GetChatHistory(List<MessageInfo> MessageList);
}
}

View File

@@ -12,6 +12,10 @@ using System.Reflection.Metadata;
using Microsoft.KernelMemory;
using System.Collections.Generic;
using Markdig;
using ChatHistory = Microsoft.SemanticKernel.ChatCompletion.ChatHistory;
using Microsoft.SemanticKernel.Plugins.Core;
using Azure.Core;
using AntSK.Domain.Domain.Model;
namespace AntSK.Domain.Domain.Service
{
@@ -29,13 +33,31 @@ namespace AntSK.Domain.Domain.Service
/// <param name="questions"></param>
/// <param name="history"></param>
/// <returns></returns>
public async IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, string history)
public async IAsyncEnumerable<StreamingKernelContent> SendChatByAppAsync(Apps app, string questions, ChatHistory history)
{
if (string.IsNullOrEmpty(app.Prompt) || !app.Prompt.Contains("{{$input}}"))
{
//如果模板为空,给默认提示词
app.Prompt = app.Prompt.ConvertToString() + "{{$input}}";
}
KernelArguments args =new KernelArguments();
if (history.Count > 10)
{
app.Prompt = @"${{ConversationSummaryPlugin.SummarizeConversation $history}}" + app.Prompt;
args = new() {
{ "history", string.Join("\n", history.Select(x => x.Role + ": " + x.Content)) },
{ "input", questions }
};
}
else
{
args=new()
{
{ "input", $"{string.Join("\n", history.Select(x => x.Role + ": " + x.Content))}{Environment.NewLine} user:{questions}" }
};
}
var _kernel = _kernelService.GetKernelByApp(app);
var temperature = app.Temperature / 100;//存的是0~100需要缩小
OpenAIPromptExecutionSettings settings = new() { Temperature = temperature };
@@ -45,14 +67,15 @@ namespace AntSK.Domain.Domain.Service
settings.ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions;
}
var func = _kernel.CreateFunctionFromPrompt(app.Prompt, settings);
var chatResult = _kernel.InvokeStreamingAsync(function: func, arguments: new KernelArguments() { ["input"] = $"{history}{Environment.NewLine} user:{questions}" });
var chatResult = _kernel.InvokeStreamingAsync(function: func,
arguments: args);
await foreach (var content in chatResult)
{
yield return content;
}
}
public async IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, string history, string filePath, List<RelevantSource> relevantSources = null)
public async IAsyncEnumerable<StreamingKernelContent> SendKmsByAppAsync(Apps app, string questions, ChatHistory history, string filePath, List<RelevantSource> relevantSources = null)
{
var relevantSourceList = await _kMService.GetRelevantSourceList(app.KmsIdList, questions);
var _kernel = _kernelService.GetKernelByApp(app);
@@ -84,9 +107,9 @@ namespace AntSK.Domain.Domain.Service
dataMsg.AppendLine(item.ToString());
}
KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask");
KernelFunction jsonFun = _kernel.Plugins.GetFunction("KMSPlugin", "Ask1");
var chatResult = _kernel.InvokeStreamingAsync(function: jsonFun,
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = history, ["questions"] = questions });
arguments: new KernelArguments() { ["doc"] = dataMsg, ["history"] = string.Join("\n", history.Select(x => x.Role + ": " + x.Content)), ["questions"] = questions });
await foreach (var content in chatResult)
{
@@ -98,5 +121,26 @@ namespace AntSK.Domain.Domain.Service
yield return new StreamingTextContent(KmsConstantcs.KmsSearchNull);
}
}
public async Task<ChatHistory> GetChatHistory(List<MessageInfo> MessageList)
{
ChatHistory history = new ChatHistory();
if (MessageList.Count > 1)
{
foreach (var item in MessageList)
{
if (item.IsSend)
{
history.AddUserMessage(item.Context);
}
else
{
history.AddAssistantMessage(item.Context);
}
}
}
return history;
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Text;
using Markdig;
using AntSK.Domain.Domain.Model;
using AntSK.Domain.Domain.Model.Dto;
using Microsoft.SemanticKernel.ChatCompletion;
namespace AntSK.Pages.ChatPage
{
@@ -121,24 +122,24 @@ namespace AntSK.Pages.ChatPage
protected async Task<bool> SendAsync(string questions, string? filePath)
{
string msg = "";
ChatHistory history = new ChatHistory() ;
//处理多轮会话
Apps app = _apps_Repositories.GetFirst(p => p.Id == AppId);
if (MessageList.Count > 0)
{
msg = await HistorySummarize(app, questions);
history = await _chatService.GetChatHistory(MessageList);
}
switch (app.Type)
{
case "chat" when filePath == null:
//普通会话
await SendChat(questions, msg, app);
await SendChat(questions, history, app);
break;
default:
//知识库问答
await SendKms(questions, msg, filePath, app);
await SendKms(questions, history, filePath, app);
break;
}
@@ -149,14 +150,14 @@ namespace AntSK.Pages.ChatPage
/// 发送知识库问答
/// </summary>
/// <param name="questions"></param>
/// <param name="msg"></param>
/// <param name="history"></param>
/// <param name="filePath"></param>
/// <param name="app"></param>
/// <returns></returns>
private async Task SendKms(string questions, string msg, string filePath, Apps app)
private async Task SendKms(string questions, ChatHistory history, string filePath, Apps app)
{
MessageInfo info = null;
var chatResult = _chatService.SendKmsByAppAsync(app, questions, msg, filePath, _relevantSources);
var chatResult = _chatService.SendKmsByAppAsync(app, questions, history, filePath, _relevantSources);
await foreach (var content in chatResult)
{
if (info == null)
@@ -189,7 +190,7 @@ namespace AntSK.Pages.ChatPage
/// <param name="history"></param>
/// <param name="app"></param>
/// <returns></returns>
private async Task SendChat(string questions, string history, Apps app)
private async Task SendChat(string questions, ChatHistory history, Apps app)
{
MessageInfo info = null;
var chatResult = _chatService.SendChatByAppAsync(app, questions, history);
@@ -222,6 +223,7 @@ namespace AntSK.Pages.ChatPage
{
if (info.IsNotNull())
{
info!.Context = info!.HtmlAnswers;
// info!.HtmlAnswers = markdown.Transform(info.HtmlAnswers);
info!.HtmlAnswers = Markdown.ToHtml(info.HtmlAnswers);
}
@@ -231,48 +233,6 @@ namespace AntSK.Pages.ChatPage
await _JSRuntime.ScrollToBottomAsync("scrollDiv");
}
/// <summary>
/// 历史会话的会话总结
/// </summary>
/// <param name="questions"></param>
/// <returns></returns>
private async Task<string> HistorySummarize(Apps app, string questions)
{
var _kernel = _kernelService.GetKernelByApp(app);
if (MessageList.Count > 1)
{
StringBuilder history = new StringBuilder();
foreach (var item in MessageList)
{
if (item.IsSend)
{
history.Append($"user:{item.Context}{Environment.NewLine}");
}
else
{
history.Append($"assistant:{item.Context}{Environment.NewLine}");
}
}
if (MessageList.Count > 10)
{
//历史会话大于10条进行总结
var msg = await _kernelService.HistorySummarize(_kernel, questions, history.ToString());
return msg;
}
else
{
var msg =
$"history{Environment.NewLine}{history.ToString()}{Environment.NewLine}{Environment.NewLine}";
return msg;
}
}
else
{
return "";
}
}
private void OnSingleCompleted(UploadInfo fileInfo)
{
fileList.Add(new()

View File

@@ -12,6 +12,7 @@ using AntSK.Domain.Utils;
using Microsoft.JSInterop;
using Markdig;
using AntSK.Domain.Domain.Model;
using Microsoft.SemanticKernel.ChatCompletion;
namespace AntSK.Pages.ChatPage
{
@@ -120,22 +121,22 @@ namespace AntSK.Pages.ChatPage
protected async Task<bool> SendAsync(string questions)
{
string msg = "";
ChatHistory history=new ChatHistory();
//处理多轮会话
Apps app = _apps_Repositories.GetFirst(p => p.Id == AppId);
if (MessageList.Count > 0)
{
msg = await HistorySummarize(app, questions);
history = await _chatService.GetChatHistory(MessageList);
}
switch (app.Type)
{
case "chat":
//普通会话
await SendChat(questions, msg, app);
await SendChat(questions, history, app);
break;
case "kms":
//知识库问答
await SendKms(questions, msg, app);
await SendKms(questions, history, app);
break;
}
@@ -149,10 +150,10 @@ namespace AntSK.Pages.ChatPage
/// <param name="msg"></param>
/// <param name="app"></param>
/// <returns></returns>
private async Task SendKms(string questions, string msg, Apps app)
private async Task SendKms(string questions, ChatHistory history, Apps app)
{
MessageInfo info = null;
var chatResult=_chatService.SendKmsByAppAsync(app, questions, "" ,msg);
var chatResult=_chatService.SendKmsByAppAsync(app, questions, history, "" );
await foreach (var content in chatResult)
{
if (info == null)
@@ -183,7 +184,7 @@ namespace AntSK.Pages.ChatPage
/// <param name="history"></param>
/// <param name="app"></param>
/// <returns></returns>
private async Task SendChat(string questions, string history, Apps app)
private async Task SendChat(string questions, ChatHistory history, Apps app)
{
MessageInfo info = null;
var chatResult = _chatService.SendChatByAppAsync(app, questions, history);
@@ -221,45 +222,6 @@ namespace AntSK.Pages.ChatPage
await InvokeAsync(StateHasChanged);
await _JSRuntime.InvokeVoidAsync("Prism.highlightAll");
await _JSRuntime.ScrollToBottomAsync("scrollDiv");
}
/// <summary>
/// 历史会话的会话总结
/// </summary>
/// <param name="questions"></param>
/// <returns></returns>
private async Task<string> HistorySummarize(Apps app, string questions)
{
var _kernel = _kernelService.GetKernelByApp(app);
if (MessageList.Count > 1)
{
StringBuilder history = new StringBuilder();
foreach (var item in MessageList)
{
if (item.IsSend)
{
history.Append($"user:{item.Context}{Environment.NewLine}");
}
else
{
history.Append($"assistant:{item.Context}{Environment.NewLine}");
}
}
if (MessageList.Count > 10)
{
//历史会话大于10条进行总结
var msg = await _kernelService.HistorySummarize(_kernel, questions, history.ToString());
return msg;
}
else
{
var msg = $"history{history.ToString()}{Environment.NewLine} user{questions}"; ;
return msg;
}
}
else
{
return "";
}
}
}
}
}

View File

@@ -5,6 +5,7 @@ using AntSK.Domain.Repositories;
using AntSK.Domain.Utils;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Newtonsoft.Json;
using System.Text;
@@ -99,7 +100,7 @@ namespace AntSK.Services.OpenApi
private async Task SendChatStream(HttpContext HttpContext, OpenAIStreamResult result, Apps app, string msg)
{
HttpContext.Response.Headers.Add("Content-Type", "text/event-stream");
var chatResult = _chatService.SendChatByAppAsync(app, msg, "");
var chatResult = _chatService.SendChatByAppAsync(app, msg, new ChatHistory());
await foreach (var content in chatResult)
{
result.choices[0].delta.content = content.ConvertToString();
@@ -154,7 +155,7 @@ namespace AntSK.Services.OpenApi
private async Task SendKmsStream(HttpContext HttpContext, OpenAIStreamResult result, Apps app, string msg)
{
HttpContext.Response.Headers.Add("Content-Type", "text/event-stream");
var chatResult = _chatService.SendKmsByAppAsync(app, msg,"", "");
var chatResult = _chatService.SendKmsByAppAsync(app, msg,new ChatHistory(), "");
int i = 0;
await foreach (var content in chatResult)
{

View File

@@ -1,7 +1,7 @@
Facts:
{{$doc}}
--------------------------
History:{{$history}}
History:{{ConversationSummaryPlugin.SummarizeConversation $history}}
--------------------------
Question: {{$questions}}
--------------------------

View File

@@ -11,7 +11,7 @@
- 如果Markdown有图片则正常显示
--------------------------
历史聊天记录:{{$history}}
历史聊天记录:{{ConversationSummaryPlugin.SummarizeConversation $history}}
--------------------------
用户问题: {{$questions}}