feat: 支持消息自定义创建时间并完善TokenUsage初始化

- 用户消息创建支持传入创建时间,用于统计与回放
- TokenUsage 为空时自动初始化,避免空引用问题
- 网关记录消息开始时间并传递至消息管理器
- 标记并停用旧的发送消息接口
- 前端版本号更新至 3.6
- 移除未使用的 VITE_BUILD_COMPRESS 类型声明
This commit is contained in:
ccnetcore
2026-01-31 21:22:09 +08:00
parent 007a4c223a
commit dbc6b8cf5e
6 changed files with 67 additions and 53 deletions

View File

@@ -127,54 +127,55 @@ public class AiChatService : ApplicationService
} }
/// <summary> // /// <summary>
/// 发送消息 // /// 发送消息
/// </summary> // /// </summary>
/// <param name="input"></param> // /// <param name="input"></param>
/// <param name="sessionId"></param> // /// <param name="sessionId"></param>
/// <param name="cancellationToken"></param> // /// <param name="cancellationToken"></param>
[HttpPost("ai-chat/send")] // [HttpPost("ai-chat/send")]
public async Task PostSendAsync([FromBody] ThorChatCompletionsRequest input, [FromQuery] Guid? sessionId, // [Obsolete]
CancellationToken cancellationToken) // public async Task PostSendAsync([FromBody] ThorChatCompletionsRequest input, [FromQuery] Guid? sessionId,
{ // CancellationToken cancellationToken)
//除了免费模型,其他的模型都要校验 // {
if (input.Model!=FreeModelId) // //除了免费模型,其他的模型都要校验
{ // if (input.Model!=FreeModelId)
//有token需要黑名单校验 // {
if (CurrentUser.IsAuthenticated) // //有token需要黑名单校验
{ // if (CurrentUser.IsAuthenticated)
await _aiBlacklistManager.VerifiyAiBlacklist(CurrentUser.GetId()); // {
if (!CurrentUser.IsAiVip()) // await _aiBlacklistManager.VerifiyAiBlacklist(CurrentUser.GetId());
{ // if (!CurrentUser.IsAiVip())
throw new UserFriendlyException("该模型需要VIP用户才能使用请购买VIP后重新登录重试"); // {
} // throw new UserFriendlyException("该模型需要VIP用户才能使用请购买VIP后重新登录重试");
} // }
else // }
{ // else
throw new UserFriendlyException("未登录用户只能使用未加速的DeepSeek-R1请登录后重试"); // {
} // throw new UserFriendlyException("未登录用户只能使用未加速的DeepSeek-R1请登录后重试");
} // }
// }
//如果是尊享包服务,需要校验是是否尊享包足够 //
if (CurrentUser.IsAuthenticated) // //如果是尊享包服务,需要校验是是否尊享包足够
{ // if (CurrentUser.IsAuthenticated)
var isPremium = await _modelManager.IsPremiumModelAsync(input.Model); // {
// var isPremium = await _modelManager.IsPremiumModelAsync(input.Model);
if (isPremium) //
{ // if (isPremium)
// 检查尊享token包用量 // {
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(CurrentUser.GetId()); // // 检查尊享token包用量
if (availableTokens <= 0) // var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(CurrentUser.GetId());
{ // if (availableTokens <= 0)
throw new UserFriendlyException("尊享token包用量不足请先购买尊享token包"); // {
} // throw new UserFriendlyException("尊享token包用量不足请先购买尊享token包");
} // }
} // }
// }
//ai网关代理httpcontext //
await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input, // //ai网关代理httpcontext
CurrentUser.Id, sessionId, null, CancellationToken.None); // await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
} // CurrentUser.Id, sessionId, null, CancellationToken.None);
// }
/// <summary> /// <summary>
/// 发送消息 /// 发送消息

View File

