mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-11 19:57:41 +08:00
154 lines
3.4 KiB
Go
154 lines
3.4 KiB
Go
package gemini
|
|
|
|
import "strings"
|
|
|
|
func geminiMessagesFromRequest(req map[string]any) []any {
|
|
out := make([]any, 0, 8)
|
|
if sys := normalizeGeminiSystemInstruction(req["systemInstruction"]); strings.TrimSpace(sys) != "" {
|
|
out = append(out, map[string]any{
|
|
"role": "system",
|
|
"content": sys,
|
|
})
|
|
}
|
|
|
|
contents, _ := req["contents"].([]any)
|
|
for _, item := range contents {
|
|
content, ok := item.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
role := mapGeminiRole(content["role"])
|
|
if role == "" {
|
|
role = "user"
|
|
}
|
|
parts, _ := content["parts"].([]any)
|
|
if len(parts) == 0 {
|
|
if text := strings.TrimSpace(asString(content["text"])); text != "" {
|
|
out = append(out, map[string]any{
|
|
"role": role,
|
|
"content": text,
|
|
})
|
|
}
|
|
continue
|
|
}
|
|
|
|
textParts := make([]string, 0, len(parts))
|
|
flushText := func() {
|
|
if len(textParts) == 0 {
|
|
return
|
|
}
|
|
out = append(out, map[string]any{
|
|
"role": role,
|
|
"content": strings.Join(textParts, "\n"),
|
|
})
|
|
textParts = textParts[:0]
|
|
}
|
|
|
|
for _, rawPart := range parts {
|
|
part, ok := rawPart.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if text := strings.TrimSpace(asString(part["text"])); text != "" {
|
|
textParts = append(textParts, text)
|
|
continue
|
|
}
|
|
|
|
if fnCall, ok := part["functionCall"].(map[string]any); ok {
|
|
flushText()
|
|
if name := strings.TrimSpace(asString(fnCall["name"])); name != "" {
|
|
callID := strings.TrimSpace(asString(fnCall["id"]))
|
|
if callID == "" {
|
|
callID = "call_gemini"
|
|
}
|
|
out = append(out, map[string]any{
|
|
"role": "assistant",
|
|
"tool_calls": []any{
|
|
map[string]any{
|
|
"id": callID,
|
|
"type": "function",
|
|
"function": map[string]any{
|
|
"name": name,
|
|
"arguments": stringifyJSON(fnCall["args"]),
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
continue
|
|
}
|
|
|
|
if fnResp, ok := part["functionResponse"].(map[string]any); ok {
|
|
flushText()
|
|
name := strings.TrimSpace(asString(fnResp["name"]))
|
|
callID := strings.TrimSpace(asString(fnResp["id"]))
|
|
if callID == "" {
|
|
callID = strings.TrimSpace(asString(fnResp["callId"]))
|
|
}
|
|
if callID == "" {
|
|
callID = strings.TrimSpace(asString(fnResp["tool_call_id"]))
|
|
}
|
|
if callID == "" {
|
|
callID = "call_gemini"
|
|
}
|
|
content := fnResp["response"]
|
|
if content == nil {
|
|
content = fnResp["output"]
|
|
}
|
|
if content == nil {
|
|
content = ""
|
|
}
|
|
msg := map[string]any{
|
|
"role": "tool",
|
|
"tool_call_id": callID,
|
|
"content": content,
|
|
}
|
|
if name != "" {
|
|
msg["name"] = name
|
|
}
|
|
out = append(out, msg)
|
|
}
|
|
}
|
|
flushText()
|
|
}
|
|
return out
|
|
}
|
|
|
|
func normalizeGeminiSystemInstruction(raw any) string {
|
|
switch v := raw.(type) {
|
|
case string:
|
|
return strings.TrimSpace(v)
|
|
case map[string]any:
|
|
if parts, ok := v["parts"].([]any); ok {
|
|
texts := make([]string, 0, len(parts))
|
|
for _, item := range parts {
|
|
part, ok := item.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if text := strings.TrimSpace(asString(part["text"])); text != "" {
|
|
texts = append(texts, text)
|
|
}
|
|
}
|
|
return strings.Join(texts, "\n")
|
|
}
|
|
if text := strings.TrimSpace(asString(v["text"])); text != "" {
|
|
return text
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func mapGeminiRole(v any) string {
|
|
switch strings.ToLower(strings.TrimSpace(asString(v))) {
|
|
case "user":
|
|
return "user"
|
|
case "model", "assistant":
|
|
return "assistant"
|
|
case "system":
|
|
return "system"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|