135 lines
2.8 KiB
Go
135 lines
2.8 KiB
Go
package anthropic
|
|
|
|
import (
|
|
"cursor-api-proxy/internal/openai"
|
|
"strings"
|
|
)
|
|
|
|
type MessageParam struct {
|
|
Role string `json:"role"`
|
|
Content interface{} `json:"content"`
|
|
}
|
|
|
|
type MessagesRequest struct {
|
|
Model string `json:"model"`
|
|
MaxTokens int `json:"max_tokens"`
|
|
Messages []MessageParam `json:"messages"`
|
|
System interface{} `json:"system"`
|
|
Stream bool `json:"stream"`
|
|
Tools []interface{} `json:"tools"`
|
|
}
|
|
|
|
func systemToText(system interface{}) string {
|
|
if system == nil {
|
|
return ""
|
|
}
|
|
switch v := system.(type) {
|
|
case string:
|
|
return strings.TrimSpace(v)
|
|
case []interface{}:
|
|
var parts []string
|
|
for _, p := range v {
|
|
if m, ok := p.(map[string]interface{}); ok {
|
|
if m["type"] == "text" {
|
|
if t, ok := m["text"].(string); ok {
|
|
parts = append(parts, t)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return strings.Join(parts, "\n")
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func anthropicBlockToText(p interface{}) string {
|
|
if p == nil {
|
|
return ""
|
|
}
|
|
switch v := p.(type) {
|
|
case string:
|
|
return v
|
|
case map[string]interface{}:
|
|
typ, _ := v["type"].(string)
|
|
switch typ {
|
|
case "text":
|
|
if t, ok := v["text"].(string); ok {
|
|
return t
|
|
}
|
|
case "image":
|
|
if src, ok := v["source"].(map[string]interface{}); ok {
|
|
srcType, _ := src["type"].(string)
|
|
switch srcType {
|
|
case "base64":
|
|
mt, _ := src["media_type"].(string)
|
|
if mt == "" {
|
|
mt = "image"
|
|
}
|
|
return "[Image: base64 " + mt + "]"
|
|
case "url":
|
|
url, _ := src["url"].(string)
|
|
return "[Image: " + url + "]"
|
|
}
|
|
}
|
|
return "[Image]"
|
|
case "document":
|
|
title, _ := v["title"].(string)
|
|
if title == "" {
|
|
if src, ok := v["source"].(map[string]interface{}); ok {
|
|
title, _ = src["url"].(string)
|
|
}
|
|
}
|
|
if title != "" {
|
|
return "[Document: " + title + "]"
|
|
}
|
|
return "[Document]"
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func anthropicContentToText(content interface{}) string {
|
|
switch v := content.(type) {
|
|
case string:
|
|
return v
|
|
case []interface{}:
|
|
var parts []string
|
|
for _, p := range v {
|
|
if t := anthropicBlockToText(p); t != "" {
|
|
parts = append(parts, t)
|
|
}
|
|
}
|
|
return strings.Join(parts, " ")
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func BuildPromptFromAnthropicMessages(messages []MessageParam, system interface{}) string {
|
|
var oaiMessages []interface{}
|
|
|
|
systemText := systemToText(system)
|
|
if systemText != "" {
|
|
oaiMessages = append(oaiMessages, map[string]interface{}{
|
|
"role": "system",
|
|
"content": systemText,
|
|
})
|
|
}
|
|
|
|
for _, m := range messages {
|
|
text := anthropicContentToText(m.Content)
|
|
if text == "" {
|
|
continue
|
|
}
|
|
role := m.Role
|
|
if role != "user" && role != "assistant" {
|
|
role = "user"
|
|
}
|
|
oaiMessages = append(oaiMessages, map[string]interface{}{
|
|
"role": role,
|
|
"content": text,
|
|
})
|
|
}
|
|
|
|
return openai.BuildPromptFromMessages(oaiMessages)
|
|
}
|