From 6d54c650f03ea9a713500819361988796ea6c02c Mon Sep 17 00:00:00 2001 From: ccnetcore Date: Sun, 1 Feb 2026 13:02:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B6=88=E6=81=AF=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E8=BF=94=E5=9B=9EID=E5=B9=B6=E5=9C=A8=E6=B5=81=E5=BC=8F?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E4=B8=AD=E4=B8=8B=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 消息管理器创建用户/系统消息时返回 MessageId - 网关在流式响应中新增消息创建事件,返回 MessageId 与创建时间 - 统一在消息创建完成后发送 [DONE] 标识,优化流式结束时机 --- .../Dtos/Chat/MessageCreatedOutput.cs | 47 +++++++++++++++++++ .../Managers/AiGateWayManager.cs | 36 ++++++++++---- .../Managers/AiMessageManager.cs | 6 ++- 3 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Chat/MessageCreatedOutput.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Chat/MessageCreatedOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Chat/MessageCreatedOutput.cs new file mode 100644 index 00000000..e0ec14f7 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Chat/MessageCreatedOutput.cs @@ -0,0 +1,47 @@ +using System.Reflection; +using System.Text.Json.Serialization; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Chat; + +/// +/// 消息创建结果输出 +/// +public class MessageCreatedOutput +{ + /// + /// 消息类型 + /// + [JsonIgnore] + public ChatMessageTypeEnum TypeEnum { get; set; } + + /// + /// 消息类型 + /// + public string Type => TypeEnum.ToString(); + + /// + /// 消息ID + /// + public Guid MessageId { get; set; } + + /// + /// 消息创建时间 + /// + public DateTime CreationTime { get; set; } +} + +/// +/// 消息类型枚举 +/// +public enum ChatMessageTypeEnum +{ + /// + /// 用户消息 + /// + UserMessage, + + /// + /// 系统消息 + /// + SystemMessage +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs index 0feb8e26..f789241a 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs @@ -23,6 +23,7 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Embeddings; using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Images; using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Responses; using Yi.Framework.AiHub.Domain.Shared.Enums; +using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat; using Yi.Framework.AiHub.Domain.Shared.Extensions; using Yi.Framework.Core.Extensions; using Yi.Framework.SqlSugarCore.Abstractions; @@ -1207,12 +1208,9 @@ public class AiGateWayManager : DomainService throw new UserFriendlyException($"不支持的API类型: {apiType}"); } - // 标记完成并等待消费任务结束 - isComplete = true; - await outputTask; - + // 统一的统计处理 - await _aiMessageManager.CreateUserMessageAsync(userId, sessionId, + var userMessageId = await _aiMessageManager.CreateUserMessageAsync(userId, sessionId, new MessageInputDto { Content = sessionId is null ? "不予存储" : processResult?.UserContent ?? string.Empty, @@ -1220,7 +1218,7 @@ public class AiGateWayManager : DomainService TokenUsage = processResult?.TokenUsage, }, tokenId,createTime:startTime); - await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId, + var systemMessageId = await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId, new MessageInputDto { Content = sessionId is null ? "不予存储" : processResult?.SystemContent ?? string.Empty, @@ -1228,6 +1226,29 @@ public class AiGateWayManager : DomainService TokenUsage = processResult?.TokenUsage }, tokenId); + // 流式返回消息ID + var now = DateTime.Now; + var userMessageOutput = new MessageCreatedOutput + { + TypeEnum = ChatMessageTypeEnum.UserMessage, + MessageId = userMessageId, + CreationTime = startTime + }; + messageQueue.Enqueue($"data: {JsonSerializer.Serialize(userMessageOutput, ThorJsonSerializer.DefaultOptions)}\n\n"); + + var systemMessageOutput = new MessageCreatedOutput + { + TypeEnum = ChatMessageTypeEnum.SystemMessage, + MessageId = systemMessageId, + CreationTime = now + }; + messageQueue.Enqueue($"data: {JsonSerializer.Serialize(systemMessageOutput, ThorJsonSerializer.DefaultOptions)}\n\n"); + + // 标记完成并等待消费任务结束 + messageQueue.Enqueue("data: [DONE]\n\n"); + isComplete = true; + await outputTask; + await _usageStatisticsManager.SetUsageAsync(userId, sourceModelId, processResult?.TokenUsage, tokenId); // 扣减尊享token包用量 @@ -1325,8 +1346,7 @@ public class AiGateWayManager : DomainService }); messageQueue.Enqueue($"data: {errorMessage}\n\n"); } - - messageQueue.Enqueue("data: [DONE]\n\n"); + return new StreamProcessResult { UserContent = userContent, diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiMessageManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiMessageManager.cs index b8310d66..90509246 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiMessageManager.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiMessageManager.cs @@ -24,11 +24,12 @@ public class AiMessageManager : DomainService /// 消息输入 /// Token Id(Web端传Guid.Empty) /// - public async Task CreateSystemMessageAsync(Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null) + public async Task CreateSystemMessageAsync(Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null) { input.Role = "system"; var message = new MessageAggregateRoot(userId, sessionId, input.Content, input.Role, input.ModelId, input.TokenUsage, tokenId); await _repository.InsertAsync(message); + return message.Id; } /// @@ -40,7 +41,7 @@ public class AiMessageManager : DomainService /// Token Id(Web端传Guid.Empty) /// /// - public async Task CreateUserMessageAsync( Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null,DateTime? createTime=null) + public async Task CreateUserMessageAsync( Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null,DateTime? createTime=null) { input.Role = "user"; var message = new MessageAggregateRoot(userId, sessionId, input.Content, input.Role, input.ModelId, input.TokenUsage, tokenId) @@ -48,5 +49,6 @@ public class AiMessageManager : DomainService CreationTime = createTime??DateTime.Now }; await _repository.InsertAsync(message); + return message.Id; } } \ No newline at end of file