mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
Fixed: #97
feat(translator): enhance request and response parsing for Gemini API and CLI - Added support for removing predefined JSON paths (`additionalProperties`, `$schema`, `ref`) during request transformation for Gemini. - Introduced `FunctionIndex` parameter to manage function call indexing in streaming responses for both API and CLI translators. - Improved handling of tool call content and function call templates in response parsing logic.
This commit is contained in:
@@ -26,6 +26,20 @@ import (
|
|||||||
// - []byte: The transformed request data in Gemini CLI API format
|
// - []byte: The transformed request data in Gemini CLI API format
|
||||||
func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bool) []byte {
|
func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bool) []byte {
|
||||||
rawJSON := bytes.Clone(inputRawJSON)
|
rawJSON := bytes.Clone(inputRawJSON)
|
||||||
|
var pathsToDelete []string
|
||||||
|
root := gjson.ParseBytes(rawJSON)
|
||||||
|
util.Walk(root, "", "additionalProperties", &pathsToDelete)
|
||||||
|
util.Walk(root, "", "$schema", &pathsToDelete)
|
||||||
|
util.Walk(root, "", "ref", &pathsToDelete)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _, p := range pathsToDelete {
|
||||||
|
rawJSON, err = sjson.DeleteBytes(rawJSON, p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Base envelope
|
// Base envelope
|
||||||
out := []byte(`{"project":"","request":{"contents":[],"generationConfig":{"thinkingConfig":{"include_thoughts":true}}},"model":"gemini-2.5-pro"}`)
|
out := []byte(`{"project":"","request":{"contents":[],"generationConfig":{"thinkingConfig":{"include_thoughts":true}}},"model":"gemini-2.5-pro"}`)
|
||||||
|
|
||||||
@@ -232,7 +246,7 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pathsToType []string
|
var pathsToType []string
|
||||||
root := gjson.ParseBytes(out)
|
root = gjson.ParseBytes(out)
|
||||||
util.Walk(root, "", "type", &pathsToType)
|
util.Walk(root, "", "type", &pathsToType)
|
||||||
for _, p := range pathsToType {
|
for _, p := range pathsToType {
|
||||||
typeResult := gjson.GetBytes(out, p)
|
typeResult := gjson.GetBytes(out, p)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
// convertCliResponseToOpenAIChatParams holds parameters for response conversion.
|
// convertCliResponseToOpenAIChatParams holds parameters for response conversion.
|
||||||
type convertCliResponseToOpenAIChatParams struct {
|
type convertCliResponseToOpenAIChatParams struct {
|
||||||
UnixTimestamp int64
|
UnixTimestamp int64
|
||||||
|
FunctionIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertCliResponseToOpenAI translates a single chunk of a streaming response from the
|
// ConvertCliResponseToOpenAI translates a single chunk of a streaming response from the
|
||||||
@@ -40,6 +41,7 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ
|
|||||||
if *param == nil {
|
if *param == nil {
|
||||||
*param = &convertCliResponseToOpenAIChatParams{
|
*param = &convertCliResponseToOpenAIChatParams{
|
||||||
UnixTimestamp: 0,
|
UnixTimestamp: 0,
|
||||||
|
FunctionIndex: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +119,18 @@ func ConvertCliResponseToOpenAI(_ context.Context, _ string, originalRequestRawJ
|
|||||||
} else if functionCallResult.Exists() {
|
} else if functionCallResult.Exists() {
|
||||||
// Handle function call content.
|
// Handle function call content.
|
||||||
toolCallsResult := gjson.Get(template, "choices.0.delta.tool_calls")
|
toolCallsResult := gjson.Get(template, "choices.0.delta.tool_calls")
|
||||||
if !toolCallsResult.Exists() || !toolCallsResult.IsArray() {
|
functionCallIndex := (*param).(*convertCliResponseToOpenAIChatParams).FunctionIndex
|
||||||
|
(*param).(*convertCliResponseToOpenAIChatParams).FunctionIndex++
|
||||||
|
if toolCallsResult.Exists() && toolCallsResult.IsArray() {
|
||||||
|
functionCallIndex = len(toolCallsResult.Array())
|
||||||
|
} else {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionCallTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}`
|
functionCallTemplate := `{"id": "","index": 0,"type": "function","function": {"name": "","arguments": ""}}`
|
||||||
fcName := functionCallResult.Get("name").String()
|
fcName := functionCallResult.Get("name").String()
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
|
||||||
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "index", functionCallIndex)
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.name", fcName)
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.name", fcName)
|
||||||
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
|
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.arguments", fcArgsResult.Raw)
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.arguments", fcArgsResult.Raw)
|
||||||
|
|||||||
@@ -26,6 +26,20 @@ import (
|
|||||||
// - []byte: The transformed request data in Gemini API format
|
// - []byte: The transformed request data in Gemini API format
|
||||||
func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool) []byte {
|
func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool) []byte {
|
||||||
rawJSON := bytes.Clone(inputRawJSON)
|
rawJSON := bytes.Clone(inputRawJSON)
|
||||||
|
var pathsToDelete []string
|
||||||
|
root := gjson.ParseBytes(rawJSON)
|
||||||
|
util.Walk(root, "", "additionalProperties", &pathsToDelete)
|
||||||
|
util.Walk(root, "", "$schema", &pathsToDelete)
|
||||||
|
util.Walk(root, "", "ref", &pathsToDelete)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _, p := range pathsToDelete {
|
||||||
|
rawJSON, err = sjson.DeleteBytes(rawJSON, p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Base envelope
|
// Base envelope
|
||||||
out := []byte(`{"contents":[],"generationConfig":{"thinkingConfig":{"include_thoughts":true}}}`)
|
out := []byte(`{"contents":[],"generationConfig":{"thinkingConfig":{"include_thoughts":true}}}`)
|
||||||
|
|
||||||
@@ -257,7 +271,7 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pathsToType []string
|
var pathsToType []string
|
||||||
root := gjson.ParseBytes(out)
|
root = gjson.ParseBytes(out)
|
||||||
util.Walk(root, "", "type", &pathsToType)
|
util.Walk(root, "", "type", &pathsToType)
|
||||||
for _, p := range pathsToType {
|
for _, p := range pathsToType {
|
||||||
typeResult := gjson.GetBytes(out, p)
|
typeResult := gjson.GetBytes(out, p)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
// convertGeminiResponseToOpenAIChatParams holds parameters for response conversion.
|
// convertGeminiResponseToOpenAIChatParams holds parameters for response conversion.
|
||||||
type convertGeminiResponseToOpenAIChatParams struct {
|
type convertGeminiResponseToOpenAIChatParams struct {
|
||||||
UnixTimestamp int64
|
UnixTimestamp int64
|
||||||
|
FunctionIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertGeminiResponseToOpenAI translates a single chunk of a streaming response from the
|
// ConvertGeminiResponseToOpenAI translates a single chunk of a streaming response from the
|
||||||
@@ -39,6 +40,7 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
|
|||||||
if *param == nil {
|
if *param == nil {
|
||||||
*param = &convertGeminiResponseToOpenAIChatParams{
|
*param = &convertGeminiResponseToOpenAIChatParams{
|
||||||
UnixTimestamp: 0,
|
UnixTimestamp: 0,
|
||||||
|
FunctionIndex: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,13 +122,18 @@ func ConvertGeminiResponseToOpenAI(_ context.Context, _ string, originalRequestR
|
|||||||
} else if functionCallResult.Exists() {
|
} else if functionCallResult.Exists() {
|
||||||
// Handle function call content.
|
// Handle function call content.
|
||||||
toolCallsResult := gjson.Get(template, "choices.0.delta.tool_calls")
|
toolCallsResult := gjson.Get(template, "choices.0.delta.tool_calls")
|
||||||
if !toolCallsResult.Exists() || !toolCallsResult.IsArray() {
|
functionCallIndex := (*param).(*convertGeminiResponseToOpenAIChatParams).FunctionIndex
|
||||||
|
(*param).(*convertGeminiResponseToOpenAIChatParams).FunctionIndex++
|
||||||
|
if toolCallsResult.Exists() && toolCallsResult.IsArray() {
|
||||||
|
functionCallIndex = len(toolCallsResult.Array())
|
||||||
|
} else {
|
||||||
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`)
|
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`)
|
||||||
}
|
}
|
||||||
|
|
||||||
functionCallTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}`
|
functionCallTemplate := `{"id": "","index": 0,"type": "function","function": {"name": "","arguments": ""}}`
|
||||||
fcName := functionCallResult.Get("name").String()
|
fcName := functionCallResult.Get("name").String()
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
|
||||||
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "index", functionCallIndex)
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.name", fcName)
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.name", fcName)
|
||||||
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
|
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
|
||||||
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.arguments", fcArgsResult.Raw)
|
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.arguments", fcArgsResult.Raw)
|
||||||
|
|||||||
Reference in New Issue
Block a user