256 lines
7.5 KiB
Go
256 lines
7.5 KiB
Go
// Package aiwire 定义 AI 网关的线格式类型:OpenAI Responses / Chat Completions /
|
|
// Anthropic Messages / Embeddings 与通用记账、错误、模型列表结构。上游统一为
|
|
// OCI OpenAI 兼容面。
|
|
package aiwire
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
// StringList 兼容 OpenAI stop 的 string 与 []string 两种线格式。
|
|
type StringList []string
|
|
|
|
func (s *StringList) UnmarshalJSON(b []byte) error {
|
|
if len(b) > 0 && b[0] == '"' {
|
|
var one string
|
|
if err := json.Unmarshal(b, &one); err != nil {
|
|
return err
|
|
}
|
|
*s = StringList{one}
|
|
return nil
|
|
}
|
|
var many []string
|
|
if err := json.Unmarshal(b, &many); err != nil {
|
|
return err
|
|
}
|
|
*s = many
|
|
return nil
|
|
}
|
|
|
|
// Usage 是 token 用量。
|
|
type Usage struct {
|
|
PromptTokens int `json:"prompt_tokens"`
|
|
CompletionTokens int `json:"completion_tokens"`
|
|
TotalTokens int `json:"total_tokens"`
|
|
// PromptTokensDetails 携带缓存命中细分;OCI 为隐式 prompt 缓存,只有读取计数
|
|
PromptTokensDetails *PromptTokensDetails `json:"prompt_tokens_details,omitempty"`
|
|
}
|
|
|
|
// PromptTokensDetails 是输入 token 细分(OpenAI prompt_tokens_details 同构)。
|
|
type PromptTokensDetails struct {
|
|
CachedTokens int `json:"cached_tokens"`
|
|
}
|
|
|
|
// CachedTokens 返回缓存命中读取的 token 数;无细分时为 0。
|
|
func (u *Usage) CachedTokens() int {
|
|
if u == nil || u.PromptTokensDetails == nil {
|
|
return 0
|
|
}
|
|
return u.PromptTokensDetails.CachedTokens
|
|
}
|
|
|
|
// Model 是 /v1/models 列表项。
|
|
type Model struct {
|
|
ID string `json:"id"`
|
|
Object string `json:"object"`
|
|
Created int64 `json:"created"`
|
|
OwnedBy string `json:"owned_by"`
|
|
}
|
|
|
|
// ModelList 是 /v1/models 响应体。
|
|
type ModelList struct {
|
|
Object string `json:"object"`
|
|
Data []Model `json:"data"`
|
|
}
|
|
|
|
// ErrorBody 是 OpenAI 格式错误响应。
|
|
type ErrorBody struct {
|
|
Error ErrorDetail `json:"error"`
|
|
}
|
|
|
|
// ErrorDetail 是错误明细。
|
|
type ErrorDetail struct {
|
|
Message string `json:"message"`
|
|
Type string `json:"type"`
|
|
Code string `json:"code,omitempty"`
|
|
}
|
|
|
|
// ---- Chat Completions 线格式(/ai/v1/chat/completions,Tier 2 兼容层)----
|
|
|
|
// ChatRequest 是 OpenAI /v1/chat/completions 请求体;只声明网关读取的字段,
|
|
// 无对应物的字段(stop / seed / n / penalty 等)由 JSON 解码天然忽略。
|
|
type ChatRequest struct {
|
|
Model string `json:"model"`
|
|
Messages []ChatMessage `json:"messages"`
|
|
MaxTokens *int `json:"max_tokens,omitempty"`
|
|
MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"`
|
|
Temperature *float64 `json:"temperature,omitempty"`
|
|
TopP *float64 `json:"top_p,omitempty"`
|
|
ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
|
|
Stream bool `json:"stream,omitempty"`
|
|
StreamOptions *StreamOptions `json:"stream_options,omitempty"`
|
|
Tools []Tool `json:"tools,omitempty"`
|
|
ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
|
|
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
|
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
|
}
|
|
|
|
// StreamOptions 控制流式末尾是否附带 usage 块。
|
|
type StreamOptions struct {
|
|
IncludeUsage bool `json:"include_usage"`
|
|
}
|
|
|
|
// ChatMessage 是请求与非流式响应共用的消息结构。
|
|
type ChatMessage struct {
|
|
Role string `json:"role"`
|
|
Content Content `json:"content"`
|
|
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
|
}
|
|
|
|
// Content 兼容 string 与多模态块数组两种线格式,序列化时保形。
|
|
type Content struct {
|
|
Text string
|
|
Parts []ContentPart
|
|
IsArray bool
|
|
}
|
|
|
|
func (c *Content) UnmarshalJSON(b []byte) error {
|
|
t := strings.TrimSpace(string(b))
|
|
if t == "null" {
|
|
return nil
|
|
}
|
|
if strings.HasPrefix(t, "[") {
|
|
c.IsArray = true
|
|
return json.Unmarshal(b, &c.Parts)
|
|
}
|
|
return json.Unmarshal(b, &c.Text)
|
|
}
|
|
|
|
func (c Content) MarshalJSON() ([]byte, error) {
|
|
if c.IsArray {
|
|
return json.Marshal(c.Parts)
|
|
}
|
|
return json.Marshal(c.Text)
|
|
}
|
|
|
|
// NewTextContent 构造字符串形态的内容。
|
|
func NewTextContent(text string) Content {
|
|
return Content{Text: text}
|
|
}
|
|
|
|
// JoinText 拍平内容为纯文本(数组形态拼接 text 块)。
|
|
func (c Content) JoinText() string {
|
|
if !c.IsArray {
|
|
return c.Text
|
|
}
|
|
var sb strings.Builder
|
|
for _, p := range c.Parts {
|
|
if p.Type == "" || p.Type == "text" {
|
|
sb.WriteString(p.Text)
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
// ContentPart 是块数组中的一段;text 与 image_url 被网关承接,其余类型拒绝。
|
|
type ContentPart struct {
|
|
Type string `json:"type"`
|
|
Text string `json:"text,omitempty"`
|
|
ImageURL *ImageURL `json:"image_url,omitempty"`
|
|
}
|
|
|
|
// ImageURL 是 image_url 块负载;url 为 data URI(base64)或公网地址。
|
|
type ImageURL struct {
|
|
URL string `json:"url"`
|
|
Detail string `json:"detail,omitempty"`
|
|
}
|
|
|
|
// Tool 是嵌套形态的 function 工具定义。
|
|
type Tool struct {
|
|
Type string `json:"type"`
|
|
Function FunctionDef `json:"function"`
|
|
}
|
|
|
|
// FunctionDef 描述工具的名称与 JSON Schema 参数。
|
|
type FunctionDef struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
Parameters json.RawMessage `json:"parameters,omitempty"`
|
|
}
|
|
|
|
// ToolCall 是助手消息中的工具调用。
|
|
type ToolCall struct {
|
|
ID string `json:"id"`
|
|
Type string `json:"type"`
|
|
Function FunctionCall `json:"function"`
|
|
}
|
|
|
|
// FunctionCall 携带调用名与 JSON 编码的实参。
|
|
type FunctionCall struct {
|
|
Name string `json:"name"`
|
|
Arguments string `json:"arguments"`
|
|
}
|
|
|
|
// ResponseFormat 对应 response_format(json_object / json_schema)。
|
|
type ResponseFormat struct {
|
|
Type string `json:"type"`
|
|
JSONSchema json.RawMessage `json:"json_schema,omitempty"`
|
|
}
|
|
|
|
// ChatResponse 是非流式响应体(chat.completion)。
|
|
type ChatResponse struct {
|
|
ID string `json:"id"`
|
|
Object string `json:"object"`
|
|
Created int64 `json:"created"`
|
|
Model string `json:"model"`
|
|
Choices []Choice `json:"choices"`
|
|
Usage *Usage `json:"usage,omitempty"`
|
|
}
|
|
|
|
// Choice 是一条候选回复。
|
|
type Choice struct {
|
|
Index int `json:"index"`
|
|
Message ChatMessage `json:"message"`
|
|
FinishReason string `json:"finish_reason"`
|
|
}
|
|
|
|
// ChatChunk 是流式增量事件体(chat.completion.chunk)。
|
|
type ChatChunk struct {
|
|
ID string `json:"id"`
|
|
Object string `json:"object"`
|
|
Created int64 `json:"created"`
|
|
Model string `json:"model"`
|
|
Choices []ChunkChoice `json:"choices"`
|
|
Usage *Usage `json:"usage,omitempty"`
|
|
}
|
|
|
|
// ChunkChoice 是流式事件中的增量候选。
|
|
type ChunkChoice struct {
|
|
Index int `json:"index"`
|
|
Delta Delta `json:"delta"`
|
|
FinishReason *string `json:"finish_reason"`
|
|
}
|
|
|
|
// Delta 是流式增量内容;Content 为纯文本片段。
|
|
type Delta struct {
|
|
Role string `json:"role,omitempty"`
|
|
Content string `json:"content,omitempty"`
|
|
ToolCalls []ToolCallDelta `json:"tool_calls,omitempty"`
|
|
}
|
|
|
|
// ToolCallDelta 是工具调用的流式片段;Index 标识聚合目标。
|
|
type ToolCallDelta struct {
|
|
Index int `json:"index"`
|
|
ID string `json:"id,omitempty"`
|
|
Type string `json:"type,omitempty"`
|
|
Function FunctionCallDelta `json:"function"`
|
|
}
|
|
|
|
// FunctionCallDelta 是函数名 / 实参的增量片段。
|
|
type FunctionCallDelta struct {
|
|
Name string `json:"name,omitempty"`
|
|
Arguments string `json:"arguments,omitempty"`
|
|
}
|