From a14fa1adb13d2e7ba173ab03d0bfaa9e20ee61db Mon Sep 17 00:00:00 2001 From: "1808837298@qq.com" <1808837298@qq.com> Date: Thu, 25 Apr 2024 16:04:53 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20claude=20=E6=95=B4=E7=90=86prompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/claude/relay-claude.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index 33e742a..bd28512 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -72,12 +72,12 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR } formatMessages := make([]dto.Message, 0) var lastMessage *dto.Message - for i, message := range textRequest.Messages { - if message.Role == "system" { - if i != 0 { - message.Role = "user" - } - } + for _, message := range textRequest.Messages { + //if message.Role == "system" { + // if i != 0 { + // message.Role = "user" + // } + //} if message.Role == "" { message.Role = "user" } From e2edd5e7e5d2f79da2ee4c18ad6a905846bc027a Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Thu, 25 Apr 2024 20:37:50 +0800 Subject: [PATCH 2/6] fix: claude --- common/logger.go | 11 +++++++++++ relay/channel/claude/relay-claude.go | 18 ++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/common/logger.go b/common/logger.go index 6162721..02ddb71 100644 --- a/common/logger.go +++ b/common/logger.go @@ -2,6 +2,7 @@ package common import ( "context" + "encoding/json" "fmt" "github.com/gin-gonic/gin" "io" @@ -98,3 +99,13 @@ func LogQuota(quota int) string { return fmt.Sprintf("%d 点额度", quota) } } + +// LogJson 仅供测试使用 only for test +func LogJson(ctx context.Context, msg string, obj any) { + jsonStr, err := json.Marshal(obj) + if err != nil { + LogError(ctx, fmt.Sprintf("json marshal failed: %s", err.Error())) + return + } + LogInfo(ctx, fmt.Sprintf("%s | %s", msg, string(jsonStr))) +} diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index bd28512..2726eeb 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -72,7 +72,7 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR } formatMessages := make([]dto.Message, 0) var lastMessage *dto.Message - for _, message := range textRequest.Messages { + for i, message := range textRequest.Messages { //if message.Role == "system" { // if i != 0 { // message.Role = "user" @@ -98,13 +98,24 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR fmtMessage.Content = content } formatMessages = append(formatMessages, fmtMessage) - lastMessage = &message + lastMessage = &textRequest.Messages[i] } claudeMessages := make([]ClaudeMessage, 0) for _, message := range formatMessages { if message.Role == "system" { - claudeRequest.System = message.StringContent() + if message.IsStringContent() { + claudeRequest.System = message.StringContent() + } else { + contents := message.ParseContent() + content := "" + for _, ctx := range contents { + if ctx.Type == "text" { + content += ctx.Text + } + } + claudeRequest.System = content + } } else { claudeMessage := ClaudeMessage{ Role: message.Role, @@ -149,7 +160,6 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR } claudeRequest.Prompt = "" claudeRequest.Messages = claudeMessages - return &claudeRequest, nil } From be4809b95a844c9862796428221c64e0a4abea57 Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Thu, 25 Apr 2024 20:47:18 +0800 Subject: [PATCH 3/6] feat: log status code --- controller/relay.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller/relay.go b/controller/relay.go index 3a4ae72..0bbd409 100644 --- a/controller/relay.go +++ b/controller/relay.go @@ -124,7 +124,7 @@ func shouldRetry(c *gin.Context, channelId int, openaiErr *dto.OpenAIErrorWithSt func processChannelError(c *gin.Context, channelId int, err *dto.OpenAIErrorWithStatusCode) { autoBan := c.GetBool("auto_ban") - common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d): %s", channelId, err.Error.Message)) + common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message)) if service.ShouldDisableChannel(&err.Error, err.StatusCode) && autoBan { channelName := c.GetString("channel_name") service.DisableChannel(channelId, channelName, err.Error.Message) @@ -160,7 +160,7 @@ func RelayMidjourney(c *gin.Context) { "code": err.Code, }) channelId := c.GetInt("channel_id") - common.SysError(fmt.Sprintf("relay error (channel #%d): %s", channelId, fmt.Sprintf("%s %s", err.Description, err.Result))) + common.LogError(c, fmt.Sprintf("relay error (channel #%d, status code %d): %s", channelId, statusCode, fmt.Sprintf("%s %s", err.Description, err.Result))) } } From 7d2d52505150f1533a889d91cdd29407bed8e464 Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Thu, 25 Apr 2024 22:57:11 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix:=20claude=E6=B5=81=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1role?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- relay/channel/claude/relay-claude.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index 2726eeb..015b645 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -79,7 +79,7 @@ func RequestOpenAI2ClaudeMessage(textRequest dto.GeneralOpenAIRequest) (*ClaudeR // } //} if message.Role == "" { - message.Role = "user" + textRequest.Messages[i].Role = "user" } fmtMessage := dto.Message{ Role: message.Role, @@ -172,6 +172,7 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* var choice dto.ChatCompletionsStreamResponseChoice if reqMode == RequestModeCompletion { choice.Delta.Content = claudeResponse.Completion + choice.Delta.Role = "assistant" finishReason := stopReasonClaude2OpenAI(claudeResponse.StopReason) if finishReason != "null" { choice.FinishReason = &finishReason @@ -184,6 +185,7 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* } else if claudeResponse.Type == "content_block_delta" { choice.Index = claudeResponse.Index choice.Delta.Content = claudeResponse.Delta.Text + choice.Delta.Role = "assistant" } else if claudeResponse.Type == "message_delta" { finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason) if finishReason != "null" { From d1c8947851c001aad8d39a22db84b404be421c4d Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Thu, 25 Apr 2024 23:57:39 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=E8=A7=84=E8=8C=83claude=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dto/text_response.go | 21 ++++++++++++++++++--- relay/channel/ali/relay-ali.go | 4 ++-- relay/channel/baidu/relay-baidu.go | 2 +- relay/channel/claude/relay-claude.go | 12 ++++++++---- relay/channel/cohere/relay-cohere.go | 2 +- relay/channel/gemini/relay-gemini.go | 4 ++-- relay/channel/openai/relay-openai.go | 4 ++-- relay/channel/palm/relay-palm.go | 2 +- relay/channel/tencent/relay-tencent.go | 4 ++-- relay/channel/xunfei/relay-xunfei.go | 2 +- relay/channel/zhipu/relay-zhipu.go | 4 ++-- 11 files changed, 40 insertions(+), 21 deletions(-) diff --git a/dto/text_response.go b/dto/text_response.go index a589d75..617c375 100644 --- a/dto/text_response.go +++ b/dto/text_response.go @@ -54,17 +54,32 @@ type OpenAIEmbeddingResponse struct { } type ChatCompletionsStreamResponseChoice struct { - Delta ChatCompletionsStreamResponseChoiceDelta `json:"delta"` - FinishReason *string `json:"finish_reason,omitempty"` + Delta ChatCompletionsStreamResponseChoiceDelta `json:"delta,omitempty"` + FinishReason *string `json:"finish_reason"` Index int `json:"index,omitempty"` } type ChatCompletionsStreamResponseChoiceDelta struct { - Content string `json:"content"` + Content *string `json:"content,omitempty"` Role string `json:"role,omitempty"` ToolCalls []ToolCall `json:"tool_calls,omitempty"` } +func (c *ChatCompletionsStreamResponseChoiceDelta) IsEmpty() bool { + return c.Content == nil && len(c.ToolCalls) == 0 +} + +func (c *ChatCompletionsStreamResponseChoiceDelta) SetContentString(s string) { + c.Content = &s +} + +func (c *ChatCompletionsStreamResponseChoiceDelta) GetContentString() string { + if c.Content == nil { + return "" + } + return *c.Content +} + type ToolCall struct { // Index is not nil only in chat completion chunk object Index *int `json:"index,omitempty"` diff --git a/relay/channel/ali/relay-ali.go b/relay/channel/ali/relay-ali.go index e087eea..4280b1c 100644 --- a/relay/channel/ali/relay-ali.go +++ b/relay/channel/ali/relay-ali.go @@ -136,7 +136,7 @@ func responseAli2OpenAI(response *AliChatResponse) *dto.OpenAITextResponse { func streamResponseAli2OpenAI(aliResponse *AliChatResponse) *dto.ChatCompletionsStreamResponse { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = aliResponse.Output.Text + choice.Delta.SetContentString(aliResponse.Output.Text) if aliResponse.Output.FinishReason != "null" { finishReason := aliResponse.Output.FinishReason choice.FinishReason = &finishReason @@ -199,7 +199,7 @@ func aliStreamHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIErrorWith usage.TotalTokens = aliResponse.Usage.InputTokens + aliResponse.Usage.OutputTokens } response := streamResponseAli2OpenAI(&aliResponse) - response.Choices[0].Delta.Content = strings.TrimPrefix(response.Choices[0].Delta.Content, lastResponseText) + response.Choices[0].Delta.SetContentString(strings.TrimPrefix(response.Choices[0].Delta.GetContentString(), lastResponseText)) lastResponseText = aliResponse.Output.Text jsonResponse, err := json.Marshal(response) if err != nil { diff --git a/relay/channel/baidu/relay-baidu.go b/relay/channel/baidu/relay-baidu.go index 6f773ba..f1ceab3 100644 --- a/relay/channel/baidu/relay-baidu.go +++ b/relay/channel/baidu/relay-baidu.go @@ -57,7 +57,7 @@ func responseBaidu2OpenAI(response *BaiduChatResponse) *dto.OpenAITextResponse { func streamResponseBaidu2OpenAI(baiduResponse *BaiduChatStreamResponse) *dto.ChatCompletionsStreamResponse { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = baiduResponse.Result + choice.Delta.SetContentString(baiduResponse.Result) if baiduResponse.IsEnd { choice.FinishReason = &relaycommon.StopFinishReason } diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index 015b645..859b7b1 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -171,8 +171,7 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* response.Choices = make([]dto.ChatCompletionsStreamResponseChoice, 0) var choice dto.ChatCompletionsStreamResponseChoice if reqMode == RequestModeCompletion { - choice.Delta.Content = claudeResponse.Completion - choice.Delta.Role = "assistant" + choice.Delta.SetContentString(claudeResponse.Completion) finishReason := stopReasonClaude2OpenAI(claudeResponse.StopReason) if finishReason != "null" { choice.FinishReason = &finishReason @@ -182,10 +181,12 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* response.Id = claudeResponse.Message.Id response.Model = claudeResponse.Message.Model claudeUsage = &claudeResponse.Message.Usage + } else if claudeResponse.Type == "content_block_start" { + choice.Delta.SetContentString("") + choice.Delta.Role = "assistant" } else if claudeResponse.Type == "content_block_delta" { choice.Index = claudeResponse.Index - choice.Delta.Content = claudeResponse.Delta.Text - choice.Delta.Role = "assistant" + choice.Delta.SetContentString(claudeResponse.Delta.Text) } else if claudeResponse.Type == "message_delta" { finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason) if finishReason != "null" { @@ -194,12 +195,15 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* claudeUsage = &claudeResponse.Usage } else if claudeResponse.Type == "message_stop" { return nil, nil + } else { + return nil, nil } } if claudeUsage == nil { claudeUsage = &ClaudeUsage{} } response.Choices = append(response.Choices, choice) + return &response, claudeUsage } diff --git a/relay/channel/cohere/relay-cohere.go b/relay/channel/cohere/relay-cohere.go index a21d4a9..463e8b1 100644 --- a/relay/channel/cohere/relay-cohere.go +++ b/relay/channel/cohere/relay-cohere.go @@ -117,7 +117,7 @@ func cohereStreamHandler(c *gin.Context, resp *http.Response, modelName string, { Delta: dto.ChatCompletionsStreamResponseChoiceDelta{ Role: "assistant", - Content: cohereResp.Text, + Content: &cohereResp.Text, }, Index: 0, }, diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index 4a10a73..ee9301d 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -151,7 +151,7 @@ func responseGeminiChat2OpenAI(response *GeminiChatResponse) *dto.OpenAITextResp func streamResponseGeminiChat2OpenAI(geminiResponse *GeminiChatResponse) *dto.ChatCompletionsStreamResponse { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = geminiResponse.GetResponseText() + choice.Delta.SetContentString(geminiResponse.GetResponseText()) choice.FinishReason = &relaycommon.StopFinishReason var response dto.ChatCompletionsStreamResponse response.Object = "chat.completion.chunk" @@ -203,7 +203,7 @@ func geminiChatStreamHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIEr err := json.Unmarshal([]byte(data), &dummy) responseText += dummy.Content var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = dummy.Content + choice.Delta.SetContentString(dummy.Content) response := dto.ChatCompletionsStreamResponse{ Id: fmt.Sprintf("chatcmpl-%s", common.GetUUID()), Object: "chat.completion.chunk", diff --git a/relay/channel/openai/relay-openai.go b/relay/channel/openai/relay-openai.go index 5469ed7..d627575 100644 --- a/relay/channel/openai/relay-openai.go +++ b/relay/channel/openai/relay-openai.go @@ -68,7 +68,7 @@ func OpenaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*d err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse) if err == nil { for _, choice := range streamResponse.Choices { - responseTextBuilder.WriteString(choice.Delta.Content) + responseTextBuilder.WriteString(choice.Delta.GetContentString()) if choice.Delta.ToolCalls != nil { if len(choice.Delta.ToolCalls) > toolCount { toolCount = len(choice.Delta.ToolCalls) @@ -84,7 +84,7 @@ func OpenaiStreamHandler(c *gin.Context, resp *http.Response, relayMode int) (*d } else { for _, streamResponse := range streamResponses { for _, choice := range streamResponse.Choices { - responseTextBuilder.WriteString(choice.Delta.Content) + responseTextBuilder.WriteString(choice.Delta.GetContentString()) if choice.Delta.ToolCalls != nil { if len(choice.Delta.ToolCalls) > toolCount { toolCount = len(choice.Delta.ToolCalls) diff --git a/relay/channel/palm/relay-palm.go b/relay/channel/palm/relay-palm.go index 3a7d4fa..6933d6f 100644 --- a/relay/channel/palm/relay-palm.go +++ b/relay/channel/palm/relay-palm.go @@ -61,7 +61,7 @@ func responsePaLM2OpenAI(response *PaLMChatResponse) *dto.OpenAITextResponse { func streamResponsePaLM2OpenAI(palmResponse *PaLMChatResponse) *dto.ChatCompletionsStreamResponse { var choice dto.ChatCompletionsStreamResponseChoice if len(palmResponse.Candidates) > 0 { - choice.Delta.Content = palmResponse.Candidates[0].Content + choice.Delta.SetContentString(palmResponse.Candidates[0].Content) } choice.FinishReason = &relaycommon.StopFinishReason var response dto.ChatCompletionsStreamResponse diff --git a/relay/channel/tencent/relay-tencent.go b/relay/channel/tencent/relay-tencent.go index 6f4cd91..c22b545 100644 --- a/relay/channel/tencent/relay-tencent.go +++ b/relay/channel/tencent/relay-tencent.go @@ -86,7 +86,7 @@ func streamResponseTencent2OpenAI(TencentResponse *TencentChatResponse) *dto.Cha } if len(TencentResponse.Choices) > 0 { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = TencentResponse.Choices[0].Delta.Content + choice.Delta.SetContentString(TencentResponse.Choices[0].Delta.Content) if TencentResponse.Choices[0].FinishReason == "stop" { choice.FinishReason = &relaycommon.StopFinishReason } @@ -138,7 +138,7 @@ func tencentStreamHandler(c *gin.Context, resp *http.Response) (*dto.OpenAIError } response := streamResponseTencent2OpenAI(&TencentResponse) if len(response.Choices) != 0 { - responseText += response.Choices[0].Delta.Content + responseText += response.Choices[0].Delta.GetContentString() } jsonResponse, err := json.Marshal(response) if err != nil { diff --git a/relay/channel/xunfei/relay-xunfei.go b/relay/channel/xunfei/relay-xunfei.go index 1690e96..7cb6c8a 100644 --- a/relay/channel/xunfei/relay-xunfei.go +++ b/relay/channel/xunfei/relay-xunfei.go @@ -87,7 +87,7 @@ func streamResponseXunfei2OpenAI(xunfeiResponse *XunfeiChatResponse) *dto.ChatCo } } var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = xunfeiResponse.Payload.Choices.Text[0].Content + choice.Delta.SetContentString(xunfeiResponse.Payload.Choices.Text[0].Content) if xunfeiResponse.Payload.Choices.Status == 2 { choice.FinishReason = &relaycommon.StopFinishReason } diff --git a/relay/channel/zhipu/relay-zhipu.go b/relay/channel/zhipu/relay-zhipu.go index 8a54842..5ef9d7a 100644 --- a/relay/channel/zhipu/relay-zhipu.go +++ b/relay/channel/zhipu/relay-zhipu.go @@ -126,7 +126,7 @@ func responseZhipu2OpenAI(response *ZhipuResponse) *dto.OpenAITextResponse { func streamResponseZhipu2OpenAI(zhipuResponse string) *dto.ChatCompletionsStreamResponse { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = zhipuResponse + choice.Delta.SetContentString(zhipuResponse) response := dto.ChatCompletionsStreamResponse{ Object: "chat.completion.chunk", Created: common.GetTimestamp(), @@ -138,7 +138,7 @@ func streamResponseZhipu2OpenAI(zhipuResponse string) *dto.ChatCompletionsStream func streamMetaResponseZhipu2OpenAI(zhipuResponse *ZhipuStreamMetaResponse) (*dto.ChatCompletionsStreamResponse, *dto.Usage) { var choice dto.ChatCompletionsStreamResponseChoice - choice.Delta.Content = "" + choice.Delta.SetContentString("") choice.FinishReason = &relaycommon.StopFinishReason response := dto.ChatCompletionsStreamResponse{ Id: zhipuResponse.RequestId, From 1c6fd879093674562073eb0518a21e79945f7577 Mon Sep 17 00:00:00 2001 From: CaIon <1808837298@qq.com> Date: Fri, 26 Apr 2024 02:56:35 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20=E8=A7=84=E8=8C=83claude=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dto/text_response.go | 14 ++++++++------ relay/channel/aws/relay-aws.go | 2 ++ relay/channel/claude/relay-claude.go | 3 ++- service/token_counter.go | 2 +- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dto/text_response.go b/dto/text_response.go index 617c375..53c87eb 100644 --- a/dto/text_response.go +++ b/dto/text_response.go @@ -55,8 +55,9 @@ type OpenAIEmbeddingResponse struct { type ChatCompletionsStreamResponseChoice struct { Delta ChatCompletionsStreamResponseChoiceDelta `json:"delta,omitempty"` + Logprobs *any `json:"logprobs"` FinishReason *string `json:"finish_reason"` - Index int `json:"index,omitempty"` + Index int `json:"index"` } type ChatCompletionsStreamResponseChoiceDelta struct { @@ -95,11 +96,12 @@ type FunctionCall struct { } type ChatCompletionsStreamResponse struct { - Id string `json:"id"` - Object string `json:"object"` - Created int64 `json:"created"` - Model string `json:"model"` - Choices []ChatCompletionsStreamResponseChoice `json:"choices"` + Id string `json:"id"` + Object string `json:"object"` + Created int64 `json:"created"` + Model string `json:"model"` + SystemFingerprint *string `json:"system_fingerprint"` + Choices []ChatCompletionsStreamResponseChoice `json:"choices"` } type ChatCompletionsStreamResponseSimple struct { diff --git a/relay/channel/aws/relay-aws.go b/relay/channel/aws/relay-aws.go index bf64f03..1438f10 100644 --- a/relay/channel/aws/relay-aws.go +++ b/relay/channel/aws/relay-aws.go @@ -156,6 +156,7 @@ func awsStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, requestMode i var usage relaymodel.Usage var id string var model string + createdTime := common.GetTimestamp() c.Stream(func(w io.Writer) bool { event, ok := <-stream.Events() if !ok { @@ -188,6 +189,7 @@ func awsStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, requestMode i if response.Model != "" { model = response.Model } + response.Created = createdTime response.Id = id response.Model = model diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index 859b7b1..07767a4 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -181,9 +181,10 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *ClaudeResponse) (* response.Id = claudeResponse.Message.Id response.Model = claudeResponse.Message.Model claudeUsage = &claudeResponse.Message.Usage - } else if claudeResponse.Type == "content_block_start" { choice.Delta.SetContentString("") choice.Delta.Role = "assistant" + } else if claudeResponse.Type == "content_block_start" { + return nil, nil } else if claudeResponse.Type == "content_block_delta" { choice.Index = claudeResponse.Index choice.Delta.SetContentString(claudeResponse.Delta.Text) diff --git a/service/token_counter.go b/service/token_counter.go index 18fc5a3..29da0f2 100644 --- a/service/token_counter.go +++ b/service/token_counter.go @@ -232,7 +232,7 @@ func CountTokenInput(input any, model string, check bool) (int, error, bool) { func CountTokenStreamChoices(messages []dto.ChatCompletionsStreamResponseChoice, model string) int { tokens := 0 for _, message := range messages { - tkm, _, _ := CountTokenInput(message.Delta.Content, model, false) + tkm, _, _ := CountTokenInput(message.Delta.GetContentString(), model, false) tokens += tkm if message.Delta.ToolCalls != nil { for _, tool := range message.Delta.ToolCalls {