package geminichat import ( "fmt" "strings" "github.com/QuantumNous/new-api/relaykit/dto" "github.com/QuantumNous/new-api/relaykit/relayconvert/convmeta" "github.com/QuantumNous/new-api/relaykit/relayconvert/internal/jsonutil" kitutil "github.com/QuantumNous/new-api/relaykit/relayconvert/kitutil" ) func GeminiGenerateContentRequestToOpenAIChat(geminiRequest *dto.GeminiChatRequest, info convmeta.Meta) (*dto.GeneralOpenAIRequest, error) { modelName := "" isStream := false if info != nil { isStream = info.GetIsStream() } modelName = convmeta.UpstreamModelName(info) openaiRequest := &dto.GeneralOpenAIRequest{ Model: modelName, Stream: kitutil.GetPointer(isStream), } var messages []dto.Message for _, content := range geminiRequest.Contents { message := dto.Message{ Role: convertGeminiRoleToOpenAI(content.Role), } var mediaContents []dto.MediaContent var toolCalls []dto.ToolCallRequest for _, part := range content.Parts { if part.Text != "" { mediaContent := dto.MediaContent{ Type: "text", Text: part.Text, } mediaContents = append(mediaContents, mediaContent) } else if part.InlineData != nil { mediaContent := dto.MediaContent{ Type: "image_url", ImageUrl: &dto.MessageImageUrl{ Url: fmt.Sprintf("data:%s;base64,%s", part.InlineData.MimeType, part.InlineData.Data), Detail: "auto", MimeType: part.InlineData.MimeType, }, } mediaContents = append(mediaContents, mediaContent) } else if part.FileData != nil { mediaContent := dto.MediaContent{ Type: "image_url", ImageUrl: &dto.MessageImageUrl{ Url: part.FileData.FileUri, Detail: "auto", MimeType: part.FileData.MimeType, }, } mediaContents = append(mediaContents, mediaContent) } else if part.FunctionCall != nil { toolCall := dto.ToolCallRequest{ ID: fmt.Sprintf("call_%d", len(toolCalls)+1), Type: "function", Function: dto.FunctionRequest{ Name: part.FunctionCall.FunctionName, Arguments: jsonutil.ToJSONString(part.FunctionCall.Arguments), }, } toolCalls = append(toolCalls, toolCall) } else if part.FunctionResponse != nil { toolMessage := dto.Message{ Role: "tool", ToolCallId: fmt.Sprintf("call_%d", len(toolCalls)), } toolMessage.SetStringContent(jsonutil.ToJSONString(part.FunctionResponse.Response)) messages = append(messages, toolMessage) } } if len(toolCalls) > 0 { message.SetToolCalls(toolCalls) } else if len(mediaContents) == 1 && mediaContents[0].Type == "text" { message.Content = mediaContents[0].Text } else if len(mediaContents) > 0 { message.SetMediaContent(mediaContents) } if len(message.ParseContent()) > 0 || len(message.ToolCalls) > 0 { messages = append(messages, message) } } openaiRequest.Messages = messages if geminiRequest.GenerationConfig.Temperature != nil { openaiRequest.Temperature = geminiRequest.GenerationConfig.Temperature } if geminiRequest.GenerationConfig.TopP != nil && *geminiRequest.GenerationConfig.TopP > 0 { openaiRequest.TopP = kitutil.GetPointer(*geminiRequest.GenerationConfig.TopP) } if geminiRequest.GenerationConfig.TopK != nil && *geminiRequest.GenerationConfig.TopK > 0 { openaiRequest.TopK = kitutil.GetPointer(int(*geminiRequest.GenerationConfig.TopK)) } if geminiRequest.GenerationConfig.MaxOutputTokens != nil && *geminiRequest.GenerationConfig.MaxOutputTokens > 0 { openaiRequest.MaxTokens = kitutil.GetPointer(*geminiRequest.GenerationConfig.MaxOutputTokens) } if len(geminiRequest.GenerationConfig.StopSequences) > 0 { openaiRequest.Stop = geminiRequest.GenerationConfig.StopSequences[:min(len(geminiRequest.GenerationConfig.StopSequences), 4)] } if geminiRequest.GenerationConfig.CandidateCount != nil && *geminiRequest.GenerationConfig.CandidateCount > 0 { openaiRequest.N = kitutil.GetPointer(*geminiRequest.GenerationConfig.CandidateCount) } if len(geminiRequest.GetTools()) > 0 { var tools []dto.ToolCallRequest for _, tool := range geminiRequest.GetTools() { if tool.FunctionDeclarations == nil { continue } functionDeclarations, err := kitutil.Any2Type[[]dto.FunctionRequest](tool.FunctionDeclarations) if err != nil { kitutil.LogSystemError(fmt.Sprintf("failed to parse gemini function declarations: %v (type=%T)", err, tool.FunctionDeclarations)) continue } for _, function := range functionDeclarations { openAITool := dto.ToolCallRequest{ Type: "function", Function: dto.FunctionRequest{ Name: function.Name, Description: function.Description, Parameters: function.Parameters, }, } tools = append(tools, openAITool) } } if len(tools) > 0 { openaiRequest.Tools = tools } } if geminiRequest.SystemInstructions != nil { systemMessage := dto.Message{ Role: "system", Content: extractTextFromGeminiParts(geminiRequest.SystemInstructions.Parts), } openaiRequest.Messages = append([]dto.Message{systemMessage}, openaiRequest.Messages...) } return openaiRequest, nil } func convertGeminiRoleToOpenAI(geminiRole string) string { switch geminiRole { case "user": return "user" case "model": return "assistant" case "function": return "function" default: return "user" } } func extractTextFromGeminiParts(parts []dto.GeminiPart) string { texts := make([]string, 0) for _, part := range parts { if part.Text != "" { texts = append(texts, part.Text) } } return strings.Join(texts, "\n") }