mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 16:00:52 +00:00
439 lines
13 KiB
Go
439 lines
13 KiB
Go
package provider
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type Model struct {
|
|
ID string
|
|
Name string
|
|
ContextWindow int
|
|
MaxTokens int
|
|
Reasoning bool
|
|
Input []string
|
|
}
|
|
|
|
type RuntimeDefault struct {
|
|
APIType string
|
|
ContextWindow int
|
|
MaxTokens int
|
|
Input []string
|
|
}
|
|
|
|
type Meta struct {
|
|
Key string
|
|
DisplayName string
|
|
Sort uint
|
|
DefaultBaseURL string
|
|
EnvKey string
|
|
Default RuntimeDefault
|
|
Models []Model
|
|
}
|
|
|
|
var catalog = map[string]Meta{
|
|
"custom": {
|
|
Key: "custom",
|
|
DisplayName: "Custom",
|
|
Sort: 10,
|
|
DefaultBaseURL: "",
|
|
EnvKey: "CUSTOM_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 128000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{},
|
|
},
|
|
"ollama": {
|
|
Key: "ollama",
|
|
DisplayName: "Ollama",
|
|
Sort: 15,
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-responses",
|
|
ContextWindow: 160000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
},
|
|
"vllm": {
|
|
Key: "vllm",
|
|
DisplayName: "vLLM",
|
|
Sort: 20,
|
|
DefaultBaseURL: "",
|
|
EnvKey: "VLLM_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 128000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{},
|
|
},
|
|
"deepseek": {
|
|
Key: "deepseek",
|
|
DisplayName: "DeepSeek",
|
|
Sort: 25,
|
|
DefaultBaseURL: "https://api.deepseek.com/v1",
|
|
EnvKey: "DEEPSEEK_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 131072,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "deepseek/deepseek-v4-flash", Name: "deepseek-v4-flash"},
|
|
{ID: "deepseek/deepseek-v4-pro", Name: "deepseek-v4-pro"},
|
|
},
|
|
},
|
|
"bailian-coding-plan": {
|
|
Key: "bailian-coding-plan",
|
|
DisplayName: "阿里云百炼 Coding Plan",
|
|
Sort: 30,
|
|
DefaultBaseURL: "https://coding.dashscope.aliyuncs.com/v1",
|
|
EnvKey: "QWEN_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "bailian-coding-plan/qwen3.5-plus", Name: "Qwen3.5-Plus", Reasoning: true},
|
|
{ID: "bailian-coding-plan/qwen3-max", Name: "Qwen3-Max", Reasoning: true},
|
|
{ID: "bailian-coding-plan/qwen3-coder-next", Name: "Qwen3-Coder-Next", Reasoning: true},
|
|
{ID: "bailian-coding-plan/qwen3-coder-plus", Name: "Qwen3-Coder-Plus", Reasoning: true},
|
|
{ID: "bailian-coding-plan/minimax-m2.5", Name: "MiniMax M2.5", Reasoning: true},
|
|
{ID: "bailian-coding-plan/glm-5", Name: "GLM-5", Reasoning: true},
|
|
{ID: "bailian-coding-plan/kimi-k2.5", Name: "Kimi-k2.5", Reasoning: true},
|
|
{ID: "bailian-coding-plan/glm-4.7", Name: "GLM-4.7", Reasoning: true},
|
|
},
|
|
},
|
|
"ark-coding-plan": {
|
|
Key: "ark-coding-plan",
|
|
DisplayName: "方舟 Coding Plan",
|
|
Sort: 35,
|
|
DefaultBaseURL: "https://ark.cn-beijing.volces.com/api/coding/v3",
|
|
EnvKey: "ARK_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 4096,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "ark-coding-plan/ark-code-latest", Name: "Ark Coding Plan", ContextWindow: 256000, MaxTokens: 4096},
|
|
{ID: "ark-coding-plan/doubao-seed-code", Name: "Doubao Seed Code", ContextWindow: 256000, MaxTokens: 4096},
|
|
{ID: "ark-coding-plan/glm-4.7", Name: "GLM 4.7 Coding", ContextWindow: 200000, MaxTokens: 4096},
|
|
{ID: "ark-coding-plan/kimi-k2-thinking", Name: "Kimi K2 Thinking", ContextWindow: 256000, MaxTokens: 4096},
|
|
{ID: "ark-coding-plan/kimi-k2.5", Name: "Kimi K2.5 Coding", ContextWindow: 256000, MaxTokens: 4096},
|
|
{ID: "ark-coding-plan/doubao-seed-code-preview-251028", Name: "Doubao Seed Code Preview", ContextWindow: 256000, MaxTokens: 4096},
|
|
},
|
|
},
|
|
"zai": {
|
|
Key: "zai",
|
|
DisplayName: "Z.ai",
|
|
Sort: 40,
|
|
DefaultBaseURL: "https://open.bigmodel.cn/api/paas/v4",
|
|
EnvKey: "ZAI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 204800,
|
|
MaxTokens: 131072,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "zai/glm-5", Name: "GLM-5", Reasoning: true},
|
|
{ID: "zai/glm-4.7", Name: "GLM-4.7", Reasoning: true},
|
|
{ID: "zai/glm-4.7-flash", Name: "GLM-4.7-Flash", Reasoning: true},
|
|
{ID: "zai/glm-4.7-flashx", Name: "GLM-4.7-FlashX", Reasoning: true},
|
|
},
|
|
},
|
|
"minimax": {
|
|
Key: "minimax",
|
|
DisplayName: "MiniMax (CN)",
|
|
Sort: 45,
|
|
DefaultBaseURL: "https://api.minimaxi.com/anthropic",
|
|
EnvKey: "MINIMAX_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "anthropic-messages",
|
|
ContextWindow: 200000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "minimax/MiniMax-M2.7", Name: "MiniMax M2.7"},
|
|
{ID: "minimax/MiniMax-M2.7-highspeed", Name: "MiniMax M2.7 highspeed"},
|
|
{ID: "minimax/MiniMax-M2.5", Name: "MiniMax M2.5", Reasoning: true},
|
|
{ID: "minimax/MiniMax-M2.5-highspeed", Name: "MiniMax M2.5 highspeed"},
|
|
},
|
|
},
|
|
"xiaomi": {
|
|
Key: "xiaomi",
|
|
DisplayName: "Xiaomi",
|
|
Sort: 46,
|
|
DefaultBaseURL: "https://api.xiaomimimo.com/v1",
|
|
EnvKey: "XIAOMI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 262144,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "xiaomi/mimo-v2-flash", Name: "Xiaomi MiMo V2 Flash", ContextWindow: 262144, MaxTokens: 8192, Input: []string{"text"}},
|
|
{ID: "xiaomi/mimo-v2-pro", Name: "Xiaomi MiMo V2 Pro", ContextWindow: 1048576, MaxTokens: 32000, Reasoning: true, Input: []string{"text"}},
|
|
{ID: "xiaomi/mimo-v2-omni", Name: "Xiaomi MiMo V2 Omni", ContextWindow: 262144, MaxTokens: 32000, Reasoning: true, Input: []string{"text", "image"}},
|
|
},
|
|
},
|
|
"kimi": {
|
|
Key: "kimi",
|
|
DisplayName: "Kimi (CN)",
|
|
Sort: 50,
|
|
DefaultBaseURL: "https://api.moonshot.cn/v1",
|
|
EnvKey: "KIMI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text", "image"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "kimi/kimi-k2.5", Name: "Kimi K2.5", Reasoning: true},
|
|
{ID: "kimi/kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"},
|
|
{ID: "kimi/kimi-k2-thinking", Name: "Kimi K2 Thinking", Reasoning: true},
|
|
},
|
|
},
|
|
"kimi-coding": {
|
|
Key: "kimi-coding",
|
|
DisplayName: "Kimi Coding",
|
|
Sort: 51,
|
|
DefaultBaseURL: "https://api.kimi.com/coding/",
|
|
EnvKey: "KIMI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "anthropic-messages",
|
|
ContextWindow: 262144,
|
|
MaxTokens: 32768,
|
|
Input: []string{"text", "image"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "kimi-coding/kimi-code", Name: "Kimi Code", ContextWindow: 262144, MaxTokens: 32768, Reasoning: true, Input: []string{"text", "image"}},
|
|
{ID: "kimi-coding/k2p5", Name: "Kimi K2.5", ContextWindow: 262144, MaxTokens: 32768, Reasoning: true, Input: []string{"text", "image"}},
|
|
},
|
|
},
|
|
"openai": {
|
|
Key: "openai",
|
|
DisplayName: "OpenAI",
|
|
Sort: 55,
|
|
DefaultBaseURL: "https://api.openai.com/v1",
|
|
EnvKey: "OPENAI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-responses",
|
|
ContextWindow: 272000,
|
|
MaxTokens: 128000,
|
|
Input: []string{"text", "image"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "openai/gpt-5.4", Name: "gpt-5.4", ContextWindow: 272000, MaxTokens: 128000, Reasoning: true, Input: []string{"text", "image"}},
|
|
{ID: "openai/gpt-5.4-pro", Name: "gpt-5.4-pro", ContextWindow: 1050000, MaxTokens: 128000, Reasoning: true, Input: []string{"text", "image"}},
|
|
{ID: "openai/gpt-5.4-mini", Name: "gpt-5.4-mini", ContextWindow: 400000, MaxTokens: 128000, Reasoning: true, Input: []string{"text", "image"}},
|
|
{ID: "openai/gpt-5.4-nano", Name: "gpt-5.4-nano", ContextWindow: 400000, MaxTokens: 128000, Reasoning: true, Input: []string{"text", "image"}},
|
|
},
|
|
},
|
|
"openrouter": {
|
|
Key: "openrouter",
|
|
DisplayName: "OpenRouter",
|
|
Sort: 56,
|
|
DefaultBaseURL: "https://openrouter.ai/api/v1",
|
|
EnvKey: "OPENROUTER_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 128000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "openrouter/free", Name: "openrouter/free"},
|
|
{ID: "openrouter/auto", Name: "openrouter/auto"},
|
|
},
|
|
},
|
|
"anthropic": {
|
|
Key: "anthropic",
|
|
DisplayName: "Anthropic",
|
|
Sort: 60,
|
|
DefaultBaseURL: "https://api.anthropic.com",
|
|
EnvKey: "ANTHROPIC_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "anthropic-messages",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text", "image"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "anthropic/claude-sonnet-4-6", Name: "Claude Sonnet 4.6", Reasoning: true},
|
|
{ID: "anthropic/claude-opus-4-6", Name: "Claude Opus 4.6", Reasoning: true},
|
|
{ID: "anthropic/claude-opus-4-5", Name: "Claude Opus 4.5"},
|
|
{ID: "anthropic/claude-sonnet-4-5", Name: "Claude Sonnet 4.5"},
|
|
{ID: "anthropic/claude-haiku-4-5", Name: "Claude Haiku 4.5"},
|
|
},
|
|
},
|
|
"gemini": {
|
|
Key: "gemini",
|
|
DisplayName: "Gemini",
|
|
Sort: 65,
|
|
DefaultBaseURL: "https://generativelanguage.googleapis.com",
|
|
EnvKey: "GEMINI_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text", "image"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "google/gemini-3-flash-preview", Name: "Gemini 3 Flash Preview", Reasoning: true},
|
|
{ID: "google/gemini-flash-latest", Name: "Gemini Flash Latest"},
|
|
{ID: "google/gemini-3-pro-preview", Name: "Gemini 3 Pro Preview", Reasoning: true},
|
|
},
|
|
},
|
|
"moonshot": {
|
|
Key: "moonshot",
|
|
DisplayName: "Moonshot (Global)",
|
|
Sort: 70,
|
|
DefaultBaseURL: "https://api.moonshot.ai/v1",
|
|
EnvKey: "MOONSHOT_API_KEY",
|
|
Default: RuntimeDefault{
|
|
APIType: "openai-completions",
|
|
ContextWindow: 256000,
|
|
MaxTokens: 8192,
|
|
Input: []string{"text"},
|
|
},
|
|
Models: []Model{
|
|
{ID: "moonshot/kimi-k2.5", Name: "Kimi K2.5", Reasoning: true},
|
|
{ID: "moonshot/kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"},
|
|
{ID: "moonshot/kimi-k2-thinking", Name: "Kimi K2 Thinking", Reasoning: true},
|
|
},
|
|
},
|
|
}
|
|
|
|
func Get(key string) (Meta, bool) {
|
|
meta, ok := catalog[key]
|
|
if !ok {
|
|
return Meta{}, false
|
|
}
|
|
return cloneMeta(meta), true
|
|
}
|
|
|
|
func All() map[string]Meta {
|
|
result := make(map[string]Meta, len(catalog))
|
|
for key, meta := range catalog {
|
|
result[key] = cloneMeta(meta)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func DefaultBaseURL(key string) (string, bool) {
|
|
meta, ok := catalog[key]
|
|
if !ok || strings.TrimSpace(meta.DefaultBaseURL) == "" {
|
|
return "", false
|
|
}
|
|
return meta.DefaultBaseURL, true
|
|
}
|
|
|
|
func EnvKey(key string) string {
|
|
meta, ok := catalog[key]
|
|
if !ok {
|
|
return ""
|
|
}
|
|
return meta.EnvKey
|
|
}
|
|
|
|
func DisplayName(key string) string {
|
|
meta, ok := catalog[key]
|
|
if !ok {
|
|
return key
|
|
}
|
|
if strings.TrimSpace(meta.DisplayName) == "" {
|
|
return key
|
|
}
|
|
return meta.DisplayName
|
|
}
|
|
|
|
func FindModel(key, modelID string) (Model, bool) {
|
|
meta, ok := Get(key)
|
|
if !ok {
|
|
return Model{}, false
|
|
}
|
|
for _, item := range meta.Models {
|
|
if item.ID == modelID {
|
|
return item, true
|
|
}
|
|
}
|
|
return Model{}, false
|
|
}
|
|
|
|
func cloneMeta(meta Meta) Meta {
|
|
clone := meta
|
|
if len(meta.Default.Input) > 0 {
|
|
clone.Default.Input = make([]string, len(meta.Default.Input))
|
|
copy(clone.Default.Input, meta.Default.Input)
|
|
}
|
|
if len(meta.Models) > 0 {
|
|
clone.Models = make([]Model, len(meta.Models))
|
|
for i, item := range meta.Models {
|
|
clone.Models[i] = normalizeModel(meta, item)
|
|
}
|
|
}
|
|
return clone
|
|
}
|
|
|
|
func normalizeModel(meta Meta, model Model) Model {
|
|
clone := model
|
|
clone.ID = strings.TrimSpace(clone.ID)
|
|
clone.Name = strings.TrimSpace(clone.Name)
|
|
if clone.Name == "" {
|
|
clone.Name = clone.ID
|
|
}
|
|
if clone.MaxTokens <= 0 {
|
|
clone.MaxTokens = meta.Default.MaxTokens
|
|
}
|
|
if clone.ContextWindow <= 0 {
|
|
clone.ContextWindow = meta.Default.ContextWindow
|
|
}
|
|
if len(clone.Input) == 0 && len(meta.Default.Input) > 0 {
|
|
clone.Input = make([]string, len(meta.Default.Input))
|
|
copy(clone.Input, meta.Default.Input)
|
|
}
|
|
return clone
|
|
}
|
|
|
|
func ResolveRuntimeParams(provider, apiType string, maxTokens, contextWindow int) (string, int, int) {
|
|
defaultAPIType := "openai-completions"
|
|
defaultMaxTokens := 8192
|
|
defaultContextWindow := 256000
|
|
if meta, ok := Get(provider); ok {
|
|
if meta.Default.APIType != "" {
|
|
defaultAPIType = meta.Default.APIType
|
|
}
|
|
if meta.Default.MaxTokens > 0 {
|
|
defaultMaxTokens = meta.Default.MaxTokens
|
|
}
|
|
if meta.Default.ContextWindow > 0 {
|
|
defaultContextWindow = meta.Default.ContextWindow
|
|
}
|
|
}
|
|
resolvedAPI := apiType
|
|
if strings.TrimSpace(apiType) == "" {
|
|
resolvedAPI = defaultAPIType
|
|
}
|
|
resolvedMaxTokens := defaultMaxTokens
|
|
resolvedContextWindow := defaultContextWindow
|
|
if maxTokens > 0 {
|
|
resolvedMaxTokens = maxTokens
|
|
}
|
|
if contextWindow > 0 {
|
|
resolvedContextWindow = contextWindow
|
|
}
|
|
return resolvedAPI, resolvedMaxTokens, resolvedContextWindow
|
|
}
|