diff --git a/controller/channel-test.go b/controller/channel-test.go index f8327284c0..971f53826e 100644 --- a/controller/channel-test.go +++ b/controller/channel-test.go @@ -76,9 +76,9 @@ func testChannel(channel *model.Channel, request *relaymodel.GeneralOpenAIReques if len(modelNames) > 0 { modelName = modelNames[0] } - if modelMap != nil && modelMap[modelName] != "" { - modelName = modelMap[modelName] - } + } + if modelMap != nil && modelMap[modelName] != "" { + modelName = modelMap[modelName] } meta.OriginModelName, meta.ActualModelName = request.Model, modelName request.Model = modelName diff --git a/one-api b/one-api new file mode 100755 index 0000000000..4c9190bb93 Binary files /dev/null and b/one-api differ diff --git a/relay/adaptor/anthropic/constants.go b/relay/adaptor/anthropic/constants.go index 143d1efc25..9b4469b29b 100644 --- a/relay/adaptor/anthropic/constants.go +++ b/relay/adaptor/anthropic/constants.go @@ -6,4 +6,5 @@ var ModelList = []string{ "claude-3-sonnet-20240229", "claude-3-opus-20240229", "claude-3-5-sonnet-20240620", + "claude-3-5-sonnet-20241022", } diff --git a/relay/adaptor/aws/claude/main.go b/relay/adaptor/aws/claude/main.go index 7142e46f72..f1a49ec3ad 100644 --- a/relay/adaptor/aws/claude/main.go +++ b/relay/adaptor/aws/claude/main.go @@ -31,6 +31,7 @@ var AwsModelIDMap = map[string]string{ "claude-2.1": "anthropic.claude-v2:1", "claude-3-sonnet-20240229": "anthropic.claude-3-sonnet-20240229-v1:0", "claude-3-5-sonnet-20240620": "anthropic.claude-3-5-sonnet-20240620-v1:0", + "claude-3-5-sonnet-20241022": "anthropic.claude-3-5-sonnet-20241022-v2:0", "claude-3-opus-20240229": "anthropic.claude-3-opus-20240229-v1:0", "claude-3-haiku-20240307": "anthropic.claude-3-haiku-20240307-v1:0", } diff --git a/relay/adaptor/gemini/main.go b/relay/adaptor/gemini/main.go index 51fd6aa801..d6ab45d489 100644 --- a/relay/adaptor/gemini/main.go +++ b/relay/adaptor/gemini/main.go @@ -4,11 +4,12 @@ import ( "bufio" "encoding/json" "fmt" - "github.com/songquanpeng/one-api/common/render" "io" "net/http" "strings" + "github.com/songquanpeng/one-api/common/render" + "github.com/songquanpeng/one-api/common" "github.com/songquanpeng/one-api/common/config" "github.com/songquanpeng/one-api/common/helper" @@ -28,6 +29,11 @@ const ( VisionMaxImageNum = 16 ) +var mimeTypeMap = map[string]string{ + "json_object": "application/json", + "text": "text/plain", +} + // Setting safety to the lowest possible values since Gemini is already powerless enough func ConvertRequest(textRequest model.GeneralOpenAIRequest) *ChatRequest { geminiRequest := ChatRequest{ @@ -56,6 +62,15 @@ func ConvertRequest(textRequest model.GeneralOpenAIRequest) *ChatRequest { MaxOutputTokens: textRequest.MaxTokens, }, } + if textRequest.ResponseFormat != nil { + if mimeType, ok := mimeTypeMap[textRequest.ResponseFormat.Type]; ok { + geminiRequest.GenerationConfig.ResponseMimeType = mimeType + } + if textRequest.ResponseFormat.JsonSchema != nil { + geminiRequest.GenerationConfig.ResponseSchema = textRequest.ResponseFormat.JsonSchema.Schema + geminiRequest.GenerationConfig.ResponseMimeType = mimeTypeMap["json_object"] + } + } if textRequest.Tools != nil { functions := make([]model.Function, 0, len(textRequest.Tools)) for _, tool := range textRequest.Tools { diff --git a/relay/adaptor/gemini/model.go b/relay/adaptor/gemini/model.go index f7179ea48e..f6a3b25042 100644 --- a/relay/adaptor/gemini/model.go +++ b/relay/adaptor/gemini/model.go @@ -65,10 +65,12 @@ type ChatTools struct { } type ChatGenerationConfig struct { - Temperature float64 `json:"temperature,omitempty"` - TopP float64 `json:"topP,omitempty"` - TopK float64 `json:"topK,omitempty"` - MaxOutputTokens int `json:"maxOutputTokens,omitempty"` - CandidateCount int `json:"candidateCount,omitempty"` - StopSequences []string `json:"stopSequences,omitempty"` + ResponseMimeType string `json:"responseMimeType,omitempty"` + ResponseSchema any `json:"responseSchema,omitempty"` + Temperature float64 `json:"temperature,omitempty"` + TopP float64 `json:"topP,omitempty"` + TopK float64 `json:"topK,omitempty"` + MaxOutputTokens int `json:"maxOutputTokens,omitempty"` + CandidateCount int `json:"candidateCount,omitempty"` + StopSequences []string `json:"stopSequences,omitempty"` } diff --git a/relay/adaptor/groq/constants.go b/relay/adaptor/groq/constants.go index 559851eea0..9c19df393d 100644 --- a/relay/adaptor/groq/constants.go +++ b/relay/adaptor/groq/constants.go @@ -4,14 +4,21 @@ package groq var ModelList = []string{ "gemma-7b-it", - "mixtral-8x7b-32768", - "llama3-8b-8192", - "llama3-70b-8192", "gemma2-9b-it", - "llama-3.1-405b-reasoning", "llama-3.1-70b-versatile", "llama-3.1-8b-instant", + "llama-3.2-11b-text-preview", + "llama-3.2-11b-vision-preview", + "llama-3.2-1b-preview", + "llama-3.2-3b-preview", + "llama-3.2-90b-text-preview", + "llama-guard-3-8b", + "llama3-70b-8192", + "llama3-8b-8192", "llama3-groq-70b-8192-tool-use-preview", "llama3-groq-8b-8192-tool-use-preview", + "llava-v1.5-7b-4096-preview", + "mixtral-8x7b-32768", + "distil-whisper-large-v3-en", "whisper-large-v3", } diff --git a/relay/adaptor/openai/adaptor.go b/relay/adaptor/openai/adaptor.go index 5dc395adfa..6946e402a8 100644 --- a/relay/adaptor/openai/adaptor.go +++ b/relay/adaptor/openai/adaptor.go @@ -75,6 +75,13 @@ func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.G if request == nil { return nil, errors.New("request is nil") } + if request.Stream { + // always return usage in stream mode + if request.StreamOptions == nil { + request.StreamOptions = &model.StreamOptions{} + } + request.StreamOptions.IncludeUsage = true + } return request, nil } diff --git a/relay/adaptor/vertexai/gemini/adapter.go b/relay/adaptor/vertexai/gemini/adapter.go index 43e6cbcde3..ceff1ed2a0 100644 --- a/relay/adaptor/vertexai/gemini/adapter.go +++ b/relay/adaptor/vertexai/gemini/adapter.go @@ -15,7 +15,7 @@ import ( ) var ModelList = []string{ - "gemini-1.5-pro-001", "gemini-1.5-flash-001", "gemini-pro", "gemini-pro-vision", + "gemini-1.5-pro-001", "gemini-1.5-flash-001", "gemini-pro", "gemini-pro-vision", "gemini-1.5-pro-002", "gemini-1.5-flash-002", } type Adaptor struct { diff --git a/relay/adaptor/xunfei/constants.go b/relay/adaptor/xunfei/constants.go index c2992c98e4..5b82ac292f 100644 --- a/relay/adaptor/xunfei/constants.go +++ b/relay/adaptor/xunfei/constants.go @@ -7,5 +7,6 @@ var ModelList = []string{ "SparkDesk-v3.1", "SparkDesk-v3.1-128K", "SparkDesk-v3.5", + "SparkDesk-v3.5-32K", "SparkDesk-v4.0", } diff --git a/relay/adaptor/xunfei/main.go b/relay/adaptor/xunfei/main.go index 99c4d1f4a8..16b89bca2b 100644 --- a/relay/adaptor/xunfei/main.go +++ b/relay/adaptor/xunfei/main.go @@ -292,6 +292,8 @@ func apiVersion2domain(apiVersion string) string { return "pro-128k" case "v3.5": return "generalv3.5" + case "v3.5-32K": + return "max-32k" case "v4.0": return "4.0Ultra" } @@ -303,7 +305,10 @@ func getXunfeiAuthUrl(apiVersion string, apiKey string, apiSecret string) (strin domain := apiVersion2domain(apiVersion) switch apiVersion { case "v3.1-128K": - authUrl = buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/%s/pro-128k", apiVersion), apiKey, apiSecret) + authUrl = buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/chat/pro-128k"), apiKey, apiSecret) + break + case "v3.5-32K": + authUrl = buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/chat/max-32k"), apiKey, apiSecret) break default: authUrl = buildXunfeiAuthUrl(fmt.Sprintf("wss://spark-api.xf-yun.com/%s/chat", apiVersion), apiKey, apiSecret) diff --git a/relay/billing/ratio/model.go b/relay/billing/ratio/model.go index cf5268756d..00f5bd0a0c 100644 --- a/relay/billing/ratio/model.go +++ b/relay/billing/ratio/model.go @@ -81,6 +81,7 @@ var ModelRatio = map[string]float64{ "claude-3-haiku-20240307": 0.25 / 1000 * USD, "claude-3-sonnet-20240229": 3.0 / 1000 * USD, "claude-3-5-sonnet-20240620": 3.0 / 1000 * USD, + "claude-3-5-sonnet-20241022": 3.0 / 1000 * USD, "claude-3-opus-20240229": 15.0 / 1000 * USD, // https://cloud.baidu.com/doc/WENXINWORKSHOP/s/hlrk4akp7 "ERNIE-4.0-8K": 0.120 * RMB, @@ -130,6 +131,7 @@ var ModelRatio = map[string]float64{ "SparkDesk-v3.1": 1.2858, // ¥0.018 / 1k tokens "SparkDesk-v3.1-128K": 1.2858, // ¥0.018 / 1k tokens "SparkDesk-v3.5": 1.2858, // ¥0.018 / 1k tokens + "SparkDesk-v3.5-32K": 1.2858, // ¥0.018 / 1k tokens "SparkDesk-v4.0": 1.2858, // ¥0.018 / 1k tokens "360GPT_S2_V9": 0.8572, // ¥0.012 / 1k tokens "embedding-bert-512-v1": 0.0715, // ¥0.001 / 1k tokens @@ -161,15 +163,21 @@ var ModelRatio = map[string]float64{ "mistral-embed": 0.1 / 1000 * USD, // https://wow.groq.com/#:~:text=inquiries%C2%A0here.-,Model,-Current%20Speed "gemma-7b-it": 0.07 / 1000000 * USD, - "mixtral-8x7b-32768": 0.24 / 1000000 * USD, - "llama3-8b-8192": 0.05 / 1000000 * USD, - "llama3-70b-8192": 0.59 / 1000000 * USD, "gemma2-9b-it": 0.20 / 1000000 * USD, - "llama-3.1-405b-reasoning": 0.89 / 1000000 * USD, "llama-3.1-70b-versatile": 0.59 / 1000000 * USD, "llama-3.1-8b-instant": 0.05 / 1000000 * USD, + "llama-3.2-11b-text-preview": 0.05 / 1000000 * USD, + "llama-3.2-11b-vision-preview": 0.05 / 1000000 * USD, + "llama-3.2-1b-preview": 0.05 / 1000000 * USD, + "llama-3.2-3b-preview": 0.05 / 1000000 * USD, + "llama-3.2-90b-text-preview": 0.59 / 1000000 * USD, + "llama-guard-3-8b": 0.05 / 1000000 * USD, + "llama3-70b-8192": 0.59 / 1000000 * USD, + "llama3-8b-8192": 0.05 / 1000000 * USD, "llama3-groq-70b-8192-tool-use-preview": 0.89 / 1000000 * USD, "llama3-groq-8b-8192-tool-use-preview": 0.19 / 1000000 * USD, + "mixtral-8x7b-32768": 0.24 / 1000000 * USD, + // https://platform.lingyiwanwu.com/docs#-计费单元 "yi-34b-chat-0205": 2.5 / 1000 * RMB, "yi-34b-chat-200k": 12.0 / 1000 * RMB, diff --git a/relay/model/constant.go b/relay/model/constant.go index f6cf1924d1..c9d6d645c6 100644 --- a/relay/model/constant.go +++ b/relay/model/constant.go @@ -1,6 +1,7 @@ package model const ( - ContentTypeText = "text" - ContentTypeImageURL = "image_url" + ContentTypeText = "text" + ContentTypeImageURL = "image_url" + ContentTypeInputAudio = "input_audio" ) diff --git a/relay/model/general.go b/relay/model/general.go index aacc8467d1..fe73779ed7 100644 --- a/relay/model/general.go +++ b/relay/model/general.go @@ -12,9 +12,20 @@ type JSONSchema struct { Strict *bool `json:"strict,omitempty"` } +type Audio struct { + Voice string `json:"voice,omitempty"` + Format string `json:"format,omitempty"` +} + +type StreamOptions struct { + IncludeUsage bool `json:"include_usage,omitempty"` +} + type GeneralOpenAIRequest struct { Messages []Message `json:"messages,omitempty"` Model string `json:"model,omitempty"` + Modalities []string `json:"modalities,omitempty"` + Audio *Audio `json:"audio,omitempty"` FrequencyPenalty float64 `json:"frequency_penalty,omitempty"` MaxTokens int `json:"max_tokens,omitempty"` N int `json:"n,omitempty"` @@ -23,6 +34,7 @@ type GeneralOpenAIRequest struct { Seed float64 `json:"seed,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"` @@ -37,7 +49,7 @@ type GeneralOpenAIRequest struct { Dimensions int `json:"dimensions,omitempty"` Instruction string `json:"instruction,omitempty"` Size string `json:"size,omitempty"` - NumCtx int `json:"num_ctx,omitempty"` + NumCtx int `json:"num_ctx,omitempty"` } func (r GeneralOpenAIRequest) ParseInput() []string { diff --git a/web/air/src/components/TokensTable.js b/web/air/src/components/TokensTable.js index c87657dc13..48836c859a 100644 --- a/web/air/src/components/TokensTable.js +++ b/web/air/src/components/TokensTable.js @@ -395,7 +395,7 @@ const TokensTable = () => { url = mjLink + `/#/?settings={"key":"sk-${key}","url":"${serverAddress}"}`; break; case 'lobechat': - url = chatLink + `/?settings={"keyVaults":{"openai":{"apiKey":"sk-${key}","baseURL":"${serverAddress}"/v1"}}}`; + url = chatLink + `/?settings={"keyVaults":{"openai":{"apiKey":"sk-${key}","baseURL":"${serverAddress}/v1"}}}`; break; default: if (!chatLink) { diff --git a/web/air/src/pages/Channel/EditChannel.js b/web/air/src/pages/Channel/EditChannel.js index b50a6e77de..fa1ab2768b 100644 --- a/web/air/src/pages/Channel/EditChannel.js +++ b/web/air/src/pages/Channel/EditChannel.js @@ -63,7 +63,7 @@ const EditChannel = (props) => { let localModels = []; switch (value) { case 14: - localModels = ["claude-instant-1.2", "claude-2", "claude-2.0", "claude-2.1", "claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307", "claude-3-5-sonnet-20240620"]; + localModels = ["claude-instant-1.2", "claude-2", "claude-2.0", "claude-2.1", "claude-3-opus-20240229", "claude-3-sonnet-20240229", "claude-3-haiku-20240307", "claude-3-5-sonnet-20240620", "claude-3-5-sonnet-20241022"]; break; case 11: localModels = ['PaLM-2']; @@ -78,7 +78,7 @@ const EditChannel = (props) => { localModels = ['chatglm_pro', 'chatglm_std', 'chatglm_lite']; break; case 18: - localModels = ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.1-128K', 'SparkDesk-v3.5', 'SparkDesk-v4.0']; + localModels = ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.1-128K', 'SparkDesk-v3.5', 'SparkDesk-v3.5-32K', 'SparkDesk-v4.0']; break; case 19: localModels = ['360GPT_S2_V9', 'embedding-bert-512-v1', 'embedding_s1_v1', 'semantic_similarity_s1_v1']; diff --git a/web/berry/src/views/Channel/type/Config.js b/web/berry/src/views/Channel/type/Config.js index 4a8fc27a0e..1fa67364b1 100644 --- a/web/berry/src/views/Channel/type/Config.js +++ b/web/berry/src/views/Channel/type/Config.js @@ -91,7 +91,7 @@ const typeConfig = { other: '版本号' }, input: { - models: ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.1-128K', 'SparkDesk-v3.5', 'SparkDesk-v4.0'] + models: ['SparkDesk', 'SparkDesk-v1.1', 'SparkDesk-v2.1', 'SparkDesk-v3.1', 'SparkDesk-v3.1-128K', 'SparkDesk-v3.5', 'SparkDesk-v3.5-32K', 'SparkDesk-v4.0'] }, prompt: { key: '按照如下格式输入:APPID|APISecret|APIKey', diff --git a/web/berry/src/views/Token/component/TableRow.js b/web/berry/src/views/Token/component/TableRow.js index 0a7efd9837..4306be5edf 100644 --- a/web/berry/src/views/Token/component/TableRow.js +++ b/web/berry/src/views/Token/component/TableRow.js @@ -33,7 +33,7 @@ const COPY_OPTIONS = [ }, { key: 'ama', text: 'BotGem', url: 'ama://set-api-key?server={serverAddress}&key=sk-{key}', encode: true }, { key: 'opencat', text: 'OpenCat', url: 'opencat://team/join?domain={serverAddress}&token=sk-{key}', encode: true }, - { key: 'lobechat', text: 'LobeChat', url: 'https://lobehub.com/?settings={"keyVaults":{"openai":{"apiKey":"user-key","baseURL":"https://your-proxy.com/v1"}}}', encode: true } + { key: 'lobechat', text: 'LobeChat', url: 'https://lobehub.com/?settings={"keyVaults":{"openai":{"apiKey":"sk-{key}","baseURL":"{serverAddress}"}}}', encode: true } ]; function replacePlaceholders(text, key, serverAddress) { diff --git a/web/default/src/components/ChannelsTable.js b/web/default/src/components/ChannelsTable.js index 48f476a7b8..6e0ec05d2f 100644 --- a/web/default/src/components/ChannelsTable.js +++ b/web/default/src/components/ChannelsTable.js @@ -59,6 +59,12 @@ function renderBalance(type, balance) { } } +function isShowDetail() { + return localStorage.getItem("show_detail") === "true"; +} + +const promptID = "detail" + const ChannelsTable = () => { const [channels, setChannels] = useState([]); const [loading, setLoading] = useState(true); @@ -66,7 +72,8 @@ const ChannelsTable = () => { const [searchKeyword, setSearchKeyword] = useState(''); const [searching, setSearching] = useState(false); const [updatingBalance, setUpdatingBalance] = useState(false); - const [showPrompt, setShowPrompt] = useState(shouldShowPrompt("channel-test")); + const [showPrompt, setShowPrompt] = useState(shouldShowPrompt(promptID)); + const [showDetail, setShowDetail] = useState(isShowDetail()); const loadChannels = async (startIdx) => { const res = await API.get(`/api/channel/?p=${startIdx}`); @@ -120,6 +127,11 @@ const ChannelsTable = () => { await loadChannels(activePage - 1); }; + const toggleShowDetail = () => { + setShowDetail(!showDetail); + localStorage.setItem("show_detail", (!showDetail).toString()); + } + useEffect(() => { loadChannels(0) .then() @@ -364,11 +376,13 @@ const ChannelsTable = () => { showPrompt && ( { setShowPrompt(false); - setPromptShown("channel-test"); + setPromptShown(promptID); }}> OpenAI 渠道已经不再支持通过 key 获取余额,因此余额显示为 0。对于支持的渠道类型,请点击余额进行刷新。
渠道测试仅支持 chat 模型,优先使用 gpt-3.5-turbo,如果该模型不可用则使用你所配置的模型列表中的第一个模型。 +
+ 点击下方详情按钮可以显示余额以及设置额外的测试模型。
) } @@ -428,6 +442,7 @@ const ChannelsTable = () => { onClick={() => { sortChannel('balance'); }} + hidden={!showDetail} > 余额 @@ -439,7 +454,7 @@ const ChannelsTable = () => { > 优先级 - 测试模型 + 操作 @@ -467,7 +482,7 @@ const ChannelsTable = () => { basic /> - + - +