fix: 修复 Anthropic TokenUsage 计算与流式响应的用量统计
This commit is contained in:
@@ -19,38 +19,6 @@ public class AnthropicStreamDto
|
||||
|
||||
[JsonPropertyName("error")] public AnthropicStreamErrorDto? Error { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public ThorUsageResponse TokenUsage => new ThorUsageResponse
|
||||
{
|
||||
PromptTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0,
|
||||
InputTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0,
|
||||
OutputTokens = Usage?.OutputTokens??0,
|
||||
InputTokensDetails = null,
|
||||
CompletionTokens = Usage?.OutputTokens??0,
|
||||
TotalTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0 +
|
||||
Usage?.OutputTokens??0,
|
||||
PromptTokensDetails = null,
|
||||
CompletionTokensDetails = null
|
||||
};
|
||||
|
||||
|
||||
public void SupplementalMultiplier(decimal multiplier)
|
||||
{
|
||||
if (this.Usage is not null)
|
||||
{
|
||||
this.Usage.CacheCreationInputTokens =
|
||||
(int)Math.Round((this.Usage.CacheCreationInputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.CacheReadInputTokens =
|
||||
(int)Math.Round((this.Usage.CacheReadInputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.InputTokens =
|
||||
(int)Math.Round((this.Usage.InputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.OutputTokens =
|
||||
(int)Math.Round((this.Usage.OutputTokens ?? 0) * multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AnthropicStreamErrorDto
|
||||
@@ -116,37 +84,6 @@ public class AnthropicChatCompletionDto
|
||||
|
||||
public AnthropicCompletionDtoUsage? Usage { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public ThorUsageResponse TokenUsage => new ThorUsageResponse
|
||||
{
|
||||
PromptTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0,
|
||||
InputTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0,
|
||||
OutputTokens = Usage?.OutputTokens??0,
|
||||
InputTokensDetails = null,
|
||||
CompletionTokens = Usage?.OutputTokens??0,
|
||||
TotalTokens = Usage?.InputTokens??0 + Usage?.CacheCreationInputTokens??0 + Usage?.CacheReadInputTokens??0 +
|
||||
Usage?.OutputTokens??0,
|
||||
PromptTokensDetails = null,
|
||||
CompletionTokensDetails = null
|
||||
};
|
||||
|
||||
public void SupplementalMultiplier(decimal multiplier)
|
||||
{
|
||||
if (this.Usage is not null)
|
||||
{
|
||||
this.Usage.CacheCreationInputTokens =
|
||||
(int)Math.Round((this.Usage?.CacheCreationInputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.CacheReadInputTokens =
|
||||
(int)Math.Round((this.Usage?.CacheReadInputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.InputTokens =
|
||||
(int)Math.Round((this.Usage?.InputTokens ?? 0) * multiplier);
|
||||
|
||||
this.Usage.OutputTokens =
|
||||
(int)Math.Round((this.Usage?.OutputTokens ?? 0) * multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AnthropicChatCompletionDtoContent
|
||||
|
||||
@@ -549,7 +549,16 @@ public class AiGateWayManager : DomainService
|
||||
LazyServiceProvider.GetRequiredKeyedService<IAnthropicChatCompletionService>(modelDescribe.HandlerName);
|
||||
var data = await chatService.ChatCompletionsAsync(modelDescribe, request, cancellationToken);
|
||||
|
||||
data.SupplementalMultiplier(modelDescribe.Multiplier);
|
||||
var currentUsage = data.Usage;
|
||||
ThorUsageResponse tokenUsage = new ThorUsageResponse
|
||||
{
|
||||
InputTokens = (currentUsage?.InputTokens??0) + (currentUsage?.CacheCreationInputTokens??0)+ (currentUsage?.CacheReadInputTokens??0),
|
||||
OutputTokens = (currentUsage?.OutputTokens??0),
|
||||
TotalTokens = (currentUsage?.InputTokens??0) + (currentUsage?.CacheCreationInputTokens??0)+ (currentUsage?.CacheReadInputTokens??0)+(currentUsage?.OutputTokens??0)
|
||||
};
|
||||
|
||||
|
||||
tokenUsage.SetSupplementalMultiplier(modelDescribe.Multiplier);
|
||||
|
||||
if (userId is not null)
|
||||
{
|
||||
@@ -558,7 +567,7 @@ public class AiGateWayManager : DomainService
|
||||
{
|
||||
Content = "不予存储",
|
||||
ModelId = sourceModelId,
|
||||
TokenUsage = data.TokenUsage,
|
||||
TokenUsage = tokenUsage,
|
||||
}, tokenId);
|
||||
|
||||
await _aiMessageManager.CreateSystemMessageAsync(userId.Value, sessionId,
|
||||
@@ -566,13 +575,13 @@ public class AiGateWayManager : DomainService
|
||||
{
|
||||
Content = "不予存储",
|
||||
ModelId = sourceModelId,
|
||||
TokenUsage = data.TokenUsage
|
||||
TokenUsage = tokenUsage
|
||||
}, tokenId);
|
||||
|
||||
await _usageStatisticsManager.SetUsageAsync(userId.Value, sourceModelId, data.TokenUsage, tokenId);
|
||||
await _usageStatisticsManager.SetUsageAsync(userId.Value, sourceModelId, tokenUsage, tokenId);
|
||||
|
||||
// 直接扣减尊享token包用量
|
||||
var totalTokens = data.TokenUsage.TotalTokens ?? 0;
|
||||
var totalTokens = tokenUsage.TotalTokens ?? 0;
|
||||
if (totalTokens > 0)
|
||||
{
|
||||
await PremiumPackageManager.TryConsumeTokensAsync(userId.Value, totalTokens);
|
||||
@@ -620,24 +629,41 @@ public class AiGateWayManager : DomainService
|
||||
}
|
||||
|
||||
var completeChatResponse = chatService.StreamChatCompletionsAsync(modelDescribe, request, cancellationToken);
|
||||
ThorUsageResponse? tokenUsage = null;
|
||||
StringBuilder backupSystemContent = new StringBuilder();
|
||||
ThorUsageResponse? tokenUsage = new ThorUsageResponse();
|
||||
try
|
||||
{
|
||||
await foreach (var responseResult in completeChatResponse)
|
||||
{
|
||||
responseResult.Item2.SupplementalMultiplier(modelDescribe.Multiplier);
|
||||
//message_start是为了保底机制
|
||||
if (responseResult.Item1.Contains("message_delta") || responseResult.Item1.Contains("message_start")||responseResult.Item1.Contains("message_stop"))
|
||||
//部分供应商message_start放一部分
|
||||
if (responseResult.Item1.Contains("message_start"))
|
||||
{
|
||||
if (responseResult.Item2?.TokenUsage is not null&&responseResult.Item2?.TokenUsage.TotalTokens>0)
|
||||
var currentTokenUsage = responseResult.Item2.Message.Usage;
|
||||
if ((currentTokenUsage.InputTokens ?? 0) != 0)
|
||||
{
|
||||
tokenUsage = responseResult.Item2?.TokenUsage;
|
||||
tokenUsage.InputTokens = (currentTokenUsage?.InputTokens??0) + (currentTokenUsage?.CacheCreationInputTokens??0)+ (currentTokenUsage?.CacheReadInputTokens??0);
|
||||
}
|
||||
if ((currentTokenUsage.OutputTokens ?? 0) != 0)
|
||||
{
|
||||
tokenUsage.OutputTokens = currentTokenUsage.OutputTokens;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
backupSystemContent.Append(responseResult.Item2?.Delta?.Text);
|
||||
//message_delta又放一部分
|
||||
if (responseResult.Item1.Contains("message_delta"))
|
||||
{
|
||||
var currentTokenUsage = responseResult.Item2.Usage;
|
||||
|
||||
if ((currentTokenUsage.InputTokens ?? 0) != 0)
|
||||
{
|
||||
tokenUsage.InputTokens = (currentTokenUsage?.InputTokens??0) + (currentTokenUsage?.CacheCreationInputTokens??0)+ (currentTokenUsage?.CacheReadInputTokens??0);;
|
||||
}
|
||||
if ((currentTokenUsage.OutputTokens ?? 0) != 0)
|
||||
{
|
||||
tokenUsage.OutputTokens = currentTokenUsage.OutputTokens;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
await WriteAsEventStreamDataAsync(httpContext, responseResult.Item1, responseResult.Item2,
|
||||
cancellationToken);
|
||||
}
|
||||
@@ -648,7 +674,8 @@ public class AiGateWayManager : DomainService
|
||||
var errorContent = $"对话Ai异常,异常信息:\n当前Ai模型:{sourceModelId}\n异常信息:{e.Message}\n异常堆栈:{e}";
|
||||
throw new UserFriendlyException(errorContent);
|
||||
}
|
||||
|
||||
tokenUsage.TotalTokens = (tokenUsage.InputTokens ?? 0) + (tokenUsage.OutputTokens ?? 0);
|
||||
tokenUsage.SetSupplementalMultiplier(modelDescribe.Multiplier);
|
||||
await _aiMessageManager.CreateUserMessageAsync(userId, sessionId,
|
||||
new MessageInputDto
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user