mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-10 02:23:43 +08:00
feat: support openai websearch models
This commit is contained in:
@@ -25,46 +25,50 @@ type StreamOptions struct {
|
||||
|
||||
type GeneralOpenAIRequest struct {
|
||||
// https://platform.openai.com/docs/api-reference/chat/create
|
||||
Messages []Message `json:"messages,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Store *bool `json:"store,omitempty"`
|
||||
ReasoningEffort *string `json:"reasoning_effort,omitempty"`
|
||||
Metadata any `json:"metadata,omitempty"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
|
||||
LogitBias any `json:"logit_bias,omitempty"`
|
||||
Logprobs *bool `json:"logprobs,omitempty"`
|
||||
TopLogprobs *int `json:"top_logprobs,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
Modalities []string `json:"modalities,omitempty"`
|
||||
Prediction any `json:"prediction,omitempty"`
|
||||
Audio *Audio `json:"audio,omitempty"`
|
||||
PresencePenalty *float64 `json:"presence_penalty,omitempty"`
|
||||
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
||||
Seed float64 `json:"seed,omitempty"`
|
||||
ServiceTier *string `json:"service_tier,omitempty"`
|
||||
Stop any `json:"stop,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *StreamOptions `json:"stream_options,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"`
|
||||
ParallelTooCalls *bool `json:"parallel_tool_calls,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
FunctionCall any `json:"function_call,omitempty"`
|
||||
Functions any `json:"functions,omitempty"`
|
||||
Messages []Message `json:"messages,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Store *bool `json:"store,omitempty"`
|
||||
Metadata any `json:"metadata,omitempty"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`
|
||||
LogitBias any `json:"logit_bias,omitempty"`
|
||||
Logprobs *bool `json:"logprobs,omitempty"`
|
||||
TopLogprobs *int `json:"top_logprobs,omitempty"`
|
||||
MaxTokens int `json:"max_tokens,omitempty"`
|
||||
MaxCompletionTokens *int `json:"max_completion_tokens,omitempty"`
|
||||
N int `json:"n,omitempty"`
|
||||
// ReasoningEffort constrains effort on reasoning for reasoning models, reasoning models only.
|
||||
ReasoningEffort *string `json:"reasoning_effort,omitempty" binding:"omitempty,oneof=low medium high"`
|
||||
// Modalities currently the model only programmatically allows modalities = [“text”, “audio”]
|
||||
Modalities []string `json:"modalities,omitempty"`
|
||||
Prediction any `json:"prediction,omitempty"`
|
||||
Audio *Audio `json:"audio,omitempty"`
|
||||
PresencePenalty *float64 `json:"presence_penalty,omitempty"`
|
||||
ResponseFormat *ResponseFormat `json:"response_format,omitempty"`
|
||||
Seed float64 `json:"seed,omitempty"`
|
||||
ServiceTier *string `json:"service_tier,omitempty" binding:"omitempty,oneof=default auto"`
|
||||
Stop any `json:"stop,omitempty"`
|
||||
Stream bool `json:"stream,omitempty"`
|
||||
StreamOptions *StreamOptions `json:"stream_options,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"`
|
||||
ParallelTooCalls *bool `json:"parallel_tool_calls,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
FunctionCall any `json:"function_call,omitempty"`
|
||||
Functions any `json:"functions,omitempty"`
|
||||
// https://platform.openai.com/docs/api-reference/embeddings/create
|
||||
Input any `json:"input,omitempty"`
|
||||
EncodingFormat string `json:"encoding_format,omitempty"`
|
||||
Dimensions int `json:"dimensions,omitempty"`
|
||||
// https://platform.openai.com/docs/api-reference/images/create
|
||||
Prompt any `json:"prompt,omitempty"`
|
||||
Quality *string `json:"quality,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
Style *string `json:"style,omitempty"`
|
||||
Prompt string `json:"prompt,omitempty"`
|
||||
Quality *string `json:"quality,omitempty"`
|
||||
Size string `json:"size,omitempty"`
|
||||
Style *string `json:"style,omitempty"`
|
||||
WebSearchOptions *WebSearchOptions `json:"web_search_options,omitempty"`
|
||||
|
||||
// Others
|
||||
Instruction string `json:"instruction,omitempty"`
|
||||
NumCtx int `json:"num_ctx,omitempty"`
|
||||
@@ -79,6 +83,34 @@ type GeneralOpenAIRequest struct {
|
||||
Thinking *Thinking `json:"thinking,omitempty"`
|
||||
}
|
||||
|
||||
// WebSearchOptions is the tool searches the web for relevant results to use in a response.
|
||||
type WebSearchOptions struct {
|
||||
// SearchContextSize is the high level guidance for the amount of context window space to use for the search,
|
||||
// default is "medium".
|
||||
SearchContextSize *string `json:"search_context_size,omitempty" binding:"omitempty,oneof=low medium high"`
|
||||
UserLocation *UserLocation `json:"user_location,omitempty"`
|
||||
}
|
||||
|
||||
// UserLocation is a struct that contains the location of the user.
|
||||
type UserLocation struct {
|
||||
// Approximate is the approximate location parameters for the search.
|
||||
Approximate UserLocationApproximate `json:"approximate" binding:"required"`
|
||||
// Type is the type of location approximation.
|
||||
Type string `json:"type" binding:"required,oneof=approximate"`
|
||||
}
|
||||
|
||||
// UserLocationApproximate is a struct that contains the approximate location of the user.
|
||||
type UserLocationApproximate struct {
|
||||
// City is the city of the user, e.g. San Francisco.
|
||||
City *string `json:"city,omitempty"`
|
||||
// Country is the country of the user, e.g. US.
|
||||
Country *string `json:"country,omitempty"`
|
||||
// Region is the region of the user, e.g. California.
|
||||
Region *string `json:"region,omitempty"`
|
||||
// Timezone is the IANA timezone of the user, e.g. America/Los_Angeles.
|
||||
Timezone *string `json:"timezone,omitempty"`
|
||||
}
|
||||
|
||||
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#implementing-extended-thinking
|
||||
type Thinking struct {
|
||||
Type string `json:"type"`
|
||||
|
||||
@@ -1,13 +1,43 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/songquanpeng/one-api/common/logger"
|
||||
)
|
||||
|
||||
// ReasoningFormat is the format of reasoning content,
|
||||
// can be set by the reasoning_format parameter in the request url.
|
||||
type ReasoningFormat string
|
||||
|
||||
const (
|
||||
ReasoningFormatUnspecified ReasoningFormat = ""
|
||||
// ReasoningFormatReasoningContent is the reasoning format used by deepseek official API
|
||||
ReasoningFormatReasoningContent ReasoningFormat = "reasoning_content"
|
||||
// ReasoningFormatReasoning is the reasoning format used by openrouter
|
||||
ReasoningFormatReasoning ReasoningFormat = "reasoning"
|
||||
|
||||
// ReasoningFormatThinkTag is the reasoning format used by 3rd party deepseek-r1 providers.
|
||||
//
|
||||
// Deprecated: I believe <think> is a very poor format, especially in stream mode, it is difficult to extract and convert.
|
||||
// Considering that only a few deepseek-r1 third-party providers use this format, it has been decided to no longer support it.
|
||||
// ReasoningFormatThinkTag ReasoningFormat = "think-tag"
|
||||
|
||||
// ReasoningFormatThinking is the reasoning format used by anthropic
|
||||
ReasoningFormatThinking ReasoningFormat = "thinking"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Role string `json:"role,omitempty"`
|
||||
// Content is a string or a list of objects
|
||||
Content any `json:"content,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ToolCalls []Tool `json:"tool_calls,omitempty"`
|
||||
ToolCallId string `json:"tool_call_id,omitempty"`
|
||||
Audio *messageAudio `json:"audio,omitempty"`
|
||||
Content any `json:"content,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
ToolCalls []Tool `json:"tool_calls,omitempty"`
|
||||
ToolCallId string `json:"tool_call_id,omitempty"`
|
||||
Audio *messageAudio `json:"audio,omitempty"`
|
||||
Annotation []AnnotationItem `json:"annotation,omitempty"`
|
||||
|
||||
// -------------------------------------
|
||||
// Deepseek 专有的一些字段
|
||||
// https://api-docs.deepseek.com/api/create-chat-completion
|
||||
@@ -18,11 +48,52 @@ type Message struct {
|
||||
// Prefix Completion feature as the input for the CoT in the last assistant message.
|
||||
// When using this feature, the prefix parameter must be set to true.
|
||||
ReasoningContent *string `json:"reasoning_content,omitempty"`
|
||||
|
||||
// -------------------------------------
|
||||
// Openrouter
|
||||
// -------------------------------------
|
||||
Reasoning *string `json:"reasoning,omitempty"`
|
||||
Refusal *bool `json:"refusal,omitempty"`
|
||||
|
||||
// -------------------------------------
|
||||
// Anthropic
|
||||
// -------------------------------------
|
||||
Thinking *string `json:"thinking,omitempty"`
|
||||
Signature *string `json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
type AnnotationItem struct {
|
||||
Type string `json:"type" binding:"oneof=url_citation"`
|
||||
UrlCitation UrlCitation `json:"url_citation"`
|
||||
}
|
||||
|
||||
// UrlCitation is a URL citation when using web search.
|
||||
type UrlCitation struct {
|
||||
// Endpoint is the index of the last character of the URL citation in the message.
|
||||
EndIndex int `json:"end_index"`
|
||||
// StartIndex is the index of the first character of the URL citation in the message.
|
||||
StartIndex int `json:"start_index"`
|
||||
// Title is the title of the web resource.
|
||||
Title string `json:"title"`
|
||||
// Url is the URL of the web resource.
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
// SetReasoningContent sets the reasoning content based on the format
|
||||
func (m *Message) SetReasoningContent(format string, reasoningContent string) {
|
||||
switch ReasoningFormat(strings.ToLower(strings.TrimSpace(format))) {
|
||||
case ReasoningFormatReasoningContent:
|
||||
m.ReasoningContent = &reasoningContent
|
||||
// case ReasoningFormatThinkTag:
|
||||
// m.Content = fmt.Sprintf("<think>%s</think>%s", reasoningContent, m.Content)
|
||||
case ReasoningFormatThinking:
|
||||
m.Thinking = &reasoningContent
|
||||
case ReasoningFormatReasoning,
|
||||
ReasoningFormatUnspecified:
|
||||
m.Reasoning = &reasoningContent
|
||||
default:
|
||||
logger.Warnf(context.TODO(), "unknown reasoning format: %q", format)
|
||||
}
|
||||
}
|
||||
|
||||
type messageAudio struct {
|
||||
@@ -50,6 +121,7 @@ func (m Message) StringContent() string {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if contentMap["type"] == ContentTypeText {
|
||||
if subStr, ok := contentMap["text"].(string); ok {
|
||||
contentStr += subStr
|
||||
@@ -58,6 +130,7 @@ func (m Message) StringContent() string {
|
||||
}
|
||||
return contentStr
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -71,6 +144,7 @@ func (m Message) ParseContent() []MessageContent {
|
||||
})
|
||||
return contentList
|
||||
}
|
||||
|
||||
anyList, ok := m.Content.([]any)
|
||||
if ok {
|
||||
for _, contentItem := range anyList {
|
||||
@@ -95,8 +169,21 @@ func (m Message) ParseContent() []MessageContent {
|
||||
},
|
||||
})
|
||||
}
|
||||
case ContentTypeInputAudio:
|
||||
if subObj, ok := contentMap["input_audio"].(map[string]any); ok {
|
||||
contentList = append(contentList, MessageContent{
|
||||
Type: ContentTypeInputAudio,
|
||||
InputAudio: &InputAudio{
|
||||
Data: subObj["data"].(string),
|
||||
Format: subObj["format"].(string),
|
||||
},
|
||||
})
|
||||
}
|
||||
default:
|
||||
logger.Warnf(context.TODO(), "unknown content type: %s", contentMap["type"])
|
||||
}
|
||||
}
|
||||
|
||||
return contentList
|
||||
}
|
||||
return nil
|
||||
@@ -108,7 +195,23 @@ type ImageURL struct {
|
||||
}
|
||||
|
||||
type MessageContent struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Text string `json:"text"`
|
||||
ImageURL *ImageURL `json:"image_url,omitempty"`
|
||||
// Type should be one of the following: text/input_audio
|
||||
Type string `json:"type,omitempty"`
|
||||
Text string `json:"text"`
|
||||
ImageURL *ImageURL `json:"image_url,omitempty"`
|
||||
InputAudio *InputAudio `json:"input_audio,omitempty"`
|
||||
// -------------------------------------
|
||||
// Anthropic
|
||||
// -------------------------------------
|
||||
Thinking *string `json:"thinking,omitempty"`
|
||||
Signature *string `json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
type InputAudio struct {
|
||||
// Data is the base64 encoded audio data
|
||||
Data string `json:"data" binding:"required"`
|
||||
// Format is the audio format, should be one of the
|
||||
// following: mp3/mp4/mpeg/mpga/m4a/wav/webm/pcm16.
|
||||
// When stream=true, format should be pcm16
|
||||
Format string `json:"format"`
|
||||
}
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
package model
|
||||
|
||||
// Usage is the token usage information returned by OpenAI API.
|
||||
type Usage struct {
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
// PromptTokensDetails may be empty for some models
|
||||
PromptTokensDetails *usagePromptTokensDetails `gorm:"-" json:"prompt_tokens_details,omitempty"`
|
||||
PromptTokensDetails *usagePromptTokensDetails `json:"prompt_tokens_details,omitempty"`
|
||||
// CompletionTokensDetails may be empty for some models
|
||||
CompletionTokensDetails *usageCompletionTokensDetails `gorm:"-" json:"completion_tokens_details,omitempty"`
|
||||
ServiceTier string `gorm:"-" json:"service_tier,omitempty"`
|
||||
SystemFingerprint string `gorm:"-" json:"system_fingerprint,omitempty"`
|
||||
CompletionTokensDetails *usageCompletionTokensDetails `json:"completion_tokens_details,omitempty"`
|
||||
ServiceTier string `json:"service_tier,omitempty"`
|
||||
SystemFingerprint string `json:"system_fingerprint,omitempty"`
|
||||
|
||||
// -------------------------------------
|
||||
// Custom fields
|
||||
// -------------------------------------
|
||||
// ToolsCost is the cost of using tools, in quota.
|
||||
ToolsCost int64 `json:"tools_cost,omitempty"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
|
||||
Reference in New Issue
Block a user