@@ -53,6 +53,15 @@ public class MessageAggregateRoot : FullAuditedAggregateRoot<Guid>
TotalTokenCount = tokenUsage.TotalTokens ?? 0 TotalTokenCount = tokenUsage.TotalTokens ?? 0
}; };
} }
else
{
this.TokenUsage = new TokenUsageValueObject
{
OutputTokenCount = 0,
InputTokenCount = 0,
TotalTokenCount = 0
};
}
this.MessageType = sessionId is null ? MessageTypeEnum.Api : MessageTypeEnum.Web; this.MessageType = sessionId is null ? MessageTypeEnum.Api : MessageTypeEnum.Web;
} }

View File

@@ -1143,6 +1143,7 @@ public class AiGateWayManager : DomainService
Guid? tokenId = null, Guid? tokenId = null,
CancellationToken cancellationToken = default) CancellationToken cancellationToken = default)
{ {
var startTime = DateTime.Now;
var response = httpContext.Response; var response = httpContext.Response;
// 设置响应头,声明是 SSE 流 // 设置响应头,声明是 SSE 流
response.ContentType = "text/event-stream;charset=utf-8;"; response.ContentType = "text/event-stream;charset=utf-8;";
@@ -1217,7 +1218,7 @@ public class AiGateWayManager : DomainService
Content = sessionId is null ? "不予存储" : processResult?.UserContent ?? string.Empty, Content = sessionId is null ? "不予存储" : processResult?.UserContent ?? string.Empty,
ModelId = sourceModelId, ModelId = sourceModelId,
TokenUsage = processResult?.TokenUsage, TokenUsage = processResult?.TokenUsage,
}, tokenId); }, tokenId,createTime:startTime);
await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId, await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId,
new MessageInputDto new MessageInputDto

View File

@@ -38,11 +38,15 @@ public class AiMessageManager : DomainService
/// <param name="sessionId">会话Id</param> /// <param name="sessionId">会话Id</param>
/// <param name="input">消息输入</param> /// <param name="input">消息输入</param>
/// <param name="tokenId">Token IdWeb端传Guid.Empty</param> /// <param name="tokenId">Token IdWeb端传Guid.Empty</param>
/// <param name="createTime"></param>
/// <returns></returns> /// <returns></returns>
public async Task CreateUserMessageAsync(Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null) public async Task CreateUserMessageAsync( Guid? userId, Guid? sessionId, MessageInputDto input, Guid? tokenId = null,DateTime? createTime=null)
{ {
input.Role = "user"; input.Role = "user";
var message = new MessageAggregateRoot(userId, sessionId, input.Content, input.Role, input.ModelId, input.TokenUsage, tokenId); var message = new MessageAggregateRoot(userId, sessionId, input.Content, input.Role, input.ModelId, input.TokenUsage, tokenId)
{
CreationTime = createTime??DateTime.Now
};
await _repository.InsertAsync(message); await _repository.InsertAsync(message);
} }
} }

View File

@@ -112,7 +112,7 @@
<body> <body>
<!-- 加载动画容器 --> <!-- 加载动画容器 -->
<div id="yixinai-loader" class="loader-container"> <div id="yixinai-loader" class="loader-container">
<div class="loader-title">意心Ai 3.5</div> <div class="loader-title">意心Ai 3.6</div>
<div class="loader-subtitle">海外地址仅首次访问预计加载约10秒无需梯子</div> <div class="loader-subtitle">海外地址仅首次访问预计加载约10秒无需梯子</div>
<div class="loader-logo"> <div class="loader-logo">
<div class="pulse-box"></div> <div class="pulse-box"></div>

View File

@@ -7,7 +7,6 @@ interface ImportMetaEnv {
readonly VITE_WEB_BASE_API: string; readonly VITE_WEB_BASE_API: string;
readonly VITE_API_URL: string; readonly VITE_API_URL: string;
readonly VITE_FILE_UPLOAD_API: string; readonly VITE_FILE_UPLOAD_API: string;
readonly VITE_BUILD_COMPRESS: string;
readonly VITE_SSO_SEVER_URL: string; readonly VITE_SSO_SEVER_URL: string;
readonly VITE_APP_VERSION: string; readonly VITE_APP_VERSION: string;
} }