| package dto |
|
|
| import ( |
| "encoding/json" |
| "fmt" |
| "strings" |
|
|
| "github.com/QuantumNous/new-api/common" |
| "github.com/QuantumNous/new-api/types" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| type ResponseFormat struct { |
| Type string `json:"type,omitempty"` |
| JsonSchema json.RawMessage `json:"json_schema,omitempty"` |
| } |
|
|
| type FormatJsonSchema struct { |
| Description string `json:"description,omitempty"` |
| Name string `json:"name"` |
| Schema any `json:"schema,omitempty"` |
| Strict json.RawMessage `json:"strict,omitempty"` |
| } |
|
|
| |
| |
| type GeneralOpenAIRequest struct { |
| Model string `json:"model,omitempty"` |
| Messages []Message `json:"messages,omitempty"` |
| Prompt any `json:"prompt,omitempty"` |
| Prefix any `json:"prefix,omitempty"` |
| Suffix any `json:"suffix,omitempty"` |
| Stream bool `json:"stream,omitempty"` |
| StreamOptions *StreamOptions `json:"stream_options,omitempty"` |
| MaxTokens uint `json:"max_tokens,omitempty"` |
| MaxCompletionTokens uint `json:"max_completion_tokens,omitempty"` |
| ReasoningEffort string `json:"reasoning_effort,omitempty"` |
| Verbosity json.RawMessage `json:"verbosity,omitempty"` |
| Temperature *float64 `json:"temperature,omitempty"` |
| TopP float64 `json:"top_p,omitempty"` |
| TopK int `json:"top_k,omitempty"` |
| Stop any `json:"stop,omitempty"` |
| N int `json:"n,omitempty"` |
| Input any `json:"input,omitempty"` |
| Instruction string `json:"instruction,omitempty"` |
| Size string `json:"size,omitempty"` |
| Functions json.RawMessage `json:"functions,omitempty"` |
| FrequencyPenalty float64 `json:"frequency_penalty,omitempty"` |
| PresencePenalty float64 `json:"presence_penalty,omitempty"` |
| ResponseFormat *ResponseFormat `json:"response_format,omitempty"` |
| EncodingFormat json.RawMessage `json:"encoding_format,omitempty"` |
| Seed float64 `json:"seed,omitempty"` |
| ParallelTooCalls *bool `json:"parallel_tool_calls,omitempty"` |
| Tools []ToolCallRequest `json:"tools,omitempty"` |
| ToolChoice any `json:"tool_choice,omitempty"` |
| User string `json:"user,omitempty"` |
| LogProbs bool `json:"logprobs,omitempty"` |
| TopLogProbs int `json:"top_logprobs,omitempty"` |
| Dimensions int `json:"dimensions,omitempty"` |
| Modalities json.RawMessage `json:"modalities,omitempty"` |
| Audio json.RawMessage `json:"audio,omitempty"` |
| |
| |
| SafetyIdentifier string `json:"safety_identifier,omitempty"` |
| |
| |
| |
| Store json.RawMessage `json:"store,omitempty"` |
| |
| PromptCacheKey string `json:"prompt_cache_key,omitempty"` |
| PromptCacheRetention json.RawMessage `json:"prompt_cache_retention,omitempty"` |
| LogitBias json.RawMessage `json:"logit_bias,omitempty"` |
| Metadata json.RawMessage `json:"metadata,omitempty"` |
| Prediction json.RawMessage `json:"prediction,omitempty"` |
| |
| ExtraBody json.RawMessage `json:"extra_body,omitempty"` |
| |
| SearchParameters json.RawMessage `json:"search_parameters,omitempty"` |
| |
| WebSearchOptions *WebSearchOptions `json:"web_search_options,omitempty"` |
| |
| Usage json.RawMessage `json:"usage,omitempty"` |
| Reasoning json.RawMessage `json:"reasoning,omitempty"` |
| |
| VlHighResolutionImages json.RawMessage `json:"vl_high_resolution_images,omitempty"` |
| EnableThinking json.RawMessage `json:"enable_thinking,omitempty"` |
| ChatTemplateKwargs json.RawMessage `json:"chat_template_kwargs,omitempty"` |
| EnableSearch json.RawMessage `json:"enable_search,omitempty"` |
| |
| Think json.RawMessage `json:"think,omitempty"` |
| |
| WebSearch json.RawMessage `json:"web_search,omitempty"` |
| |
| THINKING json.RawMessage `json:"thinking,omitempty"` |
| |
| SearchDomainFilter json.RawMessage `json:"search_domain_filter,omitempty"` |
| SearchRecencyFilter string `json:"search_recency_filter,omitempty"` |
| ReturnImages bool `json:"return_images,omitempty"` |
| ReturnRelatedQuestions bool `json:"return_related_questions,omitempty"` |
| SearchMode string `json:"search_mode,omitempty"` |
| } |
|
|
| func (r *GeneralOpenAIRequest) GetTokenCountMeta() *types.TokenCountMeta { |
| var tokenCountMeta types.TokenCountMeta |
| var texts = make([]string, 0) |
| var fileMeta = make([]*types.FileMeta, 0) |
|
|
| if r.Prompt != nil { |
| switch v := r.Prompt.(type) { |
| case string: |
| texts = append(texts, v) |
| case []any: |
| for _, item := range v { |
| if str, ok := item.(string); ok { |
| texts = append(texts, str) |
| } |
| } |
| default: |
| texts = append(texts, fmt.Sprintf("%v", r.Prompt)) |
| } |
| } |
|
|
| if r.Input != nil { |
| inputs := r.ParseInput() |
| texts = append(texts, inputs...) |
| } |
|
|
| if r.MaxCompletionTokens > r.MaxTokens { |
| tokenCountMeta.MaxTokens = int(r.MaxCompletionTokens) |
| } else { |
| tokenCountMeta.MaxTokens = int(r.MaxTokens) |
| } |
|
|
| for _, message := range r.Messages { |
| tokenCountMeta.MessagesCount++ |
| texts = append(texts, message.Role) |
| if message.Content != nil { |
| if message.Name != nil { |
| tokenCountMeta.NameCount++ |
| texts = append(texts, *message.Name) |
| } |
| arrayContent := message.ParseContent() |
| for _, m := range arrayContent { |
| if m.Type == ContentTypeImageURL { |
| imageUrl := m.GetImageMedia() |
| if imageUrl != nil { |
| if imageUrl.Url != "" { |
| meta := &types.FileMeta{ |
| FileType: types.FileTypeImage, |
| } |
| meta.OriginData = imageUrl.Url |
| meta.Detail = imageUrl.Detail |
| fileMeta = append(fileMeta, meta) |
| } |
| } |
| } else if m.Type == ContentTypeInputAudio { |
| inputAudio := m.GetInputAudio() |
| if inputAudio != nil { |
| meta := &types.FileMeta{ |
| FileType: types.FileTypeAudio, |
| } |
| meta.OriginData = inputAudio.Data |
| fileMeta = append(fileMeta, meta) |
| } |
| } else if m.Type == ContentTypeFile { |
| file := m.GetFile() |
| if file != nil { |
| meta := &types.FileMeta{ |
| FileType: types.FileTypeFile, |
| } |
| meta.OriginData = file.FileData |
| fileMeta = append(fileMeta, meta) |
| } |
| } else if m.Type == ContentTypeVideoUrl { |
| videoUrl := m.GetVideoUrl() |
| if videoUrl != nil && videoUrl.Url != "" { |
| meta := &types.FileMeta{ |
| FileType: types.FileTypeVideo, |
| } |
| meta.OriginData = videoUrl.Url |
| fileMeta = append(fileMeta, meta) |
| } |
| } else { |
| texts = append(texts, m.Text) |
| } |
| } |
| } |
| } |
|
|
| if r.Tools != nil { |
| openaiTools := r.Tools |
| for _, tool := range openaiTools { |
| tokenCountMeta.ToolsCount++ |
| texts = append(texts, tool.Function.Name) |
| if tool.Function.Description != "" { |
| texts = append(texts, tool.Function.Description) |
| } |
| if tool.Function.Parameters != nil { |
| texts = append(texts, fmt.Sprintf("%v", tool.Function.Parameters)) |
| } |
| } |
| |
| |
| |
| } |
| tokenCountMeta.CombineText = strings.Join(texts, "\n") |
| tokenCountMeta.Files = fileMeta |
| return &tokenCountMeta |
| } |
|
|
| func (r *GeneralOpenAIRequest) IsStream(c *gin.Context) bool { |
| return r.Stream |
| } |
|
|
| func (r *GeneralOpenAIRequest) SetModelName(modelName string) { |
| if modelName != "" { |
| r.Model = modelName |
| } |
| } |
|
|
| func (r *GeneralOpenAIRequest) ToMap() map[string]any { |
| result := make(map[string]any) |
| data, _ := common.Marshal(r) |
| _ = common.Unmarshal(data, &result) |
| return result |
| } |
|
|
| func (r *GeneralOpenAIRequest) GetSystemRoleName() string { |
| if strings.HasPrefix(r.Model, "o") { |
| if !strings.HasPrefix(r.Model, "o1-mini") && !strings.HasPrefix(r.Model, "o1-preview") { |
| return "developer" |
| } |
| } else if strings.HasPrefix(r.Model, "gpt-5") { |
| return "developer" |
| } |
| return "system" |
| } |
|
|
| const CustomType = "custom" |
|
|
| type ToolCallRequest struct { |
| ID string `json:"id,omitempty"` |
| Type string `json:"type"` |
| Function FunctionRequest `json:"function,omitempty"` |
| Custom json.RawMessage `json:"custom,omitempty"` |
| } |
|
|
| type FunctionRequest struct { |
| Description string `json:"description,omitempty"` |
| Name string `json:"name"` |
| Parameters any `json:"parameters,omitempty"` |
| Arguments string `json:"arguments,omitempty"` |
| } |
|
|
| type StreamOptions struct { |
| IncludeUsage bool `json:"include_usage,omitempty"` |
| } |
|
|
| func (r *GeneralOpenAIRequest) GetMaxTokens() uint { |
| if r.MaxCompletionTokens != 0 { |
| return r.MaxCompletionTokens |
| } |
| return r.MaxTokens |
| } |
|
|
| func (r *GeneralOpenAIRequest) ParseInput() []string { |
| if r.Input == nil { |
| return nil |
| } |
| var input []string |
| switch r.Input.(type) { |
| case string: |
| input = []string{r.Input.(string)} |
| case []any: |
| input = make([]string, 0, len(r.Input.([]any))) |
| for _, item := range r.Input.([]any) { |
| if str, ok := item.(string); ok { |
| input = append(input, str) |
| } |
| } |
| } |
| return input |
| } |
|
|
| type Message struct { |
| Role string `json:"role"` |
| Content any `json:"content"` |
| Name *string `json:"name,omitempty"` |
| Prefix *bool `json:"prefix,omitempty"` |
| ReasoningContent string `json:"reasoning_content,omitempty"` |
| Reasoning string `json:"reasoning,omitempty"` |
| ToolCalls json.RawMessage `json:"tool_calls,omitempty"` |
| ToolCallId string `json:"tool_call_id,omitempty"` |
| parsedContent []MediaContent |
| |
| } |
|
|
| type MediaContent struct { |
| Type string `json:"type"` |
| Text string `json:"text,omitempty"` |
| ImageUrl any `json:"image_url,omitempty"` |
| InputAudio any `json:"input_audio,omitempty"` |
| File any `json:"file,omitempty"` |
| VideoUrl any `json:"video_url,omitempty"` |
| |
| CacheControl json.RawMessage `json:"cache_control,omitempty"` |
| } |
|
|
| func (m *MediaContent) GetImageMedia() *MessageImageUrl { |
| if m.ImageUrl != nil { |
| if _, ok := m.ImageUrl.(*MessageImageUrl); ok { |
| return m.ImageUrl.(*MessageImageUrl) |
| } |
| if itemMap, ok := m.ImageUrl.(map[string]any); ok { |
| out := &MessageImageUrl{ |
| Url: common.Interface2String(itemMap["url"]), |
| Detail: common.Interface2String(itemMap["detail"]), |
| MimeType: common.Interface2String(itemMap["mime_type"]), |
| } |
| return out |
| } |
| } |
| return nil |
| } |
|
|
| func (m *MediaContent) GetInputAudio() *MessageInputAudio { |
| if m.InputAudio != nil { |
| if _, ok := m.InputAudio.(*MessageInputAudio); ok { |
| return m.InputAudio.(*MessageInputAudio) |
| } |
| if itemMap, ok := m.InputAudio.(map[string]any); ok { |
| out := &MessageInputAudio{ |
| Data: common.Interface2String(itemMap["data"]), |
| Format: common.Interface2String(itemMap["format"]), |
| } |
| return out |
| } |
| } |
| return nil |
| } |
|
|
| func (m *MediaContent) GetFile() *MessageFile { |
| if m.File != nil { |
| if _, ok := m.File.(*MessageFile); ok { |
| return m.File.(*MessageFile) |
| } |
| if itemMap, ok := m.File.(map[string]any); ok { |
| out := &MessageFile{ |
| FileName: common.Interface2String(itemMap["file_name"]), |
| FileData: common.Interface2String(itemMap["file_data"]), |
| FileId: common.Interface2String(itemMap["file_id"]), |
| } |
| return out |
| } |
| } |
| return nil |
| } |
|
|
| func (m *MediaContent) GetVideoUrl() *MessageVideoUrl { |
| if m.VideoUrl != nil { |
| if _, ok := m.VideoUrl.(*MessageVideoUrl); ok { |
| return m.VideoUrl.(*MessageVideoUrl) |
| } |
| if itemMap, ok := m.VideoUrl.(map[string]any); ok { |
| out := &MessageVideoUrl{ |
| Url: common.Interface2String(itemMap["url"]), |
| } |
| return out |
| } |
| } |
| return nil |
| } |
|
|
| type MessageImageUrl struct { |
| Url string `json:"url"` |
| Detail string `json:"detail"` |
| MimeType string |
| } |
|
|
| func (m *MessageImageUrl) IsRemoteImage() bool { |
| return strings.HasPrefix(m.Url, "http") |
| } |
|
|
| type MessageInputAudio struct { |
| Data string `json:"data"` |
| Format string `json:"format"` |
| } |
|
|
| type MessageFile struct { |
| FileName string `json:"filename,omitempty"` |
| FileData string `json:"file_data,omitempty"` |
| FileId string `json:"file_id,omitempty"` |
| } |
|
|
| type MessageVideoUrl struct { |
| Url string `json:"url"` |
| } |
|
|
| const ( |
| ContentTypeText = "text" |
| ContentTypeImageURL = "image_url" |
| ContentTypeInputAudio = "input_audio" |
| ContentTypeFile = "file" |
| ContentTypeVideoUrl = "video_url" |
| |
| ) |
|
|
| func (m *Message) GetPrefix() bool { |
| if m.Prefix == nil { |
| return false |
| } |
| return *m.Prefix |
| } |
|
|
| func (m *Message) SetPrefix(prefix bool) { |
| m.Prefix = &prefix |
| } |
|
|
| func (m *Message) ParseToolCalls() []ToolCallRequest { |
| if m.ToolCalls == nil { |
| return nil |
| } |
| var toolCalls []ToolCallRequest |
| if err := json.Unmarshal(m.ToolCalls, &toolCalls); err == nil { |
| return toolCalls |
| } |
| return toolCalls |
| } |
|
|
| func (m *Message) SetToolCalls(toolCalls any) { |
| toolCallsJson, _ := json.Marshal(toolCalls) |
| m.ToolCalls = toolCallsJson |
| } |
|
|
| func (m *Message) StringContent() string { |
| switch m.Content.(type) { |
| case string: |
| return m.Content.(string) |
| case []any: |
| var contentStr string |
| for _, contentItem := range m.Content.([]any) { |
| contentMap, ok := contentItem.(map[string]any) |
| if !ok { |
| continue |
| } |
| if contentMap["type"] == ContentTypeText { |
| if subStr, ok := contentMap["text"].(string); ok { |
| contentStr += subStr |
| } |
| } |
| } |
| return contentStr |
| } |
|
|
| return "" |
| } |
|
|
| func (m *Message) SetNullContent() { |
| m.Content = nil |
| m.parsedContent = nil |
| } |
|
|
| func (m *Message) SetStringContent(content string) { |
| m.Content = content |
| m.parsedContent = nil |
| } |
|
|
| func (m *Message) SetMediaContent(content []MediaContent) { |
| m.Content = content |
| m.parsedContent = content |
| } |
|
|
| func (m *Message) IsStringContent() bool { |
| _, ok := m.Content.(string) |
| if ok { |
| return true |
| } |
| return false |
| } |
|
|
| func (m *Message) ParseContent() []MediaContent { |
| if m.Content == nil { |
| return nil |
| } |
| if len(m.parsedContent) > 0 { |
| return m.parsedContent |
| } |
|
|
| var contentList []MediaContent |
| |
| content, ok := m.Content.(string) |
| if ok { |
| contentList = []MediaContent{{ |
| Type: ContentTypeText, |
| Text: content, |
| }} |
| m.parsedContent = contentList |
| return contentList |
| } |
|
|
| |
| |
|
|
| arrayContent, ok := m.Content.([]any) |
| if !ok { |
| return contentList |
| } |
|
|
| for _, contentItemAny := range arrayContent { |
| mediaItem, ok := contentItemAny.(MediaContent) |
| if ok { |
| contentList = append(contentList, mediaItem) |
| continue |
| } |
|
|
| contentItem, ok := contentItemAny.(map[string]any) |
| if !ok { |
| continue |
| } |
| contentType, ok := contentItem["type"].(string) |
| if !ok { |
| continue |
| } |
|
|
| switch contentType { |
| case ContentTypeText: |
| if text, ok := contentItem["text"].(string); ok { |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeText, |
| Text: text, |
| }) |
| } |
|
|
| case ContentTypeImageURL: |
| imageUrl := contentItem["image_url"] |
| temp := &MessageImageUrl{ |
| Detail: "high", |
| } |
| switch v := imageUrl.(type) { |
| case string: |
| temp.Url = v |
| case map[string]interface{}: |
| url, ok1 := v["url"].(string) |
| detail, ok2 := v["detail"].(string) |
| if ok2 { |
| temp.Detail = detail |
| } |
| if ok1 { |
| temp.Url = url |
| } |
| } |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeImageURL, |
| ImageUrl: temp, |
| }) |
|
|
| case ContentTypeInputAudio: |
| if audioData, ok := contentItem["input_audio"].(map[string]interface{}); ok { |
| data, ok1 := audioData["data"].(string) |
| format, ok2 := audioData["format"].(string) |
| if ok1 && ok2 { |
| temp := &MessageInputAudio{ |
| Data: data, |
| Format: format, |
| } |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeInputAudio, |
| InputAudio: temp, |
| }) |
| } |
| } |
| case ContentTypeFile: |
| if fileData, ok := contentItem["file"].(map[string]interface{}); ok { |
| fileId, ok3 := fileData["file_id"].(string) |
| if ok3 { |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeFile, |
| File: &MessageFile{ |
| FileId: fileId, |
| }, |
| }) |
| } else { |
| fileName, ok1 := fileData["filename"].(string) |
| fileDataStr, ok2 := fileData["file_data"].(string) |
| if ok1 && ok2 { |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeFile, |
| File: &MessageFile{ |
| FileName: fileName, |
| FileData: fileDataStr, |
| }, |
| }) |
| } |
| } |
| } |
| case ContentTypeVideoUrl: |
| if videoUrl, ok := contentItem["video_url"].(string); ok { |
| contentList = append(contentList, MediaContent{ |
| Type: ContentTypeVideoUrl, |
| VideoUrl: &MessageVideoUrl{ |
| Url: videoUrl, |
| }, |
| }) |
| } |
| } |
| } |
|
|
| if len(contentList) > 0 { |
| m.parsedContent = contentList |
| } |
| return contentList |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| type WebSearchOptions struct { |
| SearchContextSize string `json:"search_context_size,omitempty"` |
| UserLocation json.RawMessage `json:"user_location,omitempty"` |
| } |
|
|
| |
| type OpenAIResponsesRequest struct { |
| Model string `json:"model"` |
| Input json.RawMessage `json:"input,omitempty"` |
| Include json.RawMessage `json:"include,omitempty"` |
| Instructions json.RawMessage `json:"instructions,omitempty"` |
| MaxOutputTokens uint `json:"max_output_tokens,omitempty"` |
| Metadata json.RawMessage `json:"metadata,omitempty"` |
| ParallelToolCalls json.RawMessage `json:"parallel_tool_calls,omitempty"` |
| PreviousResponseID string `json:"previous_response_id,omitempty"` |
| Reasoning *Reasoning `json:"reasoning,omitempty"` |
| |
| ServiceTier string `json:"service_tier,omitempty"` |
| Store json.RawMessage `json:"store,omitempty"` |
| PromptCacheKey json.RawMessage `json:"prompt_cache_key,omitempty"` |
| PromptCacheRetention json.RawMessage `json:"prompt_cache_retention,omitempty"` |
| Stream bool `json:"stream,omitempty"` |
| Temperature float64 `json:"temperature,omitempty"` |
| Text json.RawMessage `json:"text,omitempty"` |
| ToolChoice json.RawMessage `json:"tool_choice,omitempty"` |
| Tools json.RawMessage `json:"tools,omitempty"` |
| TopP float64 `json:"top_p,omitempty"` |
| Truncation string `json:"truncation,omitempty"` |
| User string `json:"user,omitempty"` |
| MaxToolCalls uint `json:"max_tool_calls,omitempty"` |
| Prompt json.RawMessage `json:"prompt,omitempty"` |
| } |
|
|
| func (r *OpenAIResponsesRequest) GetTokenCountMeta() *types.TokenCountMeta { |
| var fileMeta = make([]*types.FileMeta, 0) |
| var texts = make([]string, 0) |
|
|
| if r.Input != nil { |
| inputs := r.ParseInput() |
| for _, input := range inputs { |
| if input.Type == "input_image" { |
| if input.ImageUrl != "" { |
| fileMeta = append(fileMeta, &types.FileMeta{ |
| FileType: types.FileTypeImage, |
| OriginData: input.ImageUrl, |
| Detail: input.Detail, |
| }) |
| } |
| } else if input.Type == "input_file" { |
| if input.FileUrl != "" { |
| fileMeta = append(fileMeta, &types.FileMeta{ |
| FileType: types.FileTypeFile, |
| OriginData: input.FileUrl, |
| }) |
| } |
| } else { |
| texts = append(texts, input.Text) |
| } |
| } |
| } |
|
|
| if len(r.Instructions) > 0 { |
| texts = append(texts, string(r.Instructions)) |
| } |
|
|
| if len(r.Metadata) > 0 { |
| texts = append(texts, string(r.Metadata)) |
| } |
|
|
| if len(r.Text) > 0 { |
| texts = append(texts, string(r.Text)) |
| } |
|
|
| if len(r.ToolChoice) > 0 { |
| texts = append(texts, string(r.ToolChoice)) |
| } |
|
|
| if len(r.Prompt) > 0 { |
| texts = append(texts, string(r.Prompt)) |
| } |
|
|
| if len(r.Tools) > 0 { |
| texts = append(texts, string(r.Tools)) |
| } |
|
|
| return &types.TokenCountMeta{ |
| CombineText: strings.Join(texts, "\n"), |
| Files: fileMeta, |
| MaxTokens: int(r.MaxOutputTokens), |
| } |
| } |
|
|
| func (r *OpenAIResponsesRequest) IsStream(c *gin.Context) bool { |
| return r.Stream |
| } |
|
|
| func (r *OpenAIResponsesRequest) SetModelName(modelName string) { |
| if modelName != "" { |
| r.Model = modelName |
| } |
| } |
|
|
| func (r *OpenAIResponsesRequest) GetToolsMap() []map[string]any { |
| var toolsMap []map[string]any |
| if len(r.Tools) > 0 { |
| _ = common.Unmarshal(r.Tools, &toolsMap) |
| } |
| return toolsMap |
| } |
|
|
| type Reasoning struct { |
| Effort string `json:"effort,omitempty"` |
| Summary string `json:"summary,omitempty"` |
| } |
|
|
| type Input struct { |
| Type string `json:"type,omitempty"` |
| Role string `json:"role,omitempty"` |
| Content json.RawMessage `json:"content,omitempty"` |
| } |
|
|
| type MediaInput struct { |
| Type string `json:"type"` |
| Text string `json:"text,omitempty"` |
| FileUrl string `json:"file_url,omitempty"` |
| ImageUrl string `json:"image_url,omitempty"` |
| Detail string `json:"detail,omitempty"` |
| } |
|
|
| |
| |
| |
| |
| |
| func (r *OpenAIResponsesRequest) ParseInput() []MediaInput { |
| if r.Input == nil { |
| return nil |
| } |
|
|
| var mediaInputs []MediaInput |
|
|
| |
| |
| |
| |
| |
| if common.GetJsonType(r.Input) == "string" { |
| var str string |
| _ = common.Unmarshal(r.Input, &str) |
| mediaInputs = append(mediaInputs, MediaInput{Type: "input_text", Text: str}) |
| return mediaInputs |
| } |
|
|
| |
| if common.GetJsonType(r.Input) == "array" { |
| var inputs []Input |
| _ = common.Unmarshal(r.Input, &inputs) |
| for _, input := range inputs { |
| if common.GetJsonType(input.Content) == "string" { |
| var str string |
| _ = common.Unmarshal(input.Content, &str) |
| mediaInputs = append(mediaInputs, MediaInput{Type: "input_text", Text: str}) |
| } |
|
|
| if common.GetJsonType(input.Content) == "array" { |
| var array []any |
| _ = common.Unmarshal(input.Content, &array) |
| for _, itemAny := range array { |
| |
| if media, ok := itemAny.(MediaInput); ok { |
| mediaInputs = append(mediaInputs, media) |
| continue |
| } |
|
|
| |
| item, ok := itemAny.(map[string]any) |
| if !ok { |
| continue |
| } |
|
|
| typeVal, ok := item["type"].(string) |
| if !ok { |
| continue |
| } |
| switch typeVal { |
| case "input_text": |
| text, _ := item["text"].(string) |
| mediaInputs = append(mediaInputs, MediaInput{Type: "input_text", Text: text}) |
| case "input_image": |
| |
| var imageUrl string |
| switch v := item["image_url"].(type) { |
| case string: |
| imageUrl = v |
| case map[string]any: |
| if url, ok := v["url"].(string); ok { |
| imageUrl = url |
| } |
| } |
| mediaInputs = append(mediaInputs, MediaInput{Type: "input_image", ImageUrl: imageUrl}) |
| case "input_file": |
| |
| var fileUrl string |
| switch v := item["file_url"].(type) { |
| case string: |
| fileUrl = v |
| case map[string]any: |
| if url, ok := v["url"].(string); ok { |
| fileUrl = url |
| } |
| } |
| mediaInputs = append(mediaInputs, MediaInput{Type: "input_file", FileUrl: fileUrl}) |
| } |
| } |
| } |
| } |
| } |
|
|
| return mediaInputs |
| } |
|
|