diff --git a/relay/channel/claude/relay-claude.go b/relay/channel/claude/relay-claude.go index f9f4d4d09..7faa2ac9f 100644 --- a/relay/channel/claude/relay-claude.go +++ b/relay/channel/claude/relay-claude.go @@ -437,8 +437,10 @@ func StreamResponseClaude2OpenAI(reqMode int, claudeResponse *dto.ClaudeResponse } } else { if claudeResponse.Type == "message_start" { - response.Id = claudeResponse.Message.Id - response.Model = claudeResponse.Message.Model + 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" @@ -589,35 +591,49 @@ type ClaudeResponseInfo struct { } func FormatClaudeResponseInfo(requestMode int, 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" { - claudeInfo.ResponseId = claudeResponse.Message.Id - claudeInfo.Model = claudeResponse.Message.Model + if claudeResponse.Message != nil { + claudeInfo.ResponseId = claudeResponse.Message.Id + claudeInfo.Model = claudeResponse.Message.Model + } // message_start, 获取usage - 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.Text != nil { - claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Text) + 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 } - if claudeResponse.Delta.Thinking != nil { - claudeInfo.ResponseText.WriteString(*claudeResponse.Delta.Thinking) + } 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.InputTokens > 0 { - // 不叠加,只取最新的 - claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens + if claudeResponse.Usage != nil { + if claudeResponse.Usage.InputTokens > 0 { + // 不叠加,只取最新的 + claudeInfo.Usage.PromptTokens = claudeResponse.Usage.InputTokens + } + claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens + claudeInfo.Usage.TotalTokens = claudeInfo.Usage.PromptTokens + claudeInfo.Usage.CompletionTokens } - claudeInfo.Usage.CompletionTokens = claudeResponse.Usage.OutputTokens - claudeInfo.Usage.TotalTokens = claudeInfo.Usage.PromptTokens + claudeInfo.Usage.CompletionTokens // 判断是否完整 claudeInfo.Done = true @@ -657,7 +673,9 @@ func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud } else { if claudeResponse.Type == "message_start" { // message_start, 获取usage - info.UpstreamModelName = claudeResponse.Message.Model + if claudeResponse.Message != nil { + info.UpstreamModelName = claudeResponse.Message.Model + } } else if claudeResponse.Type == "content_block_delta" { } else if claudeResponse.Type == "message_delta" { } @@ -745,13 +763,18 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud if requestMode == RequestModeCompletion { claudeInfo.Usage = service.ResponseText2Usage(c, claudeResponse.Completion, info.UpstreamModelName, info.GetEstimatePromptTokens()) } else { - 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 { @@ -766,7 +789,7 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud responseData = data } - if claudeResponse.Usage.ServerToolUse != nil && claudeResponse.Usage.ServerToolUse.WebSearchRequests > 0 { + if claudeResponse.Usage != nil && claudeResponse.Usage.ServerToolUse != nil && claudeResponse.Usage.ServerToolUse.WebSearchRequests > 0 { c.Set("claude_web_search_requests", claudeResponse.Usage.ServerToolUse.WebSearchRequests) }