diff --git a/relay/channel/ali/adaptor.go b/relay/channel/ali/adaptor.go index 9e9b9b255..f3cc4b6c3 100644 --- a/relay/channel/ali/adaptor.go +++ b/relay/channel/ali/adaptor.go @@ -224,10 +224,10 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom case types.RelayFormatClaude: if supportsAliAnthropicMessages(info.UpstreamModelName) { if info.IsStream { - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) } - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) } adaptor := openai.Adaptor{} diff --git a/relay/channel/aws/constants.go b/relay/channel/aws/constants.go index 888d96eef..4b78b3985 100644 --- a/relay/channel/aws/constants.go +++ b/relay/channel/aws/constants.go @@ -3,10 +3,7 @@ package aws import "strings" var awsModelIDMap = map[string]string{ - "claude-instant-1.2": "anthropic.claude-instant-v1", - "claude-2.0": "anthropic.claude-v2", - "claude-2.1": "anthropic.claude-v2:1", - "claude-3-sonnet-20240229": "anthropic.claude-3-sonnet-20240229-v1:0", + "claude-3-sonnet-20240229": "anthropic.claude-3-sonnet-20240229-v1:0", "claude-3-opus-20240229": "anthropic.claude-3-opus-20240229-v1:0", "claude-3-haiku-20240307": "anthropic.claude-3-haiku-20240307-v1:0", "claude-3-5-sonnet-20240620": "anthropic.claude-3-5-sonnet-20240620-v1:0", diff --git a/relay/channel/aws/relay-aws.go b/relay/channel/aws/relay-aws.go index ea59aedae..aab4baea0 100644 --- a/relay/channel/aws/relay-aws.go +++ b/relay/channel/aws/relay-aws.go @@ -233,7 +233,7 @@ func awsHandler(c *gin.Context, info *relaycommon.RelayInfo, a *Adaptor) (*types c.Writer.Header().Set("Content-Type", *awsResp.ContentType) } - handlerErr := claude.HandleClaudeResponseData(c, info, claudeInfo, nil, awsResp.Body, claude.RequestModeMessage) + handlerErr := claude.HandleClaudeResponseData(c, info, claudeInfo, nil, awsResp.Body) if handlerErr != nil { return handlerErr, nil } @@ -264,7 +264,7 @@ func awsStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, a *Adaptor) ( switch v := event.(type) { case *bedrockruntimeTypes.ResponseStreamMemberChunk: info.SetFirstResponseTime() - respErr := claude.HandleStreamResponseData(c, info, claudeInfo, string(v.Value.Bytes), claude.RequestModeMessage) + respErr := claude.HandleStreamResponseData(c, info, claudeInfo, string(v.Value.Bytes)) if respErr != nil { return respErr, nil } @@ -277,7 +277,7 @@ func awsStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, a *Adaptor) ( } } - claude.HandleStreamFinalResponse(c, info, claudeInfo, claude.RequestModeMessage) + claude.HandleStreamFinalResponse(c, info, claudeInfo) return nil, claudeInfo.Usage } diff --git a/relay/channel/claude/adaptor.go b/relay/channel/claude/adaptor.go index b9b7447f2..295953914 100644 --- a/relay/channel/claude/adaptor.go +++ b/relay/channel/claude/adaptor.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net/http" - "strings" "github.com/QuantumNous/new-api/dto" "github.com/QuantumNous/new-api/relay/channel" @@ -16,13 +15,7 @@ import ( "github.com/gin-gonic/gin" ) -const ( - RequestModeCompletion = 1 - RequestModeMessage = 2 -) - type Adaptor struct { - RequestMode int } func (a *Adaptor) ConvertGeminiRequest(*gin.Context, *relaycommon.RelayInfo, *dto.GeminiChatRequest) (any, error) { @@ -45,20 +38,10 @@ func (a *Adaptor) ConvertImageRequest(c *gin.Context, info *relaycommon.RelayInf } func (a *Adaptor) Init(info *relaycommon.RelayInfo) { - if strings.HasPrefix(info.UpstreamModelName, "claude-2") || strings.HasPrefix(info.UpstreamModelName, "claude-instant") { - a.RequestMode = RequestModeCompletion - } else { - a.RequestMode = RequestModeMessage - } } func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) { - baseURL := "" - if a.RequestMode == RequestModeMessage { - baseURL = fmt.Sprintf("%s/v1/messages", info.ChannelBaseUrl) - } else { - baseURL = fmt.Sprintf("%s/v1/complete", info.ChannelBaseUrl) - } + baseURL := fmt.Sprintf("%s/v1/messages", info.ChannelBaseUrl) if info.IsClaudeBetaQuery { baseURL = baseURL + "?beta=true" } @@ -90,11 +73,7 @@ func (a *Adaptor) ConvertOpenAIRequest(c *gin.Context, info *relaycommon.RelayIn if request == nil { return nil, errors.New("request is nil") } - if a.RequestMode == RequestModeCompletion { - return RequestOpenAI2ClaudeComplete(*request), nil - } else { - return RequestOpenAI2ClaudeMessage(c, *request) - } + return RequestOpenAI2ClaudeMessage(c, *request) } func (a *Adaptor) ConvertRerankRequest(c *gin.Context, relayMode int, request dto.RerankRequest) (any, error) { @@ -117,11 +96,10 @@ func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, request func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (usage any, err *types.NewAPIError) { if info.IsStream { - return ClaudeStreamHandler(c, resp, info, a.RequestMode) + return ClaudeStreamHandler(c, resp, info) } else { - return ClaudeHandler(c, resp, info, a.RequestMode) + return ClaudeHandler(c, resp, info) } - return } func (a *Adaptor) GetModelList() []string { diff --git a/relay/channel/claude/constants.go b/relay/channel/claude/constants.go index 7debb353e..b5dcc5af4 100644 --- a/relay/channel/claude/constants.go +++ b/relay/channel/claude/constants.go @@ -1,10 +1,6 @@ package claude var ModelList = []string{ - "claude-instant-1.2", - "claude-2", - "claude-2.0", - "claude-2.1", "claude-3-sonnet-20240229", "claude-3-opus-20240229", "claude-3-haiku-20240307", diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index f7e8abd15..6d90daa08 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -41,37 +41,6 @@ func maybeMarkClaudeRefusal(c *gin.Context, stopReason string) { } } -func RequestOpenAI2ClaudeComplete(textRequest dto.GeneralOpenAIRequest) *dto.ClaudeRequest { - - claudeRequest := dto.ClaudeRequest{ - Model: textRequest.Model, - Prompt: "", - StopSequences: nil, - Temperature: textRequest.Temperature, - TopP: textRequest.TopP, - TopK: textRequest.TopK, - Stream: textRequest.Stream, - } - if claudeRequest.MaxTokensToSample == 0 { - claudeRequest.MaxTokensToSample = 4096 - } - prompt := "" - for _, message := range textRequest.Messages { - if message.Role == "user" { - prompt += fmt.Sprintf("\n\nHuman: %s", message.StringContent()) - } else if message.Role == "assistant" { - prompt += fmt.Sprintf("\n\nAssistant: %s", message.StringContent()) - } else if message.Role == "system" { - if prompt == "" { - prompt = message.StringContent() - } - } - } - prompt += "\n\nAssistant:" - claudeRequest.Prompt = prompt - return &claudeRequest -} - func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRequest) (*dto.ClaudeRequest, error) { claudeTools := make([]any, 0, len(textRequest.Tools)) @@ -411,7 +380,7 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe return &claudeRequest, nil } -func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse) *dto.ChatCompletionsStreamResponse { +func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse) *dto.ChatCompletionsStreamResponse { var response dto.ChatCompletionsStreamResponse response.Object = "chat.completion.chunk" response.Model = claudeResponse.Model @@ -425,74 +394,66 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse } } var choice dto.ChatCompletionsStreamResponseChoice - if reqMode == RequestModeCompletion { - choice.Delta.SetContentString(claudeResponse.Completion) - finishReason := stopReasonClaude2OpenAI(claudeResponse.StopReason) - if finishReason != "null" { - choice.FinishReason = &finishReason + if claudeResponse.Type == "message_start" { + if claudeResponse.Message != nil { + response.Id = claudeResponse.Message.Id + response.Model = claudeResponse.Message.Model } - } else { - if claudeResponse.Type == "message_start" { - if claudeResponse.Message != nil { - response.Id = claudeResponse.Message.Id - response.Model = claudeResponse.Message.Model + //claudeUsage = &claudeResponse.Message.Usage + choice.Delta.SetContentString("") + choice.Delta.Role = "assistant" + } else if claudeResponse.Type == "content_block_start" { + if claudeResponse.ContentBlock != nil { + // 如果是文本块,尽可能发送首段文本(若存在) + if claudeResponse.ContentBlock.Type == "text" && claudeResponse.ContentBlock.Text != nil { + choice.Delta.SetContentString(*claudeResponse.ContentBlock.Text) } - //claudeUsage = &claudeResponse.Message.Usage - choice.Delta.SetContentString("") - choice.Delta.Role = "assistant" - } else if claudeResponse.Type == "content_block_start" { - if claudeResponse.ContentBlock != nil { - // 如果是文本块,尽可能发送首段文本(若存在) - if claudeResponse.ContentBlock.Type == "text" && claudeResponse.ContentBlock.Text != nil { - choice.Delta.SetContentString(*claudeResponse.ContentBlock.Text) - } - if claudeResponse.ContentBlock.Type == "tool_use" { - tools = append(tools, dto.ToolCallResponse{ - Index: common.GetPointer(fcIdx), - ID: claudeResponse.ContentBlock.Id, - Type: "function", - Function: dto.FunctionResponse{ - Name: claudeResponse.ContentBlock.Name, - Arguments: "", - }, - }) - } - } else { - return nil + if claudeResponse.ContentBlock.Type == "tool_use" { + tools = append(tools, dto.ToolCallResponse{ + Index: common.GetPointer(fcIdx), + ID: claudeResponse.ContentBlock.Id, + Type: "function", + Function: dto.FunctionResponse{ + Name: claudeResponse.ContentBlock.Name, + Arguments: "", + }, + }) } - } else if claudeResponse.Type == "content_block_delta" { - if claudeResponse.Delta != nil { - choice.Delta.Content = claudeResponse.Delta.Text - switch claudeResponse.Delta.Type { - case "input_json_delta": - tools = append(tools, dto.ToolCallResponse{ - Type: "function", - Index: common.GetPointer(fcIdx), - Function: dto.FunctionResponse{ - Arguments: *claudeResponse.Delta.PartialJson, - }, - }) - case "signature_delta": - // 加密的不处理 - signatureContent := "\n" - choice.Delta.ReasoningContent = &signatureContent - case "thinking_delta": - choice.Delta.ReasoningContent = claudeResponse.Delta.Thinking - } - } - } else if claudeResponse.Type == "message_delta" { - if claudeResponse.Delta != nil && claudeResponse.Delta.StopReason != nil { - finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason) - if finishReason != "null" { - choice.FinishReason = &finishReason - } - } - //claudeUsage = &claudeResponse.Usage - } else if claudeResponse.Type == "message_stop" { - return nil } else { return nil } + } else if claudeResponse.Type == "content_block_delta" { + if claudeResponse.Delta != nil { + choice.Delta.Content = claudeResponse.Delta.Text + switch claudeResponse.Delta.Type { + case "input_json_delta": + tools = append(tools, dto.ToolCallResponse{ + Type: "function", + Index: common.GetPointer(fcIdx), + Function: dto.FunctionResponse{ + Arguments: *claudeResponse.Delta.PartialJson, + }, + }) + case "signature_delta": + // 加密的不处理 + signatureContent := "\n" + choice.Delta.ReasoningContent = &signatureContent + case "thinking_delta": + choice.Delta.ReasoningContent = claudeResponse.Delta.Thinking + } + } + } else if claudeResponse.Type == "message_delta" { + if claudeResponse.Delta != nil && claudeResponse.Delta.StopReason != nil { + finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason) + if finishReason != "null" { + choice.FinishReason = &finishReason + } + } + //claudeUsage = &claudeResponse.Usage + } else if claudeResponse.Type == "message_stop" { + return nil + } else { + return nil } if len(tools) > 0 { choice.Delta.Content = nil // compatible with other OpenAI derivative applications, like LobeOpenAICompatibleFactory ... @@ -503,7 +464,7 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse return &response } -func ResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse) *dto.OpenAITextResponse { +func ResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse) *dto.OpenAITextResponse { choices := make([]dto.OpenAITextResponseChoice, 0) fullTextResponse := dto.OpenAITextResponse{ Id: fmt.Sprintf("chatcmpl-%s", common.GetUUID()), @@ -521,39 +482,26 @@ func ResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse) *dto tools := make([]dto.ToolCallResponse, 0) thinkingContent := "" - if reqMode == RequestModeCompletion { - choice := dto.OpenAITextResponseChoice{ - Index: 0, - Message: dto.Message{ - Role: "assistant", - Content: strings.TrimPrefix(claudeResponse.Completion, " "), - Name: nil, - }, - FinishReason: stopReasonClaude2OpenAI(claudeResponse.StopReason), - } - choices = append(choices, choice) - } else { - fullTextResponse.Id = claudeResponse.Id - for _, message := range claudeResponse.Content { - switch message.Type { - case "tool_use": - args, _ := json.Marshal(message.Input) - tools = append(tools, dto.ToolCallResponse{ - ID: message.Id, - Type: "function", // compatible with other OpenAI derivative applications - Function: dto.FunctionResponse{ - Name: message.Name, - Arguments: string(args), - }, - }) - case "thinking": - // 加密的不管, 只输出明文的推理过程 - if message.Thinking != nil { - thinkingContent = *message.Thinking - } - case "text": - responseText = message.GetText() + fullTextResponse.Id = claudeResponse.Id + for _, message := range claudeResponse.Content { + switch message.Type { + case "tool_use": + args, _ := json.Marshal(message.Input) + tools = append(tools, dto.ToolCallResponse{ + ID: message.Id, + Type: "function", // compatible with other OpenAI derivative applications + Function: dto.FunctionResponse{ + Name: message.Name, + Arguments: string(args), + }, + }) + case "thinking": + // 加密的不管, 只输出明文的推理过程 + if message.Thinking != nil { + thinkingContent = *message.Thinking } + case "text": + responseText = message.GetText() } } choice := dto.OpenAITextResponseChoice{ @@ -586,71 +534,67 @@ type ClaudeResponseInfo struct { Done bool } -func FormatClaudeResponseInfo(requestMode int, claudeResponse *dto.ClaudeResponse, oaiResponse *dto.ChatCompletionsStreamResponse, claudeInfo *ClaudeResponseInfo) bool { +func FormatClaudeResponseInfo(claudeResponse *dto.ClaudeResponse, oaiResponse *dto.ChatCompletionsStreamResponse, claudeInfo *ClaudeResponseInfo) bool { if claudeInfo == nil { return false } if claudeInfo.Usage == nil { claudeInfo.Usage = &dto.Usage{} } - if requestMode == RequestModeCompletion { - claudeInfo.ResponseText.WriteString(claudeResponse.Completion) - } else { - if claudeResponse.Type == "message_start" { - if claudeResponse.Message != nil { - claudeInfo.ResponseId = claudeResponse.Message.Id - claudeInfo.Model = claudeResponse.Message.Model - } - - // message_start, 获取usage - if claudeResponse.Message != nil && claudeResponse.Message.Usage != nil { - claudeInfo.Usage.PromptTokens = claudeResponse.Message.Usage.InputTokens - claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Message.Usage.CacheReadInputTokens - claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Message.Usage.CacheCreationInputTokens - claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Message.Usage.GetCacheCreation5mTokens() - claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Message.Usage.GetCacheCreation1hTokens() - claudeInfo.Usage.CompletionTokens = claudeResponse.Message.Usage.OutputTokens - } - } else if claudeResponse.Type == "content_block_delta" { - if claudeResponse.Delta != nil { - if claudeResponse.Delta.Text != nil { - claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Text) - } - if claudeResponse.Delta.Thinking != nil { - claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Thinking) - } - } - } else if claudeResponse.Type == "message_delta" { - // 最终的usage获取 - if claudeResponse.Usage != nil { - if claudeResponse.Usage.InputTokens > 0 { - // 不叠加,只取最新的 - claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens - } - if claudeResponse.Usage.CacheReadInputTokens > 0 { - claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Usage.CacheReadInputTokens - } - if claudeResponse.Usage.CacheCreationInputTokens > 0 { - claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Usage.CacheCreationInputTokens - } - if cacheCreation5m := claudeResponse.Usage.GetCacheCreation5mTokens(); cacheCreation5m > 0 { - claudeInfo.Usage.ClaudeCacheCreation5mTokens = cacheCreation5m - } - if cacheCreation1h := claudeResponse.Usage.GetCacheCreation1hTokens(); cacheCreation1h > 0 { - claudeInfo.Usage.ClaudeCacheCreation1hTokens = cacheCreation1h - } - if claudeResponse.Usage.OutputTokens > 0 { - claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens - } - claudeInfo.Usage.TotalTokens = claudeInfo.Usage.PromptTokens + claudeInfo.Usage.CompletionTokens - } - - // 判断是否完整 - claudeInfo.Done = true - } else if claudeResponse.Type == "content_block_start" { - } else { - return false + if claudeResponse.Type == "message_start" { + if claudeResponse.Message != nil { + claudeInfo.ResponseId = claudeResponse.Message.Id + claudeInfo.Model = claudeResponse.Message.Model } + + // message_start, 获取usage + if claudeResponse.Message != nil && claudeResponse.Message.Usage != nil { + claudeInfo.Usage.PromptTokens = claudeResponse.Message.Usage.InputTokens + claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Message.Usage.CacheReadInputTokens + claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Message.Usage.CacheCreationInputTokens + claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Message.Usage.GetCacheCreation5mTokens() + claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Message.Usage.GetCacheCreation1hTokens() + claudeInfo.Usage.CompletionTokens = claudeResponse.Message.Usage.OutputTokens + } + } else if claudeResponse.Type == "content_block_delta" { + if claudeResponse.Delta != nil { + if claudeResponse.Delta.Text != nil { + claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Text) + } + if claudeResponse.Delta.Thinking != nil { + claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Thinking) + } + } + } else if claudeResponse.Type == "message_delta" { + // 最终的usage获取 + if claudeResponse.Usage != nil { + if claudeResponse.Usage.InputTokens > 0 { + // 不叠加,只取最新的 + claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens + } + if claudeResponse.Usage.CacheReadInputTokens > 0 { + claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Usage.CacheReadInputTokens + } + if claudeResponse.Usage.CacheCreationInputTokens > 0 { + claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Usage.CacheCreationInputTokens + } + if cacheCreation5m := claudeResponse.Usage.GetCacheCreation5mTokens(); cacheCreation5m > 0 { + claudeInfo.Usage.ClaudeCacheCreation5mTokens = cacheCreation5m + } + if cacheCreation1h := claudeResponse.Usage.GetCacheCreation1hTokens(); cacheCreation1h > 0 { + claudeInfo.Usage.ClaudeCacheCreation1hTokens = cacheCreation1h + } + if claudeResponse.Usage.OutputTokens > 0 { + claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens + } + claudeInfo.Usage.TotalTokens = claudeInfo.Usage.PromptTokens + claudeInfo.Usage.CompletionTokens + } + + // 判断是否完整 + claudeInfo.Done = true + } else if claudeResponse.Type == "content_block_start" { + } else { + return false } if oaiResponse != nil { oaiResponse.Id = claudeInfo.ResponseId @@ -660,7 +604,7 @@ func FormatClaudeResponseInfo(requestMode int, claudeResponse *dto.ClaudeRespons return true } -func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, data string, requestMode int) *types.NewAPIError { +func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, data string) *types.NewAPIError { var claudeResponse dto.ClaudeResponse err := common.UnmarshalJsonStr(data, &claudeResponse) if err != nil { @@ -677,24 +621,19 @@ func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud maybeMarkClaudeRefusal(c, *claudeResponse.Delta.StopReason) } if info.RelayFormat == types.RelayFormatClaude { - FormatClaudeResponseInfo(requestMode, &claudeResponse, nil, claudeInfo) + FormatClaudeResponseInfo(&claudeResponse, nil, claudeInfo) - if requestMode == RequestModeCompletion { - } else { - if claudeResponse.Type == "message_start" { - // message_start, 获取usage - if claudeResponse.Message != nil { - info.UpstreamModelName = claudeResponse.Message.Model - } - } else if claudeResponse.Type == "content_block_delta" { - } else if claudeResponse.Type == "message_delta" { + if claudeResponse.Type == "message_start" { + // message_start, 获取usage + if claudeResponse.Message != nil { + info.UpstreamModelName = claudeResponse.Message.Model } } helper.ClaudeChunkData(c, claudeResponse, data) } else if info.RelayFormat == types.RelayFormatOpenAI { - response := StreamResponseClaude2OpenAI(requestMode, &claudeResponse) + response := StreamResponseClaude2OpenAI(&claudeResponse) - if !FormatClaudeResponseInfo(requestMode, &claudeResponse, response, claudeInfo) { + if !FormatClaudeResponseInfo(&claudeResponse, response, claudeInfo) { return nil } @@ -706,20 +645,15 @@ func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud return nil } -func HandleStreamFinalResponse(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, requestMode int) { - - if requestMode == RequestModeCompletion { - claudeInfo.Usage = service.ResponseText2Usage(c, claudeInfo.ResponseText.String(), info.UpstreamModelName, info.GetEstimatePromptTokens()) - } else { - if claudeInfo.Usage.PromptTokens == 0 { - //上游出错 - } - if claudeInfo.Usage.CompletionTokens == 0 || !claudeInfo.Done { - if common.DebugEnabled { - common.SysLog("claude response usage is not complete, maybe upstream error") - } - claudeInfo.Usage = service.ResponseText2Usage(c, claudeInfo.ResponseText.String(), info.UpstreamModelName, claudeInfo.Usage.PromptTokens) +func HandleStreamFinalResponse(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo) { + if claudeInfo.Usage.PromptTokens == 0 { + //上游出错 + } + if claudeInfo.Usage.CompletionTokens == 0 || !claudeInfo.Done { + if common.DebugEnabled { + common.SysLog("claude response usage is not complete, maybe upstream error") } + claudeInfo.Usage = service.ResponseText2Usage(c, claudeInfo.ResponseText.String(), info.UpstreamModelName, claudeInfo.Usage.PromptTokens) } if info.RelayFormat == types.RelayFormatClaude { @@ -736,7 +670,7 @@ func HandleStreamFinalResponse(c *gin.Context, info *relaycommon.RelayInfo, clau } } -func ClaudeStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo, requestMode int) (*dto.Usage, *types.NewAPIError) { +func ClaudeStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.Usage, *types.NewAPIError) { claudeInfo := &ClaudeResponseInfo{ ResponseId: helper.GetResponseID(c), Created: common.GetTimestamp(), @@ -746,7 +680,7 @@ func ClaudeStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon. } var err *types.NewAPIError helper.StreamScannerHandler(c, resp, info, func(data string) bool { - err = HandleStreamResponseData(c, info, claudeInfo, data, requestMode) + err = HandleStreamResponseData(c, info, claudeInfo, data) if err != nil { return false } @@ -756,11 +690,11 @@ func ClaudeStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon. return nil, err } - HandleStreamFinalResponse(c, info, claudeInfo, requestMode) + HandleStreamFinalResponse(c, info, claudeInfo) return claudeInfo.Usage, nil } -func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, httpResp *http.Response, data []byte, requestMode int) *types.NewAPIError { +func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claudeInfo *ClaudeResponseInfo, httpResp *http.Response, data []byte) *types.NewAPIError { var claudeResponse dto.ClaudeResponse err := common.Unmarshal(data, &claudeResponse) if err != nil { @@ -770,26 +704,22 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud return types.WithClaudeError(*claudeError, http.StatusInternalServerError) } maybeMarkClaudeRefusal(c, claudeResponse.StopReason) - if requestMode == RequestModeCompletion { - claudeInfo.Usage = service.ResponseText2Usage(c, claudeResponse.Completion, info.UpstreamModelName, info.GetEstimatePromptTokens()) - } else { - if claudeInfo.Usage == nil { - claudeInfo.Usage = &dto.Usage{} - } - if claudeResponse.Usage != nil { - claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens - claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens - claudeInfo.Usage.TotalTokens = claudeResponse.Usage.InputTokens + claudeResponse.Usage.OutputTokens - claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Usage.CacheReadInputTokens - claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Usage.CacheCreationInputTokens - claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Usage.GetCacheCreation5mTokens() - claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Usage.GetCacheCreation1hTokens() - } + if claudeInfo.Usage == nil { + claudeInfo.Usage = &dto.Usage{} + } + if claudeResponse.Usage != nil { + claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens + claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens + claudeInfo.Usage.TotalTokens = claudeResponse.Usage.InputTokens + claudeResponse.Usage.OutputTokens + claudeInfo.Usage.PromptTokensDetails.CachedTokens = claudeResponse.Usage.CacheReadInputTokens + claudeInfo.Usage.PromptTokensDetails.CachedCreationTokens = claudeResponse.Usage.CacheCreationInputTokens + claudeInfo.Usage.ClaudeCacheCreation5mTokens = claudeResponse.Usage.GetCacheCreation5mTokens() + claudeInfo.Usage.ClaudeCacheCreation1hTokens = claudeResponse.Usage.GetCacheCreation1hTokens() } var responseData []byte switch info.RelayFormat { case types.RelayFormatOpenAI: - openaiResponse := ResponseClaude2OpenAI(requestMode, &claudeResponse) + openaiResponse := ResponseClaude2OpenAI(&claudeResponse) openaiResponse.Usage = *claudeInfo.Usage responseData, err = json.Marshal(openaiResponse) if err != nil { @@ -807,7 +737,7 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud return nil } -func ClaudeHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo, requestMode int) (*dto.Usage, *types.NewAPIError) { +func ClaudeHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.Usage, *types.NewAPIError) { defer service.CloseResponseBodyGracefully(resp) claudeInfo := &ClaudeResponseInfo{ @@ -824,7 +754,7 @@ func ClaudeHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayI if common.DebugEnabled { println("responseBody: ", string(responseBody)) } - handleErr := HandleClaudeResponseData(c, info, claudeInfo, resp, responseBody, requestMode) + handleErr := HandleClaudeResponseData(c, info, claudeInfo, resp, responseBody) if handleErr != nil { return nil, handleErr } diff --git a/relay/channel/deepseek/adaptor.go b/relay/channel/deepseek/adaptor.go index 53488f0d5..6de2653b4 100644 --- a/relay/channel/deepseek/adaptor.go +++ b/relay/channel/deepseek/adaptor.go @@ -96,9 +96,9 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom switch info.RelayFormat { case types.RelayFormatClaude: if info.IsStream { - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) } else { - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) } default: adaptor := openai.Adaptor{} diff --git a/relay/channel/moonshot/adaptor.go b/relay/channel/moonshot/adaptor.go index 6591ee750..25a6e2a34 100644 --- a/relay/channel/moonshot/adaptor.go +++ b/relay/channel/moonshot/adaptor.go @@ -103,9 +103,9 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom switch info.RelayFormat { case types.RelayFormatClaude: if info.IsStream { - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) } else { - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) } default: adaptor := openai.Adaptor{} diff --git a/relay/channel/vertex/adaptor.go b/relay/channel/vertex/adaptor.go index 964c469fb..b9fbd19a4 100644 --- a/relay/channel/vertex/adaptor.go +++ b/relay/channel/vertex/adaptor.go @@ -367,7 +367,7 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom if info.IsStream { switch a.RequestMode { case RequestModeClaude: - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) case RequestModeGemini: if info.RelayMode == constant.RelayModeGemini { return gemini.GeminiTextGenerationStreamHandler(c, info, resp) @@ -380,7 +380,7 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom } else { switch a.RequestMode { case RequestModeClaude: - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) case RequestModeGemini: if info.RelayMode == constant.RelayModeGemini { return gemini.GeminiTextGenerationHandler(c, info, resp) diff --git a/relay/channel/volcengine/adaptor.go b/relay/channel/volcengine/adaptor.go index 9e09d9d8d..22caa6b92 100644 --- a/relay/channel/volcengine/adaptor.go +++ b/relay/channel/volcengine/adaptor.go @@ -348,9 +348,9 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom if info.RelayFormat == types.RelayFormatClaude { if _, ok := channelconstant.ChannelSpecialBases[info.ChannelBaseUrl]; ok { if info.IsStream { - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) } - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) } } diff --git a/relay/channel/zhipu_4v/adaptor.go b/relay/channel/zhipu_4v/adaptor.go index b11bea105..7e25c7ca5 100644 --- a/relay/channel/zhipu_4v/adaptor.go +++ b/relay/channel/zhipu_4v/adaptor.go @@ -110,9 +110,9 @@ func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, info *relaycom switch info.RelayFormat { case types.RelayFormatClaude: if info.IsStream { - return claude.ClaudeStreamHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeStreamHandler(c, resp, info) } else { - return claude.ClaudeHandler(c, resp, info, claude.RequestModeMessage) + return claude.ClaudeHandler(c, resp, info) } default: if info.RelayMode == relayconstant.RelayModeImagesGenerations { diff --git a/setting/ratio_setting/model_ratio.go b/setting/ratio_setting/model_ratio.go index c84b65fa3..61f6d044f 100644 --- a/setting/ratio_setting/model_ratio.go +++ b/setting/ratio_setting/model_ratio.go @@ -131,9 +131,6 @@ var defaultModelRatio = map[string]float64{ "text-search-ada-doc-001": 10, "text-moderation-stable": 0.1, "text-moderation-latest": 0.1, - "claude-instant-1": 0.4, // $0.8 / 1M tokens - "claude-2.0": 4, // $8 / 1M tokens - "claude-2.1": 4, // $8 / 1M tokens "claude-3-haiku-20240307": 0.125, // $0.25 / 1M tokens "claude-3-5-haiku-20241022": 0.5, // $1 / 1M tokens "claude-haiku-4-5-20251001": 0.5, // $1 / 1M tokens @@ -589,8 +586,6 @@ func getHardcodedCompletionModelRatio(name string) (float64, bool) { return 5, true } else if strings.Contains(name, "claude-sonnet-4") || strings.Contains(name, "claude-opus-4") || strings.Contains(name, "claude-haiku-4") { return 5, true - } else if strings.Contains(name, "claude-instant-1") || strings.Contains(name, "claude-2") { - return 3, true } if strings.HasPrefix(name, "gpt-3.5") { diff --git a/web/src/helpers/render.jsx b/web/src/helpers/render.jsx index 5c58ff0e4..ecc252cfd 100644 --- a/web/src/helpers/render.jsx +++ b/web/src/helpers/render.jsx @@ -571,7 +571,6 @@ export const modelColorMap = { 'claude-3-opus-20240229': 'rgb(255,132,31)', // 橙红色 'claude-3-sonnet-20240229': 'rgb(253,135,93)', // 橙色 'claude-3-haiku-20240307': 'rgb(255,175,146)', // 浅橙色 - 'claude-2.1': 'rgb(255,209,190)', // 浅橙色(略有区别) }; export function modelToColor(modelName) {