mirror of
https://github.com/hanzoai/dashscopego.git
synced 2026-11-02 16:03:23 +00:00
323 lines
8.3 KiB
Go
323 lines
8.3 KiB
Go
package qwen
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"sync"
|
|
)
|
|
|
|
// SearchOptions configures web search options for the model.
|
|
type SearchOptions struct {
|
|
SearchStrategy string `json:"search_strategy,omitempty"` // turbo (default) | max | agent
|
|
ForcedSearch bool `json:"forced_search,omitempty"` // whether to force search
|
|
EnableSource bool `json:"enable_source,omitempty"` // whether to enable source information
|
|
EnableCitation bool `json:"enable_citation,omitempty"` // whether to enable citation marks (requires enable_source=true)
|
|
CitationFormat string `json:"citation_format,omitempty"` // citation format, e.g., "[ref_<number>]"
|
|
PrependSearchResult bool `json:"prepend_search_result,omitempty"` // whether to prepend search results to the response
|
|
}
|
|
|
|
// SearchResult represents a single search result from web search.
|
|
type SearchResult struct {
|
|
Icon string `json:"icon,omitempty"`
|
|
SiteName string `json:"site_name,omitempty"`
|
|
Index int `json:"index"`
|
|
Title string `json:"title"`
|
|
URL string `json:"url"`
|
|
}
|
|
|
|
// SearchInfo contains the search results information.
|
|
type SearchInfo struct {
|
|
SearchResults []SearchResult `json:"search_results,omitempty"`
|
|
}
|
|
|
|
type Parameters struct {
|
|
ResultFormat string `json:"result_format,omitempty"`
|
|
Seed int `json:"seed,omitempty"`
|
|
MaxTokens int `json:"max_tokens,omitempty"`
|
|
TopP float64 `json:"top_p,omitempty"`
|
|
TopK int `json:"top_k,omitempty"`
|
|
Temperature float64 `json:"temperature,omitempty"`
|
|
EnableSearch bool `json:"enable_search,omitempty"`
|
|
SearchOptions *SearchOptions `json:"search_options,omitempty"` // web search options
|
|
IncrementalOutput bool `json:"incremental_output,omitempty"`
|
|
Tools []Tool `json:"tools,omitempty"` // function call tools.
|
|
}
|
|
|
|
func NewParameters() *Parameters {
|
|
return &Parameters{}
|
|
}
|
|
|
|
const DefaultTemperature = 1.0
|
|
|
|
func DefaultParameters() *Parameters {
|
|
q := Parameters{}
|
|
q.
|
|
SetResultFormat("message").
|
|
SetTemperature(DefaultTemperature)
|
|
|
|
return &q
|
|
}
|
|
|
|
func (p *Parameters) SetResultFormat(value string) *Parameters {
|
|
p = p.tryInit()
|
|
p.ResultFormat = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetSeed(value int) *Parameters {
|
|
p = p.tryInit()
|
|
p.Seed = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetMaxTokens(value int) *Parameters {
|
|
p = p.tryInit()
|
|
p.MaxTokens = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetTopP(value float64) *Parameters {
|
|
p = p.tryInit()
|
|
p.TopP = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetTopK(value int) *Parameters {
|
|
p = p.tryInit()
|
|
p.TopK = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetTemperature(value float64) *Parameters {
|
|
p.tryInit()
|
|
p.Temperature = value
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) SetEnableSearch(value bool) *Parameters {
|
|
p = p.tryInit()
|
|
p.EnableSearch = value
|
|
return p
|
|
}
|
|
|
|
// SetSearchOptions sets the search options.
|
|
func (p *Parameters) SetSearchOptions(options *SearchOptions) *Parameters {
|
|
p = p.tryInit()
|
|
p.SearchOptions = options
|
|
return p
|
|
}
|
|
|
|
// SetSearchStrategy sets the search strategy: turbo (default) | max | agent.
|
|
func (p *Parameters) SetSearchStrategy(strategy string) *Parameters {
|
|
p = p.tryInit()
|
|
if p.SearchOptions == nil {
|
|
p.SearchOptions = &SearchOptions{}
|
|
}
|
|
p.SearchOptions.SearchStrategy = strategy
|
|
return p
|
|
}
|
|
|
|
// SetForcedSearch sets whether to force search.
|
|
func (p *Parameters) SetForcedSearch(forced bool) *Parameters {
|
|
p = p.tryInit()
|
|
if p.SearchOptions == nil {
|
|
p.SearchOptions = &SearchOptions{}
|
|
}
|
|
p.SearchOptions.ForcedSearch = forced
|
|
return p
|
|
}
|
|
|
|
// SetEnableSource sets whether to enable source information.
|
|
func (p *Parameters) SetEnableSource(enable bool) *Parameters {
|
|
p = p.tryInit()
|
|
if p.SearchOptions == nil {
|
|
p.SearchOptions = &SearchOptions{}
|
|
}
|
|
p.SearchOptions.EnableSource = enable
|
|
return p
|
|
}
|
|
|
|
// SetEnableCitation sets whether to enable citation marks (requires enable_source=true).
|
|
func (p *Parameters) SetEnableCitation(enable bool) *Parameters {
|
|
p = p.tryInit()
|
|
if p.SearchOptions == nil {
|
|
p.SearchOptions = &SearchOptions{}
|
|
}
|
|
p.SearchOptions.EnableCitation = enable
|
|
return p
|
|
}
|
|
|
|
// SetPrependSearchResult sets whether to prepend search results to the response.
|
|
func (p *Parameters) SetPrependSearchResult(enable bool) *Parameters {
|
|
p = p.tryInit()
|
|
if p.SearchOptions == nil {
|
|
p.SearchOptions = &SearchOptions{}
|
|
}
|
|
p.SearchOptions.PrependSearchResult = enable
|
|
return p
|
|
}
|
|
|
|
var mu sync.Mutex
|
|
|
|
func (p *Parameters) SetIncrementalOutput(value bool) *Parameters {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
p = p.tryInit()
|
|
if p != nil && p.IncrementalOutput != value {
|
|
p.IncrementalOutput = value
|
|
}
|
|
return p
|
|
}
|
|
|
|
func (p *Parameters) tryInit() *Parameters {
|
|
if p == nil {
|
|
p = &Parameters{}
|
|
}
|
|
return p
|
|
}
|
|
|
|
type PluginCall struct {
|
|
Name string `json:"name"`
|
|
Arguments string `json:"arguments"` // TODO: 临时使用string...后续设计通用 interface 方便自定义扩展.
|
|
}
|
|
|
|
func (p *PluginCall) ToString() string {
|
|
b, err := json.Marshal(p)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
type Message[T IQwenContent] struct {
|
|
Role string `json:"role"`
|
|
Content T `json:"content"`
|
|
ReasoningContent T `json:"reasoning_content"`
|
|
|
|
Name *string `json:"name,omitempty"` // plugin 和 function_call 中使用.
|
|
// plugin parameters
|
|
PluginCall *PluginCall `json:"plugin_call,omitempty"`
|
|
// function call input parameters
|
|
ToolCalls *[]ToolCalls `json:"tool_calls,omitempty"`
|
|
}
|
|
|
|
func (m *Message[T]) HasToolCallInput() bool {
|
|
if m.ToolCalls != nil && len(*m.ToolCalls) > 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
type Input[T IQwenContent] struct {
|
|
Messages []Message[T] `json:"messages"`
|
|
}
|
|
|
|
type StreamingFunc func(ctx context.Context, typ string, chunk []byte) error
|
|
|
|
type Plugins map[string]map[string]any
|
|
|
|
func (p Plugins) toString() string {
|
|
b, err := json.Marshal(p)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
const (
|
|
PluginCodeInterpreter = "code_interpreter"
|
|
PluginPDFExtracter = "pdf_extracter"
|
|
)
|
|
|
|
type Request[T IQwenContent] struct {
|
|
Model string `json:"model"`
|
|
Input Input[T] `json:"input"`
|
|
Parameters *Parameters `json:"parameters,omitempty"`
|
|
// streaming callback function.
|
|
StreamingFn StreamingFunc `json:"-"`
|
|
// qwen-vl model need to upload image to oss for recognition.
|
|
HasUploadOss bool `json:"-"`
|
|
// plugin
|
|
Plugins Plugins `json:"-"`
|
|
// function_call
|
|
Tools []Tool `json:"-"`
|
|
}
|
|
|
|
func (q *Request[T]) SetModel(value string) *Request[T] {
|
|
q.Model = value
|
|
return q
|
|
}
|
|
|
|
func (q *Request[T]) SetInput(value Input[T]) *Request[T] {
|
|
q.Input = value
|
|
return q
|
|
}
|
|
|
|
func (q *Request[T]) SetParameters(value *Parameters) *Request[T] {
|
|
q.Parameters = value
|
|
return q
|
|
}
|
|
|
|
func (q *Request[T]) SetStreamingFunc(fn func(ctx context.Context, typ string, chunk []byte) error) *Request[T] {
|
|
q.StreamingFn = fn
|
|
return q
|
|
}
|
|
|
|
type StreamOutput[T IQwenContent] struct {
|
|
ID string `json:"id"`
|
|
Event string `json:"event"`
|
|
HTTPStatus int `json:"http_status"`
|
|
Output OutputResponse[T] `json:"output"`
|
|
Err error `json:"error"`
|
|
}
|
|
|
|
type Choice[T IQwenContent] struct {
|
|
Message Message[T] `json:"message,omitempty"`
|
|
Messages []Message[T] `json:"messages,omitempty"` // TODO: 部分 plugin 会返回message列表.
|
|
FinishReason string `json:"finish_reason"`
|
|
}
|
|
|
|
// new version response format.
|
|
type Output[T IQwenContent] struct {
|
|
Choices []Choice[T] `json:"choices"`
|
|
SearchInfo *SearchInfo `json:"search_info,omitempty"` // search results information
|
|
}
|
|
|
|
type Usage struct {
|
|
TotalTokens int `json:"total_tokens"`
|
|
InputTokens int `json:"input_tokens"`
|
|
OutputTokens int `json:"output_tokens"`
|
|
}
|
|
|
|
type OutputResponse[T IQwenContent] struct {
|
|
Output Output[T] `json:"output"`
|
|
Usage Usage `json:"usage"`
|
|
RequestID string `json:"request_id"`
|
|
// ErrMsg string `json:"error_msg"`
|
|
}
|
|
|
|
func (t *OutputResponse[T]) GetChoices() []Choice[T] {
|
|
return t.Output.Choices
|
|
}
|
|
|
|
func (t *OutputResponse[T]) GetUsage() Usage {
|
|
return t.Usage
|
|
}
|
|
|
|
func (t *OutputResponse[T]) GetRequestID() string {
|
|
return t.RequestID
|
|
}
|
|
|
|
func (t *OutputResponse[T]) ToJSONStr() string {
|
|
b, err := json.Marshal(t)
|
|
if err != nil {
|
|
return err.Error()
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func (t *OutputResponse[T]) HasToolCallInput() bool {
|
|
return t.Output.Choices[0].Message.HasToolCallInput()
|
|
}
|