|
@@ -404,15 +404,12 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe
|
|
|
return &claudeRequest, nil
|
|
return &claudeRequest, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse, claudeInfo *ClaudeResponseInfo) *dto.ChatCompletionsStreamResponse {
|
|
|
|
|
|
|
+func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse) *dto.ChatCompletionsStreamResponse {
|
|
|
var response dto.ChatCompletionsStreamResponse
|
|
var response dto.ChatCompletionsStreamResponse
|
|
|
response.Object = "chat.completion.chunk"
|
|
response.Object = "chat.completion.chunk"
|
|
|
response.Model = claudeResponse.Model
|
|
response.Model = claudeResponse.Model
|
|
|
response.Choices = make([]dto.ChatCompletionsStreamResponseChoice, 0)
|
|
response.Choices = make([]dto.ChatCompletionsStreamResponseChoice, 0)
|
|
|
tools := make([]dto.ToolCallResponse, 0)
|
|
tools := make([]dto.ToolCallResponse, 0)
|
|
|
- if claudeInfo != nil && claudeInfo.ToolCallStreamStates == nil {
|
|
|
|
|
- claudeInfo.ToolCallStreamStates = make(map[int]*ToolCallStreamState)
|
|
|
|
|
- }
|
|
|
|
|
fcIdx := 0
|
|
fcIdx := 0
|
|
|
if claudeResponse.Index != nil {
|
|
if claudeResponse.Index != nil {
|
|
|
fcIdx = *claudeResponse.Index - 1
|
|
fcIdx = *claudeResponse.Index - 1
|
|
@@ -436,13 +433,6 @@ func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse, claudeInfo
|
|
|
choice.Delta.SetContentString(*claudeResponse.ContentBlock.Text)
|
|
choice.Delta.SetContentString(*claudeResponse.ContentBlock.Text)
|
|
|
}
|
|
}
|
|
|
if claudeResponse.ContentBlock.Type == "tool_use" {
|
|
if claudeResponse.ContentBlock.Type == "tool_use" {
|
|
|
- if claudeInfo != nil {
|
|
|
|
|
- claudeInfo.ToolCallStreamStates[fcIdx] = &ToolCallStreamState{
|
|
|
|
|
- ID: claudeResponse.ContentBlock.Id,
|
|
|
|
|
- Name: claudeResponse.ContentBlock.Name,
|
|
|
|
|
- }
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
tools = append(tools, dto.ToolCallResponse{
|
|
tools = append(tools, dto.ToolCallResponse{
|
|
|
Index: common.GetPointer(fcIdx),
|
|
Index: common.GetPointer(fcIdx),
|
|
|
ID: claudeResponse.ContentBlock.Id,
|
|
ID: claudeResponse.ContentBlock.Id,
|
|
@@ -461,28 +451,19 @@ func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse, claudeInfo
|
|
|
choice.Delta.Content = claudeResponse.Delta.Text
|
|
choice.Delta.Content = claudeResponse.Delta.Text
|
|
|
switch claudeResponse.Delta.Type {
|
|
switch claudeResponse.Delta.Type {
|
|
|
case "input_json_delta":
|
|
case "input_json_delta":
|
|
|
- if claudeResponse.Delta.PartialJson == nil {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
- arguments := *claudeResponse.Delta.PartialJson
|
|
|
|
|
- if strings.TrimSpace(arguments) == "" {
|
|
|
|
|
- return nil
|
|
|
|
|
|
|
+ arguments := "{}"
|
|
|
|
|
+ if claudeResponse.Delta.PartialJson != nil {
|
|
|
|
|
+ if partial := strings.TrimSpace(*claudeResponse.Delta.PartialJson); partial != "" {
|
|
|
|
|
+ arguments = partial
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- toolCall := dto.ToolCallResponse{
|
|
|
|
|
|
|
+ tools = append(tools, dto.ToolCallResponse{
|
|
|
Type: "function",
|
|
Type: "function",
|
|
|
Index: common.GetPointer(fcIdx),
|
|
Index: common.GetPointer(fcIdx),
|
|
|
Function: dto.FunctionResponse{
|
|
Function: dto.FunctionResponse{
|
|
|
Arguments: arguments,
|
|
Arguments: arguments,
|
|
|
},
|
|
},
|
|
|
- }
|
|
|
|
|
- if claudeInfo != nil {
|
|
|
|
|
- if state, ok := claudeInfo.ToolCallStreamStates[fcIdx]; ok {
|
|
|
|
|
- state.Emitted = true
|
|
|
|
|
- toolCall.ID = state.ID
|
|
|
|
|
- toolCall.Function.Name = state.Name
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- tools = append(tools, toolCall)
|
|
|
|
|
|
|
+ })
|
|
|
case "signature_delta":
|
|
case "signature_delta":
|
|
|
// 加密的不处理
|
|
// 加密的不处理
|
|
|
signatureContent := "\n"
|
|
signatureContent := "\n"
|
|
@@ -491,27 +472,6 @@ func StreamResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse, claudeInfo
|
|
|
choice.Delta.ReasoningContent = claudeResponse.Delta.Thinking
|
|
choice.Delta.ReasoningContent = claudeResponse.Delta.Thinking
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- } else if claudeResponse.Type == "content_block_stop" {
|
|
|
|
|
- if claudeInfo == nil {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
- state, ok := claudeInfo.ToolCallStreamStates[fcIdx]
|
|
|
|
|
- if !ok {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
- delete(claudeInfo.ToolCallStreamStates, fcIdx)
|
|
|
|
|
- if state.Emitted {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
- tools = append(tools, dto.ToolCallResponse{
|
|
|
|
|
- ID: state.ID,
|
|
|
|
|
- Type: "function",
|
|
|
|
|
- Index: common.GetPointer(fcIdx),
|
|
|
|
|
- Function: dto.FunctionResponse{
|
|
|
|
|
- Name: state.Name,
|
|
|
|
|
- Arguments: "{}",
|
|
|
|
|
- },
|
|
|
|
|
- })
|
|
|
|
|
} else if claudeResponse.Type == "message_delta" {
|
|
} else if claudeResponse.Type == "message_delta" {
|
|
|
if claudeResponse.Delta != nil && claudeResponse.Delta.StopReason != nil {
|
|
if claudeResponse.Delta != nil && claudeResponse.Delta.StopReason != nil {
|
|
|
finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason)
|
|
finishReason := stopReasonClaude2OpenAI(*claudeResponse.Delta.StopReason)
|
|
@@ -596,19 +556,12 @@ func ResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse) *dto.OpenAITextRe
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type ClaudeResponseInfo struct {
|
|
type ClaudeResponseInfo struct {
|
|
|
- ResponseId string
|
|
|
|
|
- Created int64
|
|
|
|
|
- Model string
|
|
|
|
|
- ResponseText strings.Builder
|
|
|
|
|
- Usage *dto.Usage
|
|
|
|
|
- Done bool
|
|
|
|
|
- ToolCallStreamStates map[int]*ToolCallStreamState
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-type ToolCallStreamState struct {
|
|
|
|
|
- ID string
|
|
|
|
|
- Name string
|
|
|
|
|
- Emitted bool
|
|
|
|
|
|
|
+ ResponseId string
|
|
|
|
|
+ Created int64
|
|
|
|
|
+ Model string
|
|
|
|
|
+ ResponseText strings.Builder
|
|
|
|
|
+ Usage *dto.Usage
|
|
|
|
|
+ Done bool
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func buildMessageDeltaPatchUsage(claudeResponse *dto.ClaudeResponse, claudeInfo *ClaudeResponseInfo) *dto.ClaudeUsage {
|
|
func buildMessageDeltaPatchUsage(claudeResponse *dto.ClaudeResponse, claudeInfo *ClaudeResponseInfo) *dto.ClaudeUsage {
|
|
@@ -741,7 +694,7 @@ func FormatClaudeResponseInfo(claudeResponse *dto.ClaudeResponse, oaiResponse *d
|
|
|
|
|
|
|
|
// 判断是否完整
|
|
// 判断是否完整
|
|
|
claudeInfo.Done = true
|
|
claudeInfo.Done = true
|
|
|
- } else if claudeResponse.Type == "content_block_start" || claudeResponse.Type == "content_block_stop" {
|
|
|
|
|
|
|
+ } else if claudeResponse.Type == "content_block_start" {
|
|
|
} else {
|
|
} else {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
@@ -786,10 +739,7 @@ func HandleStreamResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud
|
|
|
}
|
|
}
|
|
|
helper.ClaudeChunkData(c, claudeResponse, data)
|
|
helper.ClaudeChunkData(c, claudeResponse, data)
|
|
|
} else if info.RelayFormat == types.RelayFormatOpenAI {
|
|
} else if info.RelayFormat == types.RelayFormatOpenAI {
|
|
|
- response := StreamResponseClaude2OpenAI(&claudeResponse, claudeInfo)
|
|
|
|
|
- if response == nil {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ response := StreamResponseClaude2OpenAI(&claudeResponse)
|
|
|
|
|
|
|
|
if !FormatClaudeResponseInfo(&claudeResponse, response, claudeInfo) {
|
|
if !FormatClaudeResponseInfo(&claudeResponse, response, claudeInfo) {
|
|
|
return nil
|
|
return nil
|