mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-19 22:53:41 +08:00
- Add MessageContent type to handle both string and array content formats - Implement UnmarshalJSON to automatically detect content format - Add ToContentArray() method for unified content processing - Update Message and Response structs to use MessageContent - Fix all content processing logic in main.go and controller - Resolve JSON parsing errors for different content formats 支持Anthropic协议字符串和数组内容格式: - 添加MessageContent类型处理字符串和数组两种内容格式 - 实现UnmarshalJSON自动检测内容格式 - 添加ToContentArray()方法统一内容处理 - 更新Message和Response结构体使用MessageContent - 修复main.go和controller中的所有内容处理逻辑 - 解决不同内容格式的JSON解析错误
225 lines
5.6 KiB
Go
225 lines
5.6 KiB
Go
package anthropic
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// https://docs.anthropic.com/claude/reference/messages_post
|
|
|
|
type Metadata struct {
|
|
UserId string `json:"user_id"`
|
|
}
|
|
|
|
type ImageSource struct {
|
|
Type string `json:"type"`
|
|
MediaType string `json:"media_type"`
|
|
Data string `json:"data"`
|
|
}
|
|
|
|
type Content struct {
|
|
Type string `json:"type"`
|
|
Text string `json:"text,omitempty"`
|
|
Source *ImageSource `json:"source,omitempty"`
|
|
// tool_calls
|
|
Id string `json:"id,omitempty"`
|
|
Name string `json:"name,omitempty"`
|
|
Input any `json:"input,omitempty"`
|
|
Content string `json:"content,omitempty"`
|
|
ToolUseId string `json:"tool_use_id,omitempty"`
|
|
}
|
|
|
|
// MessageContent can handle both string and array formats for the content field
|
|
type MessageContent struct {
|
|
value interface{}
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler to handle both string and array formats
|
|
func (m *MessageContent) UnmarshalJSON(data []byte) error {
|
|
// Try to unmarshal as string first
|
|
var str string
|
|
if err := json.Unmarshal(data, &str); err == nil {
|
|
m.value = str
|
|
return nil
|
|
}
|
|
|
|
// If that fails, try to unmarshal as array of Content
|
|
var arr []Content
|
|
if err := json.Unmarshal(data, &arr); err == nil {
|
|
m.value = arr
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("message content must be either a string or an array of content blocks")
|
|
}
|
|
|
|
// MarshalJSON implements json.Marshaler
|
|
func (m MessageContent) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(m.value)
|
|
}
|
|
|
|
// ToContentArray converts the message content to a []Content array
|
|
func (m MessageContent) ToContentArray() []Content {
|
|
if m.value == nil {
|
|
return []Content{}
|
|
}
|
|
|
|
switch v := m.value.(type) {
|
|
case string:
|
|
// Convert string to a single text content block
|
|
return []Content{{
|
|
Type: "text",
|
|
Text: v,
|
|
}}
|
|
case []Content:
|
|
return v
|
|
default:
|
|
return []Content{}
|
|
}
|
|
}
|
|
|
|
type Message struct {
|
|
Role string `json:"role"`
|
|
Content MessageContent `json:"content"`
|
|
}
|
|
|
|
type Tool struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
InputSchema InputSchema `json:"input_schema"`
|
|
}
|
|
|
|
type InputSchema struct {
|
|
Type string `json:"type"`
|
|
Properties any `json:"properties,omitempty"`
|
|
Required any `json:"required,omitempty"`
|
|
}
|
|
|
|
// SystemPrompt can handle both string and array formats for the system field
|
|
type SystemPrompt struct {
|
|
value interface{}
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler to handle both string and array formats
|
|
func (s *SystemPrompt) UnmarshalJSON(data []byte) error {
|
|
// Try to unmarshal as string first
|
|
var str string
|
|
if err := json.Unmarshal(data, &str); err == nil {
|
|
s.value = str
|
|
return nil
|
|
}
|
|
|
|
// If that fails, try to unmarshal as array
|
|
var arr []interface{}
|
|
if err := json.Unmarshal(data, &arr); err == nil {
|
|
s.value = arr
|
|
return nil
|
|
}
|
|
|
|
return fmt.Errorf("system field must be either a string or an array")
|
|
}
|
|
|
|
// MarshalJSON implements json.Marshaler
|
|
func (s SystemPrompt) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(s.value)
|
|
}
|
|
|
|
// String returns the system prompt as a string
|
|
func (s SystemPrompt) String() string {
|
|
if s.value == nil {
|
|
return ""
|
|
}
|
|
|
|
switch v := s.value.(type) {
|
|
case string:
|
|
return v
|
|
case []interface{}:
|
|
// Convert array to string by concatenating text content
|
|
var result string
|
|
for _, item := range v {
|
|
if itemMap, ok := item.(map[string]interface{}); ok {
|
|
if text, exists := itemMap["text"]; exists {
|
|
if textStr, ok := text.(string); ok {
|
|
result += textStr + " "
|
|
}
|
|
}
|
|
} else if str, ok := item.(string); ok {
|
|
result += str + " "
|
|
}
|
|
}
|
|
return result
|
|
default:
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
}
|
|
|
|
// IsEmpty returns true if the system prompt is empty
|
|
func (s SystemPrompt) IsEmpty() bool {
|
|
if s.value == nil {
|
|
return true
|
|
}
|
|
|
|
switch v := s.value.(type) {
|
|
case string:
|
|
return v == ""
|
|
case []interface{}:
|
|
return len(v) == 0
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
type Request struct {
|
|
Model string `json:"model"`
|
|
Messages []Message `json:"messages"`
|
|
System SystemPrompt `json:"system,omitempty"`
|
|
MaxTokens int `json:"max_tokens,omitempty"`
|
|
StopSequences []string `json:"stop_sequences,omitempty"`
|
|
Stream bool `json:"stream,omitempty"`
|
|
Temperature *float64 `json:"temperature,omitempty"`
|
|
TopP *float64 `json:"top_p,omitempty"`
|
|
TopK int `json:"top_k,omitempty"`
|
|
Tools []Tool `json:"tools,omitempty"`
|
|
ToolChoice any `json:"tool_choice,omitempty"`
|
|
//Metadata `json:"metadata,omitempty"`
|
|
}
|
|
|
|
type Usage struct {
|
|
InputTokens int `json:"input_tokens"`
|
|
OutputTokens int `json:"output_tokens"`
|
|
}
|
|
|
|
type Error struct {
|
|
Type string `json:"type"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
type Response struct {
|
|
Id string `json:"id"`
|
|
Type string `json:"type"`
|
|
Role string `json:"role"`
|
|
Content MessageContent `json:"content"`
|
|
Model string `json:"model"`
|
|
StopReason *string `json:"stop_reason"`
|
|
StopSequence *string `json:"stop_sequence"`
|
|
Usage Usage `json:"usage"`
|
|
Error Error `json:"error"`
|
|
}
|
|
|
|
type Delta struct {
|
|
Type string `json:"type"`
|
|
Text string `json:"text"`
|
|
PartialJson string `json:"partial_json,omitempty"`
|
|
StopReason *string `json:"stop_reason"`
|
|
StopSequence *string `json:"stop_sequence"`
|
|
}
|
|
|
|
type StreamResponse struct {
|
|
Type string `json:"type"`
|
|
Message *Response `json:"message"`
|
|
Index int `json:"index"`
|
|
ContentBlock *Content `json:"content_block"`
|
|
Delta *Delta `json:"delta"`
|
|
Usage *Usage `json:"usage"`
|
|
}
|