feat: 增加 Claude 模型 Token 使用量倍数调整功能
This commit is contained in:
@@ -32,6 +32,25 @@ public class AnthropicStreamDto
|
|||||||
PromptTokensDetails = null,
|
PromptTokensDetails = null,
|
||||||
CompletionTokensDetails = null
|
CompletionTokensDetails = null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public void SupplementalMultiplier(double 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
|
public class AnthropicStreamErrorDto
|
||||||
@@ -93,7 +112,7 @@ public class AnthropicChatCompletionDto
|
|||||||
|
|
||||||
public object stop_sequence { get; set; }
|
public object stop_sequence { get; set; }
|
||||||
|
|
||||||
public AnthropicCompletionDtoUsage Usage { get; set; }
|
public AnthropicCompletionDtoUsage? Usage { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ThorUsageResponse TokenUsage => new ThorUsageResponse
|
public ThorUsageResponse TokenUsage => new ThorUsageResponse
|
||||||
@@ -108,6 +127,24 @@ public class AnthropicChatCompletionDto
|
|||||||
PromptTokensDetails = null,
|
PromptTokensDetails = null,
|
||||||
CompletionTokensDetails = null
|
CompletionTokensDetails = null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public void SupplementalMultiplier(double 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
|
public class AnthropicChatCompletionDtoContent
|
||||||
|
|||||||
@@ -60,4 +60,19 @@ public record ThorChatCompletionsResponse
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("error")]
|
[JsonPropertyName("error")]
|
||||||
public ThorError? Error { get; set; }
|
public ThorError? Error { get; set; }
|
||||||
|
|
||||||
|
public void SupplementalMultiplier(double multiplier)
|
||||||
|
{
|
||||||
|
if (this.Usage is not null)
|
||||||
|
{
|
||||||
|
this.Usage.InputTokens =
|
||||||
|
(int)Math.Round((this.Usage.InputTokens ?? 0) * multiplier);
|
||||||
|
this.Usage.OutputTokens =
|
||||||
|
(int)Math.Round((this.Usage.OutputTokens ?? 0) * multiplier);
|
||||||
|
this.Usage.CompletionTokens =
|
||||||
|
(int)Math.Round((this.Usage.CompletionTokens ?? 0) * multiplier);
|
||||||
|
this.Usage.PromptTokens =
|
||||||
|
(int)Math.Round((this.Usage.PromptTokens ?? 0) * multiplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,13 @@ using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi;
|
|||||||
|
|
||||||
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorClaude.Chats;
|
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorClaude.Chats;
|
||||||
|
|
||||||
public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactory,ILogger<AnthropicChatCompletionsService> logger)
|
public class AnthropicChatCompletionsService(
|
||||||
|
IHttpClientFactory httpClientFactory,
|
||||||
|
ILogger<AnthropicChatCompletionsService> logger)
|
||||||
: IAnthropicChatCompletionService
|
: IAnthropicChatCompletionService
|
||||||
{
|
{
|
||||||
|
public const double ClaudeMultiplier = 1.3d;
|
||||||
|
|
||||||
public async Task<AnthropicChatCompletionDto> ChatCompletionsAsync(AiModelDescribe options, AnthropicInput input,
|
public async Task<AnthropicChatCompletionDto> ChatCompletionsAsync(AiModelDescribe options, AnthropicInput input,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -22,6 +26,7 @@ public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactor
|
|||||||
{
|
{
|
||||||
options.Endpoint = "https://api.anthropic.com/";
|
options.Endpoint = "https://api.anthropic.com/";
|
||||||
}
|
}
|
||||||
|
|
||||||
var client = httpClientFactory.CreateClient();
|
var client = httpClientFactory.CreateClient();
|
||||||
|
|
||||||
var headers = new Dictionary<string, string>
|
var headers = new Dictionary<string, string>
|
||||||
@@ -71,7 +76,8 @@ public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactor
|
|||||||
if (response.StatusCode >= HttpStatusCode.BadRequest)
|
if (response.StatusCode >= HttpStatusCode.BadRequest)
|
||||||
{
|
{
|
||||||
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||||
logger.LogError("OpenAI对话异常 请求地址:{Address}, StatusCode: {StatusCode} Response: {Response}", options.Endpoint,
|
logger.LogError("OpenAI对话异常 请求地址:{Address}, StatusCode: {StatusCode} Response: {Response}",
|
||||||
|
options.Endpoint,
|
||||||
response.StatusCode, error);
|
response.StatusCode, error);
|
||||||
|
|
||||||
throw new Exception("OpenAI对话异常" + response.StatusCode.ToString());
|
throw new Exception("OpenAI对话异常" + response.StatusCode.ToString());
|
||||||
@@ -80,11 +86,13 @@ public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactor
|
|||||||
var value =
|
var value =
|
||||||
await response.Content.ReadFromJsonAsync<AnthropicChatCompletionDto>(ThorJsonSerializer.DefaultOptions,
|
await response.Content.ReadFromJsonAsync<AnthropicChatCompletionDto>(ThorJsonSerializer.DefaultOptions,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
value.SupplementalMultiplier(AnthropicChatCompletionsService.ClaudeMultiplier);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async IAsyncEnumerable<(string, AnthropicStreamDto?)> StreamChatCompletionsAsync(AiModelDescribe options, AnthropicInput input,
|
public async IAsyncEnumerable<(string, AnthropicStreamDto?)> StreamChatCompletionsAsync(AiModelDescribe options,
|
||||||
|
AnthropicInput input,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
using var openai =
|
using var openai =
|
||||||
@@ -117,7 +125,8 @@ public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactor
|
|||||||
if (response.StatusCode >= HttpStatusCode.BadRequest)
|
if (response.StatusCode >= HttpStatusCode.BadRequest)
|
||||||
{
|
{
|
||||||
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
var error = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||||
logger.LogError("OpenAI对话异常 请求地址:{Address}, StatusCode: {StatusCode} Response: {Response}", options.Endpoint,
|
logger.LogError("OpenAI对话异常 请求地址:{Address}, StatusCode: {StatusCode} Response: {Response}",
|
||||||
|
options.Endpoint,
|
||||||
response.StatusCode, error);
|
response.StatusCode, error);
|
||||||
|
|
||||||
throw new Exception("OpenAI对话异常" + response.StatusCode);
|
throw new Exception("OpenAI对话异常" + response.StatusCode);
|
||||||
@@ -161,6 +170,7 @@ public class AnthropicChatCompletionsService(IHttpClientFactory httpClientFactor
|
|||||||
var result = JsonSerializer.Deserialize<AnthropicStreamDto>(data,
|
var result = JsonSerializer.Deserialize<AnthropicStreamDto>(data,
|
||||||
ThorJsonSerializer.DefaultOptions);
|
ThorJsonSerializer.DefaultOptions);
|
||||||
|
|
||||||
|
result.SupplementalMultiplier(AnthropicChatCompletionsService.ClaudeMultiplier);
|
||||||
yield return (eventType, result);
|
yield return (eventType, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -687,7 +687,7 @@ public sealed class ClaudiaChatCompletionsService(
|
|||||||
|
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
yield return new ThorChatCompletionsResponse()
|
var output = new ThorChatCompletionsResponse()
|
||||||
{
|
{
|
||||||
Choices = chat,
|
Choices = chat,
|
||||||
Model = input.Model,
|
Model = input.Model,
|
||||||
@@ -701,6 +701,8 @@ public sealed class ClaudiaChatCompletionsService(
|
|||||||
TotalTokens = result.Message.Usage?.InputTokens + result.Message.Usage?.OutputTokens
|
TotalTokens = result.Message.Usage?.InputTokens + result.Message.Usage?.OutputTokens
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
output.SupplementalMultiplier(AnthropicChatCompletionsService.ClaudeMultiplier);
|
||||||
|
yield return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,6 +858,7 @@ public sealed class ClaudiaChatCompletionsService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
thor.Usage.TotalTokens = thor.Usage.InputTokens + thor.Usage.OutputTokens;
|
thor.Usage.TotalTokens = thor.Usage.InputTokens + thor.Usage.OutputTokens;
|
||||||
|
thor.SupplementalMultiplier(AnthropicChatCompletionsService.ClaudeMultiplier);
|
||||||
return thor;
|
return thor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user