mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-09 02:45:29 +08:00
120 lines
3.1 KiB
Go
120 lines
3.1 KiB
Go
package openai
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"ds2api/internal/util"
|
|
)
|
|
|
|
func BuildResponseObject(responseID, model, finalPrompt, finalThinking, finalText string, toolNames []string) map[string]any {
|
|
// Align responses tool-call semantics with chat/completions:
|
|
// mixed prose + tool_call payloads should still be interpreted as tool calls.
|
|
detected := util.ParseToolCalls(finalText, toolNames)
|
|
if len(detected) == 0 && strings.TrimSpace(finalThinking) != "" {
|
|
detected = util.ParseToolCalls(finalThinking, toolNames)
|
|
}
|
|
exposedOutputText := finalText
|
|
output := make([]any, 0, 2)
|
|
if len(detected) > 0 {
|
|
exposedOutputText = ""
|
|
if strings.TrimSpace(finalThinking) != "" {
|
|
output = append(output, map[string]any{
|
|
"type": "reasoning",
|
|
"text": finalThinking,
|
|
})
|
|
}
|
|
formatted := util.FormatOpenAIToolCalls(detected)
|
|
output = append(output, toResponsesFunctionCallItems(formatted)...)
|
|
output = append(output, map[string]any{
|
|
"type": "tool_calls",
|
|
"tool_calls": formatted,
|
|
})
|
|
} else {
|
|
content := make([]any, 0, 2)
|
|
if finalThinking != "" {
|
|
content = append([]any{map[string]any{
|
|
"type": "reasoning",
|
|
"text": finalThinking,
|
|
}}, content...)
|
|
}
|
|
if strings.TrimSpace(finalText) != "" {
|
|
content = append(content, map[string]any{
|
|
"type": "output_text",
|
|
"text": finalText,
|
|
})
|
|
}
|
|
if strings.TrimSpace(finalText) == "" && strings.TrimSpace(finalThinking) != "" {
|
|
exposedOutputText = finalThinking
|
|
}
|
|
output = append(output, map[string]any{
|
|
"type": "message",
|
|
"id": "msg_" + strings.ReplaceAll(uuid.NewString(), "-", ""),
|
|
"role": "assistant",
|
|
"content": content,
|
|
})
|
|
}
|
|
return map[string]any{
|
|
"id": responseID,
|
|
"type": "response",
|
|
"object": "response",
|
|
"created_at": time.Now().Unix(),
|
|
"status": "completed",
|
|
"model": model,
|
|
"output": output,
|
|
"output_text": exposedOutputText,
|
|
"usage": BuildResponsesUsage(finalPrompt, finalThinking, finalText),
|
|
}
|
|
}
|
|
|
|
func toResponsesFunctionCallItems(toolCalls []map[string]any) []any {
|
|
if len(toolCalls) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]any, 0, len(toolCalls))
|
|
for _, tc := range toolCalls {
|
|
callID, _ := tc["id"].(string)
|
|
if strings.TrimSpace(callID) == "" {
|
|
callID = "call_" + strings.ReplaceAll(uuid.NewString(), "-", "")
|
|
}
|
|
name := ""
|
|
args := "{}"
|
|
if fn, ok := tc["function"].(map[string]any); ok {
|
|
if n, _ := fn["name"].(string); strings.TrimSpace(n) != "" {
|
|
name = n
|
|
}
|
|
if a, _ := fn["arguments"].(string); strings.TrimSpace(a) != "" {
|
|
args = a
|
|
}
|
|
}
|
|
out = append(out, map[string]any{
|
|
"id": "fc_" + strings.ReplaceAll(uuid.NewString(), "-", ""),
|
|
"type": "function_call",
|
|
"call_id": callID,
|
|
"name": name,
|
|
"arguments": normalizeJSONString(args),
|
|
"status": "completed",
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func normalizeJSONString(raw string) string {
|
|
s := strings.TrimSpace(raw)
|
|
if s == "" {
|
|
return "{}"
|
|
}
|
|
var v any
|
|
if err := json.Unmarshal([]byte(s), &v); err != nil {
|
|
return raw
|
|
}
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return raw
|
|
}
|
|
return string(b)
|
|
}
|