diff --git a/.gitignore b/.gitignore
index be36d9a..912a1a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,6 @@
-ui_example
node_modules
ui/node_modules
ui/ModelModal/node_modules
ui/ModelModal/dist
.DS_Store
-main
-main.go
-handler
-templates
+test/ui_example/dist
diff --git a/consts/model.go b/consts/model.go
index 7b9f14f..15d05aa 100644
--- a/consts/model.go
+++ b/consts/model.go
@@ -1,7 +1,6 @@
package consts
import (
- "errors"
"strings"
)
@@ -23,47 +22,88 @@ const (
ModelTypeFunctionCall ModelType = "function_call"
)
-func ParseModelType(s string) (ModelType, error) {
+func ParseModelType(s string) ModelType {
switch s {
case "llm", "chat":
- return ModelTypeChat, nil
+ return ModelTypeChat
case "coder", "code":
- return ModelTypeCoder, nil
+ return ModelTypeCoder
case "embedding":
- return ModelTypeEmbedding, nil
+ return ModelTypeEmbedding
case "reranker", "rerank":
- return ModelTypeRerank, nil
+ return ModelTypeRerank
case "vision":
- return ModelTypeVision, nil
+ return ModelTypeVision
case "function_call":
- return ModelTypeFunctionCall, nil
+ return ModelTypeFunctionCall
default:
- return "", errors.New("invalid model type")
+ return ModelTypeChat
}
}
type ModelProvider string
const (
- ModelProviderSiliconFlow ModelProvider = "SiliconFlow"
- ModelProviderOpenAI ModelProvider = "OpenAI"
- ModelProviderOllama ModelProvider = "Ollama"
- ModelProviderDeepSeek ModelProvider = "DeepSeek"
- ModelProviderMoonshot ModelProvider = "Moonshot"
- ModelProviderAzureOpenAI ModelProvider = "AzureOpenAI"
- ModelProviderBaiZhiCloud ModelProvider = "BaiZhiCloud"
- ModelProviderHunyuan ModelProvider = "Hunyuan"
- ModelProviderBaiLian ModelProvider = "BaiLian"
- ModelProviderVolcengine ModelProvider = "Volcengine"
- ModelProviderGemini ModelProvider = "Gemini"
- ModelProviderZhiPu ModelProvider = "ZhiPu"
- ModelProviderOther ModelProvider = "Other"
+ ModelProviderSiliconFlow ModelProvider = "SiliconFlow"
+ ModelProviderOpenAI ModelProvider = "OpenAI"
+ ModelProviderOllama ModelProvider = "Ollama"
+ ModelProviderDeepSeek ModelProvider = "DeepSeek"
+ ModelProviderMoonshot ModelProvider = "Moonshot"
+ ModelProviderAzureOpenAI ModelProvider = "AzureOpenAI"
+ ModelProviderBaiZhiCloud ModelProvider = "BaiZhiCloud"
+ ModelProviderHunyuan ModelProvider = "Hunyuan"
+ ModelProviderBaiLian ModelProvider = "BaiLian"
+ ModelProviderVolcengine ModelProvider = "Volcengine"
+ ModelProviderGemini ModelProvider = "Gemini"
+ ModelProviderZhiPu ModelProvider = "ZhiPu"
+ ModelProviderAiHubMix ModelProvider = "AiHubMix"
+ ModelProviderOcoolAI ModelProvider = "OcoolAI"
+ ModelProviderPPIO ModelProvider = "PPIO"
+ ModelProviderAlayaNew ModelProvider = "AlayaNew"
+ ModelProviderQiniu ModelProvider = "Qiniu"
+ ModelProviderDMXAPI ModelProvider = "DMXAPI"
+ ModelProviderBurnCloud ModelProvider = "BurnCloud"
+ ModelProviderTokenFlux ModelProvider = "TokenFlux"
+ ModelProvider302AI ModelProvider = "302AI"
+ ModelProviderCephalon ModelProvider = "Cephalon"
+ ModelProviderLanyun ModelProvider = "Lanyun"
+ ModelProviderPH8 ModelProvider = "PH8"
+ ModelProviderOpenRouter ModelProvider = "OpenRouter"
+ ModelProviderNewAPI ModelProvider = "NewAPI"
+ ModelProviderLMStudio ModelProvider = "LMStudio"
+ ModelProviderAnthropic ModelProvider = "Anthropic"
+ ModelProviderVertexAI ModelProvider = "VertexAI"
+ ModelProviderGithub ModelProvider = "Github"
+ ModelProviderCopilot ModelProvider = "Copilot"
+ ModelProviderYi ModelProvider = "Yi"
+ ModelProviderBaichuan ModelProvider = "Baichuan"
+ ModelProviderStepFun ModelProvider = "StepFun"
+ ModelProviderInfini ModelProvider = "Infini"
+ ModelProviderMiniMax ModelProvider = "MiniMax"
+ ModelProviderGroq ModelProvider = "Groq"
+ ModelProviderTogether ModelProvider = "Together"
+ ModelProviderFireworks ModelProvider = "Fireworks"
+ ModelProviderNvidia ModelProvider = "Nvidia"
+ ModelProviderGrok ModelProvider = "Grok"
+ ModelProviderHyperbolic ModelProvider = "Hyperbolic"
+ ModelProviderMistral ModelProvider = "Mistral"
+ ModelProviderJina ModelProvider = "Jina"
+ ModelProviderPerplexity ModelProvider = "Perplexity"
+ ModelProviderModelScope ModelProvider = "ModelScope"
+ ModelProviderXirang ModelProvider = "Xirang"
+ ModelProviderTencentCloudTI ModelProvider = "TencentCloudTI"
+ ModelProviderBaiduCloud ModelProvider = "BaiduCloud"
+ ModelProviderGPUStack ModelProvider = "GPUStack"
+ ModelProviderVoyageAI ModelProvider = "VoyageAI"
+ ModelProviderAWSBedrock ModelProvider = "AWSBedrock"
+ ModelProviderPoe ModelProvider = "Poe"
+ ModelProviderOther ModelProvider = "Other"
)
func ParseModelProvider(s string) ModelProvider {
// 转换为小写进行不区分大小写的比较
switch strings.ToLower(s) {
- case "siliconflow":
+ case "siliconflow", "silicon":
return ModelProviderSiliconFlow
case "openai":
return ModelProviderOpenAI
@@ -73,7 +113,7 @@ func ParseModelProvider(s string) ModelProvider {
return ModelProviderDeepSeek
case "moonshot":
return ModelProviderMoonshot
- case "azureopenai":
+ case "azureopenai", "azure-openai":
return ModelProviderAzureOpenAI
case "baizhicloud", "baizhiyun":
return ModelProviderBaiZhiCloud
@@ -81,12 +121,94 @@ func ParseModelProvider(s string) ModelProvider {
return ModelProviderHunyuan
case "bailian":
return ModelProviderBaiLian
- case "volcengine":
+ case "volcengine", "doubao":
return ModelProviderVolcengine
case "gemini":
return ModelProviderGemini
case "zhipu":
return ModelProviderZhiPu
+ case "aihubmix":
+ return ModelProviderAiHubMix
+ case "ocoolai":
+ return ModelProviderOcoolAI
+ case "ppio":
+ return ModelProviderPPIO
+ case "alayanew":
+ return ModelProviderAlayaNew
+ case "qiniu":
+ return ModelProviderQiniu
+ case "dmxapi":
+ return ModelProviderDMXAPI
+ case "burncloud":
+ return ModelProviderBurnCloud
+ case "tokenflux":
+ return ModelProviderTokenFlux
+ case "302ai":
+ return ModelProvider302AI
+ case "cephalon":
+ return ModelProviderCephalon
+ case "lanyun":
+ return ModelProviderLanyun
+ case "ph8":
+ return ModelProviderPH8
+ case "openrouter":
+ return ModelProviderOpenRouter
+ case "new-api":
+ return ModelProviderNewAPI
+ case "lmstudio":
+ return ModelProviderLMStudio
+ case "anthropic":
+ return ModelProviderAnthropic
+ case "vertexai":
+ return ModelProviderVertexAI
+ case "github":
+ return ModelProviderGithub
+ case "copilot":
+ return ModelProviderCopilot
+ case "yi":
+ return ModelProviderYi
+ case "baichuan":
+ return ModelProviderBaichuan
+ case "stepfun":
+ return ModelProviderStepFun
+ case "infini":
+ return ModelProviderInfini
+ case "minimax":
+ return ModelProviderMiniMax
+ case "groq":
+ return ModelProviderGroq
+ case "together":
+ return ModelProviderTogether
+ case "fireworks":
+ return ModelProviderFireworks
+ case "nvidia":
+ return ModelProviderNvidia
+ case "grok":
+ return ModelProviderGrok
+ case "hyperbolic":
+ return ModelProviderHyperbolic
+ case "mistral":
+ return ModelProviderMistral
+ case "jina":
+ return ModelProviderJina
+ case "perplexity":
+ return ModelProviderPerplexity
+ case "modelscope":
+ return ModelProviderModelScope
+ case "xirang":
+ return ModelProviderXirang
+ case "tencent-cloud-ti":
+ return ModelProviderTencentCloudTI
+ case "baidu-cloud":
+ return ModelProviderBaiduCloud
+ case "gpustack":
+ return ModelProviderGPUStack
+ case "voyageai":
+ return ModelProviderVoyageAI
+ case "aws-bedrock":
+ return ModelProviderAWSBedrock
+ case "poe":
+ return ModelProviderPoe
default:
return ModelProviderOther
}
diff --git a/domain/domain.go b/domain/domain.go
new file mode 100644
index 0000000..53a725f
--- /dev/null
+++ b/domain/domain.go
@@ -0,0 +1,106 @@
+package domain
+
+import (
+ "github.com/chaitin/ModelKit/consts"
+)
+
+type ModelKit interface {
+ // CheckModel(ctx context.Context, req *CheckModelReq) (*Model, error)
+}
+
+type ModelListReq struct {
+ Provider string `json:"provider" query:"provider" validate:"required"`
+ BaseURL string `json:"base_url" query:"base_url" validate:"required"`
+ APIKey string `json:"api_key" query:"api_key"`
+ APIHeader string `json:"api_header" query:"api_header"`
+ Type string `json:"type" query:"type" validate:"required"`
+}
+
+type Response struct {
+ Message string `json:"message"`
+ Success bool `json:"success"`
+ Data any `json:"data,omitempty"`
+}
+
+type ModelListResp struct {
+ Models []ModelListItem `json:"models"`
+}
+
+type ModelListItem struct {
+ Model string `json:"model"`
+}
+
+type CheckModelReq struct {
+ Provider string `json:"provider" query:"provider" validate:"required,oneof=OpenAI Ollama DeepSeek SiliconFlow Moonshot Other AzureOpenAI BaiZhiCloud Hunyuan BaiLian Volcengine Gemini ZhiPu AiHubMix"`
+ Model string `json:"model" query:"model_name" validate:"required"`
+ BaseURL string `json:"base_url" query:"base_url" validate:"required"`
+ APIKey string `json:"api_key" query:"api_key"`
+ APIHeader string `json:"api_header" query:"api_header"`
+ APIVersion string `json:"api_version" query:"api_version"` // for azure openai
+ Type string `json:"type" query:"model_type" validate:"required,oneof=chat embedding rerank llm"`
+}
+
+type CheckModelResp struct {
+ Error string `json:"error"`
+ Content string `json:"content"`
+}
+
+func getModelsByOwner(owner consts.ModelProvider) []ModelMetadata {
+ var ms []ModelMetadata
+ for i := range Models {
+ if Models[i].Provider == owner {
+ ms = append(ms, Models[i])
+ }
+ }
+ return ms
+}
+
+func init() {
+ initModels()
+ initModelProviders()
+}
+
+func From(ModelProvider ModelProvider) []ModelListItem {
+ var result []ModelListItem
+ for _, model := range ModelProvider.Models {
+ result = append(result, ModelListItem{
+ Model: model.ModelName,
+ })
+ }
+ return result
+}
+
+// ModelResponseParser 定义模型响应解析器接口
+type ModelResponseParser interface {
+ ParseModels() []ModelListItem
+}
+
+type GithubModel struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Registry string `json:"registry"`
+ Publisher string `json:"publisher"`
+ Summary string `json:"summary"`
+ RateLimitTier string `json:"rate_limit_tier"`
+ HTMLURL string `json:"html_url"`
+ Version string `json:"version"`
+ Capabilities []string `json:"capabilities"`
+ Limits struct {
+ MaxInputTokens int `json:"max_input_tokens"`
+ MaxOutputTokens int `json:"max_output_tokens"`
+ } `json:"limits"`
+ Tags []string `json:"tags"`
+ SupportedInputModalities []string `json:"supported_input_modalities"`
+ SupportedOutputModalities []string `json:"supported_output_modalities"`
+}
+
+type GithubResp []GithubModel
+
+// ParseModels 实现ModelResponseParser接口
+func (g *GithubResp) ParseModels() []ModelListItem {
+ var models []ModelListItem
+ for _, item := range *g {
+ models = append(models, ModelListItem{Model: item.ID})
+ }
+ return models
+}
diff --git a/domain/modelkit.go b/domain/model.go
similarity index 88%
rename from domain/modelkit.go
rename to domain/model.go
index 432bb84..a230c2d 100644
--- a/domain/modelkit.go
+++ b/domain/model.go
@@ -1,58 +1,6 @@
package domain
-import (
- "github.com/chaitin/ModelKit/consts"
-)
-
-type ModelKit interface {
- // CheckModel(ctx context.Context, req *CheckModelReq) (*Model, error)
-}
-
-type ModelListReq struct {
- Provider string `json:"provider" query:"provider" validate:"required,oneof=SiliconFlow OpenAI Ollama DeepSeek Moonshot AzureOpenAI BaiZhiCloud Hunyuan BaiLian Volcengine Gemini ZhiPu"`
- BaseURL string `json:"base_url" query:"base_url" validate:"required"`
- APIKey string `json:"api_key" query:"api_key"`
- APIHeader string `json:"api_header" query:"api_header"`
- Type string `json:"type" query:"type" validate:"required,oneof=chat embedding rerank"`
-}
-
-type Response struct {
- Message string `json:"message"`
- Success bool `json:"success"`
- Data any `json:"data,omitempty"`
-}
-
-type ModelListResp struct {
- Models []ModelListItem `json:"models"`
-}
-
-type ModelListItem struct {
- Model string `json:"model"`
-}
-
-type CheckModelReq struct {
- Provider string `json:"provider" validate:"required,oneof=OpenAI Ollama DeepSeek SiliconFlow Moonshot Other AzureOpenAI BaiZhiCloud Hunyuan BaiLian Volcengine Gemini ZhiPu"`
- Model string `json:"model" validate:"required"`
- BaseURL string `json:"base_url" validate:"required"`
- APIKey string `json:"api_key"`
- APIHeader string `json:"api_header"`
- APIVersion string `json:"api_version"` // for azure openai
- Type string `json:"type" validate:"required,oneof=chat embedding rerank"`
-}
-
-type ModelProvider struct {
- OwnerName consts.ModelProvider `json:"owner_name"` // 提供商
- APIBase string `json:"api_base"` // 接口地址 如:https://api.qwen.com
- APIKey string `json:"api_key"` // 接口密钥 如:sk-xxxx
- APIVersion string `json:"api_version"` // 接口版本 如:2023-05-15
- APIHeader string `json:"api_header"` // 接口头 如:Authorization: Bearer sk-xxxx
- Models []ModelMetadata `json:"models"` // 模型列表
-}
-
-type CheckModelResp struct {
- Error string `json:"error"`
- Content string `json:"content"`
-}
+import "github.com/chaitin/ModelKit/consts"
type ModelMetadata struct {
ModelName string `json:"id"` // 模型的名字
@@ -68,23 +16,6 @@ type ModelMetadata struct {
}
var Models []ModelMetadata
-var ModelProviders map[consts.ModelProvider]ModelProvider
-var TypeModelMap map[consts.ModelType][]ModelMetadata
-
-func getModelsByOwner(owner consts.ModelProvider) []ModelMetadata {
- var ms []ModelMetadata
- for i := range Models {
- if Models[i].Provider == owner {
- ms = append(ms, Models[i])
- }
- }
- return ms
-}
-
-func init() {
- initModels()
- initModelProviders()
-}
// getBaiZhiCloudModels 返回百智云模型列表
func getBaiZhiCloudModels() []ModelMetadata {
@@ -486,92 +417,4 @@ func initModels() {
Models = append(Models, getAzureOpenAIModels()...)
Models = append(Models, getZhiPuModels()...)
Models = append(Models, getGeminiModels()...)
-}
-
-func initModelProviders() {
- // 初始化模型提供商及其模型
- ModelProviders = map[consts.ModelProvider]ModelProvider{
- consts.ModelProviderBaiZhiCloud: {
- OwnerName: consts.ModelProviderBaiZhiCloud,
- Models: getModelsByOwner(consts.ModelProviderBaiZhiCloud),
- APIBase: "https://model-square.app.baizhi.cloud/v1",
- },
- consts.ModelProviderDeepSeek: {
- OwnerName: consts.ModelProviderDeepSeek,
- Models: getModelsByOwner(consts.ModelProviderDeepSeek),
- APIBase: "https://api.deepseek.com/v1",
- },
- consts.ModelProviderSiliconFlow: {
- OwnerName: consts.ModelProviderSiliconFlow,
- Models: getModelsByOwner(consts.ModelProviderSiliconFlow),
- APIBase: "https://api.siliconflow.cn/v1",
- },
- consts.ModelProviderOpenAI: {
- OwnerName: consts.ModelProviderOpenAI,
- Models: getModelsByOwner(consts.ModelProviderOpenAI),
- APIBase: "https://api.openai.com/v1",
- },
- consts.ModelProviderOllama: {
- OwnerName: consts.ModelProviderOllama,
- Models: getModelsByOwner(consts.ModelProviderOllama),
- APIBase: "http://localhost:11434",
- },
- consts.ModelProviderMoonshot: {
- OwnerName: consts.ModelProviderMoonshot,
- Models: getModelsByOwner(consts.ModelProviderMoonshot),
- APIBase: "https://api.moonshot.cn/v1",
- },
- consts.ModelProviderAzureOpenAI: {
- OwnerName: consts.ModelProviderAzureOpenAI,
- Models: getModelsByOwner(consts.ModelProviderAzureOpenAI),
- },
- consts.ModelProviderHunyuan: {
- OwnerName: consts.ModelProviderHunyuan,
- Models: getModelsByOwner(consts.ModelProviderHunyuan),
- APIBase: "https://api.hunyuan.cloud.tencent.com/v1",
- },
- consts.ModelProviderBaiLian: {
- OwnerName: consts.ModelProviderBaiLian,
- Models: getModelsByOwner(consts.ModelProviderBaiLian),
- APIBase: "https://dashscope.aliyuncs.com/compatible-mode/v1",
- },
- consts.ModelProviderVolcengine: {
- OwnerName: consts.ModelProviderVolcengine,
- Models: getModelsByOwner(consts.ModelProviderVolcengine),
- APIBase: "https://ark.cn-beijing.volces.com/api/v3",
- },
- consts.ModelProviderGemini: {
- OwnerName: consts.ModelProviderGemini,
- Models: getModelsByOwner(consts.ModelProviderGemini),
- APIBase: "https://generativelanguage.googleapis.com/v1beta",
- },
- consts.ModelProviderZhiPu: {
- OwnerName: consts.ModelProviderZhiPu,
- Models: getModelsByOwner(consts.ModelProviderZhiPu),
- APIBase: "https://open.bigmodel.cn/api/paas/v4",
- },
- }
-
- // 初始化按类型分组的模型映射
- TypeModelMap = make(map[consts.ModelType][]ModelMetadata)
- for i := range Models {
- model := Models[i]
- TypeModelMap[model.ModelType] = append(TypeModelMap[model.ModelType], model)
- }
-}
-
-type Resp struct {
- Code int `json:"code"`
- Message string `json:"message"`
- Data any `json:"data,omitempty"`
-}
-
-func From(ModelProvider ModelProvider) []ModelListItem {
- var result []ModelListItem
- for _, model := range ModelProvider.Models {
- result = append(result, ModelListItem{
- Model: model.ModelName,
- })
- }
- return result
-}
+}
\ No newline at end of file
diff --git a/domain/modelprovider.go b/domain/modelprovider.go
index 8595b29..edd42a1 100644
--- a/domain/modelprovider.go
+++ b/domain/modelprovider.go
@@ -1,5 +1,296 @@
package domain
+import "github.com/chaitin/ModelKit/consts"
+
type IModelProvider[T any] interface {
ListModel(subType string, provider string) ([]T, error)
+}
+
+var ModelProviders map[consts.ModelProvider]ModelProvider
+var TypeModelMap map[consts.ModelType][]ModelMetadata
+
+type ModelProvider struct {
+ OwnerName consts.ModelProvider `json:"owner_name"` // 提供商
+ APIBase string `json:"api_base"` // 接口地址 如:https://api.qwen.com
+ APIKey string `json:"api_key"` // 接口密钥 如:sk-xxxx
+ APIVersion string `json:"api_version"` // 接口版本 如:2023-05-15
+ APIHeader string `json:"api_header"` // 接口头 如:Authorization: Bearer sk-xxxx
+ Models []ModelMetadata `json:"models"` // 模型列表
+}
+
+func initModelProviders() {
+ // 初始化模型提供商及其模型
+ ModelProviders = map[consts.ModelProvider]ModelProvider{
+ consts.ModelProviderBaiZhiCloud: {
+ OwnerName: consts.ModelProviderBaiZhiCloud,
+ Models: getModelsByOwner(consts.ModelProviderBaiZhiCloud),
+ APIBase: "https://model-square.app.baizhi.cloud/v1",
+ },
+ consts.ModelProviderDeepSeek: {
+ OwnerName: consts.ModelProviderDeepSeek,
+ Models: getModelsByOwner(consts.ModelProviderDeepSeek),
+ APIBase: "https://api.deepseek.com/v1",
+ },
+ consts.ModelProviderSiliconFlow: {
+ OwnerName: consts.ModelProviderSiliconFlow,
+ Models: getModelsByOwner(consts.ModelProviderSiliconFlow),
+ APIBase: "https://api.siliconflow.cn/v1",
+ },
+ consts.ModelProviderOpenAI: {
+ OwnerName: consts.ModelProviderOpenAI,
+ Models: getModelsByOwner(consts.ModelProviderOpenAI),
+ APIBase: "https://api.openai.com/v1",
+ },
+ consts.ModelProviderOllama: {
+ OwnerName: consts.ModelProviderOllama,
+ Models: getModelsByOwner(consts.ModelProviderOllama),
+ APIBase: "http://localhost:11434",
+ },
+ consts.ModelProviderMoonshot: {
+ OwnerName: consts.ModelProviderMoonshot,
+ Models: getModelsByOwner(consts.ModelProviderMoonshot),
+ APIBase: "https://api.moonshot.cn/v1",
+ },
+ consts.ModelProviderAzureOpenAI: {
+ OwnerName: consts.ModelProviderAzureOpenAI,
+ Models: getModelsByOwner(consts.ModelProviderAzureOpenAI),
+ },
+ consts.ModelProviderHunyuan: {
+ OwnerName: consts.ModelProviderHunyuan,
+ Models: getModelsByOwner(consts.ModelProviderHunyuan),
+ APIBase: "https://api.hunyuan.cloud.tencent.com/v1",
+ },
+ consts.ModelProviderBaiLian: {
+ OwnerName: consts.ModelProviderBaiLian,
+ Models: getModelsByOwner(consts.ModelProviderBaiLian),
+ APIBase: "https://dashscope.aliyuncs.com/compatible-mode/v1",
+ },
+ consts.ModelProviderVolcengine: {
+ OwnerName: consts.ModelProviderVolcengine,
+ Models: getModelsByOwner(consts.ModelProviderVolcengine),
+ APIBase: "https://ark.cn-beijing.volces.com/api/v3",
+ },
+ consts.ModelProviderGemini: {
+ OwnerName: consts.ModelProviderGemini,
+ Models: getModelsByOwner(consts.ModelProviderGemini),
+ APIBase: "https://generativelanguage.googleapis.com/v1beta",
+ },
+ consts.ModelProviderZhiPu: {
+ OwnerName: consts.ModelProviderZhiPu,
+ Models: getModelsByOwner(consts.ModelProviderZhiPu),
+ APIBase: "https://open.bigmodel.cn/api/paas/v4",
+ },
+ consts.ModelProviderAiHubMix: {
+ OwnerName: consts.ModelProviderAiHubMix,
+ Models: getModelsByOwner(consts.ModelProviderAiHubMix),
+ APIBase: "https://aihubmix.com/v1",
+ },
+ consts.ModelProviderOcoolAI: {
+ OwnerName: consts.ModelProviderOcoolAI,
+ Models: getModelsByOwner(consts.ModelProviderOcoolAI),
+ APIBase: "https://api.ocoolai.com/v1",
+ },
+ consts.ModelProviderPPIO: {
+ OwnerName: consts.ModelProviderPPIO,
+ Models: getModelsByOwner(consts.ModelProviderPPIO),
+ APIBase: "https://api.ppinfra.com/v3/openai",
+ },
+ consts.ModelProviderAlayaNew: {
+ OwnerName: consts.ModelProviderAlayaNew,
+ Models: getModelsByOwner(consts.ModelProviderAlayaNew),
+ APIBase: "https://deepseek.alayanew.com/v1",
+ },
+ consts.ModelProviderQiniu: {
+ OwnerName: consts.ModelProviderQiniu,
+ Models: getModelsByOwner(consts.ModelProviderQiniu),
+ APIBase: "https://api.qnaigc.com/v1",
+ },
+ consts.ModelProviderDMXAPI: {
+ OwnerName: consts.ModelProviderDMXAPI,
+ Models: getModelsByOwner(consts.ModelProviderDMXAPI),
+ APIBase: "https://www.dmxapi.cn/v1",
+ },
+ consts.ModelProviderBurnCloud: {
+ OwnerName: consts.ModelProviderBurnCloud,
+ Models: getModelsByOwner(consts.ModelProviderBurnCloud),
+ APIBase: "https://ai.burncloud.com/v1",
+ },
+ consts.ModelProviderTokenFlux: {
+ OwnerName: consts.ModelProviderTokenFlux,
+ Models: getModelsByOwner(consts.ModelProviderTokenFlux),
+ APIBase: "https://tokenflux.ai/v1",
+ },
+ consts.ModelProvider302AI: {
+ OwnerName: consts.ModelProvider302AI,
+ Models: getModelsByOwner(consts.ModelProvider302AI),
+ APIBase: "https://api.302.ai/v1",
+ },
+ consts.ModelProviderCephalon: {
+ OwnerName: consts.ModelProviderCephalon,
+ Models: getModelsByOwner(consts.ModelProviderCephalon),
+ APIBase: "https://cephalon.cloud/user-center/v1/model",
+ },
+ consts.ModelProviderLanyun: {
+ OwnerName: consts.ModelProviderLanyun,
+ Models: getModelsByOwner(consts.ModelProviderLanyun),
+ APIBase: "https://maas-api.lanyun.net/v1",
+ },
+ consts.ModelProviderPH8: {
+ OwnerName: consts.ModelProviderPH8,
+ Models: getModelsByOwner(consts.ModelProviderPH8),
+ APIBase: "https://ph8.co/v1",
+ },
+ consts.ModelProviderOpenRouter: {
+ OwnerName: consts.ModelProviderOpenRouter,
+ Models: getModelsByOwner(consts.ModelProviderOpenRouter),
+ APIBase: "https://openrouter.ai/api/v1",
+ },
+ consts.ModelProviderNewAPI: {
+ OwnerName: consts.ModelProviderNewAPI,
+ Models: getModelsByOwner(consts.ModelProviderNewAPI),
+ APIBase: "http://localhost:3000/v1",
+ },
+ consts.ModelProviderLMStudio: {
+ OwnerName: consts.ModelProviderLMStudio,
+ Models: getModelsByOwner(consts.ModelProviderLMStudio),
+ APIBase: "http://localhost:1234/v1",
+ },
+ consts.ModelProviderAnthropic: {
+ OwnerName: consts.ModelProviderAnthropic,
+ Models: getModelsByOwner(consts.ModelProviderAnthropic),
+ APIBase: "https://api.anthropic.com",
+ },
+ consts.ModelProviderVertexAI: {
+ OwnerName: consts.ModelProviderVertexAI,
+ Models: getModelsByOwner(consts.ModelProviderVertexAI),
+ APIBase: "https://aiplatform.googleapis.com",
+ },
+ consts.ModelProviderGithub: {
+ OwnerName: consts.ModelProviderGithub,
+ Models: getModelsByOwner(consts.ModelProviderGithub),
+ APIBase: "https://models.github.ai/inference/v1",
+ },
+ consts.ModelProviderCopilot: {
+ OwnerName: consts.ModelProviderCopilot,
+ Models: getModelsByOwner(consts.ModelProviderCopilot),
+ APIBase: "https://api.githubcopilot.com/v1",
+ },
+ consts.ModelProviderYi: {
+ OwnerName: consts.ModelProviderYi,
+ Models: getModelsByOwner(consts.ModelProviderYi),
+ APIBase: "https://api.lingyiwanwu.com/v1",
+ },
+ consts.ModelProviderBaichuan: {
+ OwnerName: consts.ModelProviderBaichuan,
+ Models: getModelsByOwner(consts.ModelProviderBaichuan),
+ APIBase: "https://api.baichuan-ai.com/v1",
+ },
+ consts.ModelProviderStepFun: {
+ OwnerName: consts.ModelProviderStepFun,
+ Models: getModelsByOwner(consts.ModelProviderStepFun),
+ APIBase: "https://api.stepfun.com/v1",
+ },
+ consts.ModelProviderInfini: {
+ OwnerName: consts.ModelProviderInfini,
+ Models: getModelsByOwner(consts.ModelProviderInfini),
+ APIBase: "https://cloud.infini-ai.com/maas/v1",
+ },
+ consts.ModelProviderMiniMax: {
+ OwnerName: consts.ModelProviderMiniMax,
+ Models: getModelsByOwner(consts.ModelProviderMiniMax),
+ APIBase: "https://api.minimax.chat/v1",
+ },
+ consts.ModelProviderGroq: {
+ OwnerName: consts.ModelProviderGroq,
+ Models: getModelsByOwner(consts.ModelProviderGroq),
+ APIBase: "https://api.groq.com/openai/v1",
+ },
+ consts.ModelProviderTogether: {
+ OwnerName: consts.ModelProviderTogether,
+ Models: getModelsByOwner(consts.ModelProviderTogether),
+ APIBase: "https://api.together.xyz/v1",
+ },
+ consts.ModelProviderFireworks: {
+ OwnerName: consts.ModelProviderFireworks,
+ Models: getModelsByOwner(consts.ModelProviderFireworks),
+ APIBase: "https://api.fireworks.ai/inference/v1",
+ },
+ consts.ModelProviderNvidia: {
+ OwnerName: consts.ModelProviderNvidia,
+ Models: getModelsByOwner(consts.ModelProviderNvidia),
+ APIBase: "https://integrate.api.nvidia.com/v1",
+ },
+ consts.ModelProviderGrok: {
+ OwnerName: consts.ModelProviderGrok,
+ Models: getModelsByOwner(consts.ModelProviderGrok),
+ APIBase: "https://api.x.ai/v1",
+ },
+ consts.ModelProviderHyperbolic: {
+ OwnerName: consts.ModelProviderHyperbolic,
+ Models: getModelsByOwner(consts.ModelProviderHyperbolic),
+ APIBase: "https://api.hyperbolic.xyz/v1",
+ },
+ consts.ModelProviderMistral: {
+ OwnerName: consts.ModelProviderMistral,
+ Models: getModelsByOwner(consts.ModelProviderMistral),
+ APIBase: "https://api.mistral.ai/v1",
+ },
+ consts.ModelProviderJina: {
+ OwnerName: consts.ModelProviderJina,
+ Models: getModelsByOwner(consts.ModelProviderJina),
+ APIBase: "https://api.jina.ai/v1",
+ },
+ consts.ModelProviderPerplexity: {
+ OwnerName: consts.ModelProviderPerplexity,
+ Models: getModelsByOwner(consts.ModelProviderPerplexity),
+ APIBase: "https://api.perplexity.ai/v1",
+ },
+ consts.ModelProviderModelScope: {
+ OwnerName: consts.ModelProviderModelScope,
+ Models: getModelsByOwner(consts.ModelProviderModelScope),
+ APIBase: "https://api-inference.modelscope.cn/v1",
+ },
+ consts.ModelProviderXirang: {
+ OwnerName: consts.ModelProviderXirang,
+ Models: getModelsByOwner(consts.ModelProviderXirang),
+ APIBase: "https://wishub-x1.ctyun.cn/v1",
+ },
+ consts.ModelProviderTencentCloudTI: {
+ OwnerName: consts.ModelProviderTencentCloudTI,
+ Models: getModelsByOwner(consts.ModelProviderTencentCloudTI),
+ APIBase: "https://api.lkeap.cloud.tencent.com/v1",
+ },
+ consts.ModelProviderBaiduCloud: {
+ OwnerName: consts.ModelProviderBaiduCloud,
+ Models: getModelsByOwner(consts.ModelProviderBaiduCloud),
+ APIBase: "https://qianfan.baidubce.com/v2",
+ },
+ consts.ModelProviderGPUStack: {
+ OwnerName: consts.ModelProviderGPUStack,
+ Models: getModelsByOwner(consts.ModelProviderGPUStack),
+ APIBase: "",
+ },
+ consts.ModelProviderVoyageAI: {
+ OwnerName: consts.ModelProviderVoyageAI,
+ Models: getModelsByOwner(consts.ModelProviderVoyageAI),
+ APIBase: "https://api.voyageai.com/v1",
+ },
+ consts.ModelProviderAWSBedrock: {
+ OwnerName: consts.ModelProviderAWSBedrock,
+ Models: getModelsByOwner(consts.ModelProviderAWSBedrock),
+ APIBase: "",
+ },
+ consts.ModelProviderPoe: {
+ OwnerName: consts.ModelProviderPoe,
+ Models: getModelsByOwner(consts.ModelProviderPoe),
+ APIBase: "https://api.poe.com/v1",
+ },
+ }
+
+ // 初始化按类型分组的模型映射
+ TypeModelMap = make(map[consts.ModelType][]ModelMetadata)
+ for i := range Models {
+ model := Models[i]
+ TypeModelMap[model.ModelType] = append(TypeModelMap[model.ModelType], model)
+ }
}
\ No newline at end of file
diff --git a/domain/openai.go b/domain/openai.go
index 57d6828..4cfb373 100644
--- a/domain/openai.go
+++ b/domain/openai.go
@@ -7,4 +7,13 @@ type OpenAIData struct {
type OpenAIResp struct {
Object string `json:"object"`
Data []*OpenAIData `json:"data"`
+}
+
+// ParseModels 实现ModelResponseParser接口
+func (o *OpenAIResp) ParseModels() []ModelListItem {
+ var models []ModelListItem
+ for _, item := range o.Data {
+ models = append(models, ModelListItem{Model: item.ID})
+ }
+ return models
}
\ No newline at end of file
diff --git a/test/main.go b/test/main.go
new file mode 100644
index 0000000..930dad0
--- /dev/null
+++ b/test/main.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/labstack/echo/v4/middleware"
+
+ "github.com/chaitin/ModelKit/domain"
+ "github.com/chaitin/ModelKit/pkg/log"
+ "github.com/chaitin/ModelKit/usecase"
+ "github.com/labstack/echo/v4"
+)
+
+type ModelKit struct{}
+
+func NewModelKit(
+ echo *echo.Echo,
+ logger *log.Logger,
+ isApmEnabled bool,
+) *ModelKit {
+ m := &ModelKit{}
+
+ // 注册路由
+ g := echo.Group("/api/v1/modelkit")
+ g.GET("/listmodel", m.GetModelList)
+ g.GET("/checkmodel", m.CheckModel)
+
+ return m
+}
+
+func (p *ModelKit) GetModelList(c echo.Context) error {
+ var req domain.ModelListReq
+ if err := c.Bind(&req); err != nil {
+ return c.JSON(http.StatusBadRequest, domain.Response{
+ Success: false,
+ Message: "参数绑定失败: " + err.Error(),
+ })
+ }
+ fmt.Println("list model req:", req)
+
+ resp, err := usecase.ModelList(c.Request().Context(), &req)
+ if err != nil {
+ fmt.Println("err:", err)
+ return c.JSON(http.StatusInternalServerError, domain.Response{
+ Success: false,
+ Message: err.Error(),
+ })
+ }
+
+ return c.JSON(http.StatusOK, domain.Response{
+ Success: true,
+ Message: "获取模型列表成功",
+ Data: resp,
+ })
+}
+
+func (p *ModelKit) CheckModel(c echo.Context) error {
+ var req domain.CheckModelReq
+ if err := c.Bind(&req); err != nil {
+ return c.JSON(http.StatusBadRequest, domain.Response{
+ Success: false,
+ Message: "参数绑定失败: " + err.Error(),
+ })
+ }
+ fmt.Println("check model req:", req)
+
+ resp, _ := usecase.CheckModel(c.Request().Context(), &req)
+
+ // 如果检查过程中有错误,返回错误响应
+ if resp.Error != "" {
+ fmt.Println("resp.Error:", resp.Error)
+ return c.JSON(http.StatusOK, domain.Response{
+ Success: false,
+ Message: resp.Error,
+ Data: resp,
+ })
+ }
+
+ return c.JSON(http.StatusOK, domain.Response{
+ Success: true,
+ Message: "模型检查成功",
+ Data: resp,
+ })
+}
+
+// @title ModelKit API
+// @version 1.0
+// @description ModelKit API server for model management
+// @host localhost:8080
+// @BasePath /
+func main() {
+ echo := echo.New()
+
+ // 添加CORS中间件
+ echo.Use(middleware.CORS())
+
+ NewModelKit(echo, nil, false)
+
+ echo.Start(":8080")
+}
diff --git a/test/model_test.go b/test/model_test.go
deleted file mode 100644
index 0a86e4e..0000000
--- a/test/model_test.go
+++ /dev/null
@@ -1,4 +0,0 @@
-package test
-
-
-
diff --git a/test/ui_example/index.html b/test/ui_example/index.html
new file mode 100644
index 0000000..d10aa4b
--- /dev/null
+++ b/test/ui_example/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ ModelModal Example
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/ui_example/package.json b/test/ui_example/package.json
new file mode 100644
index 0000000..7db6e8b
--- /dev/null
+++ b/test/ui_example/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "modelmodal-example",
+ "version": "1.0.0",
+ "description": "Mock example for ModelModal component",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "type-check": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.11.0",
+ "@emotion/styled": "^11.11.0",
+ "@mui/icons-material": "^6.0.0",
+ "@mui/material": "^6.0.0",
+ "@yokowu/modelkit-ui": "link:../../ui/ModelModal",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
+ "react-hook-form": "^7.48.0",
+ "react-hot-toast": "^2.6.0"
+ },
+ "devDependencies": {
+ "@types/node": "^24.2.1",
+ "@types/react": "^19.1.10",
+ "@types/react-dom": "^19.1.7",
+ "@vitejs/plugin-react": "^4.2.0",
+ "typescript": "^5.3.0",
+ "vite": "^5.0.0"
+ }
+}
diff --git a/test/ui_example/pnpm-lock.yaml b/test/ui_example/pnpm-lock.yaml
new file mode 100644
index 0000000..26d0c39
--- /dev/null
+++ b/test/ui_example/pnpm-lock.yaml
@@ -0,0 +1,1646 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ dependencies:
+ '@emotion/react':
+ specifier: ^11.11.0
+ version: 11.14.0(@types/react@19.1.10)(react@19.1.1)
+ '@emotion/styled':
+ specifier: ^11.11.0
+ version: 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+ '@mui/icons-material':
+ specifier: ^6.0.0
+ version: 6.5.0(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+ '@mui/material':
+ specifier: ^6.0.0
+ version: 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ '@yokowu/modelkit-ui':
+ specifier: link:../../ui/ModelModal
+ version: link:../../ui/ModelModal
+ react:
+ specifier: ^19.1.0
+ version: 19.1.1
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.1(react@19.1.1)
+ react-hook-form:
+ specifier: ^7.48.0
+ version: 7.62.0(react@19.1.1)
+ react-hot-toast:
+ specifier: ^2.6.0
+ version: 2.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ devDependencies:
+ '@types/node':
+ specifier: ^24.2.1
+ version: 24.3.0
+ '@types/react':
+ specifier: ^19.1.10
+ version: 19.1.10
+ '@types/react-dom':
+ specifier: ^19.1.7
+ version: 19.1.7(@types/react@19.1.10)
+ '@vitejs/plugin-react':
+ specifier: ^4.2.0
+ version: 4.7.0(vite@5.4.19(@types/node@24.3.0))
+ typescript:
+ specifier: ^5.3.0
+ version: 5.9.2
+ vite:
+ specifier: ^5.0.0
+ version: 5.4.19(@types/node@24.3.0)
+
+packages:
+
+ '@ampproject/remapping@2.3.0':
+ resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
+ engines: {node: '>=6.0.0'}
+
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.28.0':
+ resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.28.3':
+ resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.28.3':
+ resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.28.3':
+ resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.28.3':
+ resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/parser@7.28.3':
+ resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/runtime@7.28.3':
+ resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.28.3':
+ resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/types@7.28.2':
+ resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@emotion/babel-plugin@11.13.5':
+ resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
+
+ '@emotion/cache@11.14.0':
+ resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
+
+ '@emotion/hash@0.9.2':
+ resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
+
+ '@emotion/is-prop-valid@1.3.1':
+ resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
+ '@emotion/react@11.14.0':
+ resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/serialize@1.3.3':
+ resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
+
+ '@emotion/sheet@1.4.0':
+ resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
+
+ '@emotion/styled@11.14.1':
+ resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==}
+ peerDependencies:
+ '@emotion/react': ^11.0.0-rc.0
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/unitless@0.10.0':
+ resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0':
+ resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@emotion/utils@1.4.2':
+ resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
+
+ '@emotion/weak-memoize@0.4.0':
+ resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
+
+ '@esbuild/aix-ppc64@0.21.5':
+ resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [aix]
+
+ '@esbuild/android-arm64@0.21.5':
+ resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [android]
+
+ '@esbuild/android-arm@0.21.5':
+ resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [android]
+
+ '@esbuild/android-x64@0.21.5':
+ resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [android]
+
+ '@esbuild/darwin-arm64@0.21.5':
+ resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@esbuild/darwin-x64@0.21.5':
+ resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@esbuild/freebsd-x64@0.21.5':
+ resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@esbuild/linux-arm64@0.21.5':
+ resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [linux]
+
+ '@esbuild/linux-arm@0.21.5':
+ resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
+ engines: {node: '>=12'}
+ cpu: [arm]
+ os: [linux]
+
+ '@esbuild/linux-ia32@0.21.5':
+ resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [linux]
+
+ '@esbuild/linux-loong64@0.21.5':
+ resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
+ engines: {node: '>=12'}
+ cpu: [loong64]
+ os: [linux]
+
+ '@esbuild/linux-mips64el@0.21.5':
+ resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
+ engines: {node: '>=12'}
+ cpu: [mips64el]
+ os: [linux]
+
+ '@esbuild/linux-ppc64@0.21.5':
+ resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
+ engines: {node: '>=12'}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@esbuild/linux-riscv64@0.21.5':
+ resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
+ engines: {node: '>=12'}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@esbuild/linux-s390x@0.21.5':
+ resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
+ engines: {node: '>=12'}
+ cpu: [s390x]
+ os: [linux]
+
+ '@esbuild/linux-x64@0.21.5':
+ resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [linux]
+
+ '@esbuild/netbsd-x64@0.21.5':
+ resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [netbsd]
+
+ '@esbuild/openbsd-x64@0.21.5':
+ resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [openbsd]
+
+ '@esbuild/sunos-x64@0.21.5':
+ resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [sunos]
+
+ '@esbuild/win32-arm64@0.21.5':
+ resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
+ engines: {node: '>=12'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@esbuild/win32-ia32@0.21.5':
+ resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
+ engines: {node: '>=12'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@esbuild/win32-x64@0.21.5':
+ resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
+ engines: {node: '>=12'}
+ cpu: [x64]
+ os: [win32]
+
+ '@jridgewell/gen-mapping@0.3.13':
+ resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
+
+ '@jridgewell/resolve-uri@3.1.2':
+ resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
+ engines: {node: '>=6.0.0'}
+
+ '@jridgewell/sourcemap-codec@1.5.5':
+ resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==}
+
+ '@mui/core-downloads-tracker@6.5.0':
+ resolution: {integrity: sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==}
+
+ '@mui/icons-material@6.5.0':
+ resolution: {integrity: sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@mui/material': ^6.5.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/material@6.5.0':
+ resolution: {integrity: sha512-yjvtXoFcrPLGtgKRxFaH6OQPtcLPhkloC0BML6rBG5UeldR0nPULR/2E2BfXdo5JNV7j7lOzrrLX2Qf/iSidow==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@mui/material-pigment-css': ^6.5.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@mui/material-pigment-css':
+ optional: true
+ '@types/react':
+ optional: true
+
+ '@mui/private-theming@6.4.9':
+ resolution: {integrity: sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/styled-engine@6.5.0':
+ resolution: {integrity: sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.4.1
+ '@emotion/styled': ^11.3.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+
+ '@mui/system@6.5.0':
+ resolution: {integrity: sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@types/react':
+ optional: true
+
+ '@mui/types@7.2.24':
+ resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@mui/utils@6.4.9':
+ resolution: {integrity: sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@popperjs/core@2.11.8':
+ resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
+
+ '@rolldown/pluginutils@1.0.0-beta.27':
+ resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==}
+
+ '@rollup/rollup-android-arm-eabi@4.46.2':
+ resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==}
+ cpu: [arm]
+ os: [android]
+
+ '@rollup/rollup-android-arm64@4.46.2':
+ resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==}
+ cpu: [arm64]
+ os: [android]
+
+ '@rollup/rollup-darwin-arm64@4.46.2':
+ resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rollup/rollup-darwin-x64@4.46.2':
+ resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rollup/rollup-freebsd-arm64@4.46.2':
+ resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==}
+ cpu: [arm64]
+ os: [freebsd]
+
+ '@rollup/rollup-freebsd-x64@4.46.2':
+ resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.46.2':
+ resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm-musleabihf@4.46.2':
+ resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
+ cpu: [arm]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-gnu@4.46.2':
+ resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-arm64-musl@4.46.2':
+ resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.46.2':
+ resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
+ cpu: [loong64]
+ os: [linux]
+
+ '@rollup/rollup-linux-ppc64-gnu@4.46.2':
+ resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-gnu@4.46.2':
+ resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-riscv64-musl@4.46.2':
+ resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.46.2':
+ resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-gnu@4.46.2':
+ resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-linux-x64-musl@4.46.2':
+ resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
+ cpu: [x64]
+ os: [linux]
+
+ '@rollup/rollup-win32-arm64-msvc@4.46.2':
+ resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rollup/rollup-win32-ia32-msvc@4.46.2':
+ resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@rollup/rollup-win32-x64-msvc@4.46.2':
+ resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==}
+ cpu: [x64]
+ os: [win32]
+
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.28.0':
+ resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==}
+
+ '@types/estree@1.0.8':
+ resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
+
+ '@types/node@24.3.0':
+ resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==}
+
+ '@types/parse-json@4.0.2':
+ resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
+
+ '@types/prop-types@15.7.15':
+ resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
+
+ '@types/react-dom@19.1.7':
+ resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==}
+ peerDependencies:
+ '@types/react': ^19.0.0
+
+ '@types/react-transition-group@4.4.12':
+ resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==}
+ peerDependencies:
+ '@types/react': '*'
+
+ '@types/react@19.1.10':
+ resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==}
+
+ '@vitejs/plugin-react@4.7.0':
+ resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+
+ babel-plugin-macros@3.1.0:
+ resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
+ engines: {node: '>=10', npm: '>=6'}
+
+ browserslist@4.25.2:
+ resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
+ caniuse-lite@1.0.30001735:
+ resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==}
+
+ clsx@2.1.1:
+ resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
+ engines: {node: '>=6'}
+
+ convert-source-map@1.9.0:
+ resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
+ cosmiconfig@7.1.0:
+ resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
+ engines: {node: '>=10'}
+
+ csstype@3.1.3:
+ resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
+
+ debug@4.4.1:
+ resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
+ dom-helpers@5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+
+ electron-to-chromium@1.5.203:
+ resolution: {integrity: sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g==}
+
+ error-ex@1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+
+ esbuild@0.21.5:
+ resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
+ engines: {node: '>=12'}
+ hasBin: true
+
+ escalade@3.2.0:
+ resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
+ engines: {node: '>=6'}
+
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ find-root@1.1.0:
+ resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
+
+ fsevents@2.3.3:
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
+ goober@2.1.16:
+ resolution: {integrity: sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==}
+ peerDependencies:
+ csstype: ^3.0.10
+
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ hoist-non-react-statics@3.3.2:
+ resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
+ json5@2.2.3:
+ resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
+ engines: {node: '>=6'}
+ hasBin: true
+
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
+ nanoid@3.3.11:
+ resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
+ object-assign@4.1.1:
+ resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
+ engines: {node: '>=0.10.0'}
+
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
+ picocolors@1.1.1:
+ resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
+
+ postcss@8.5.6:
+ resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
+ engines: {node: ^10 || ^12 || >=14}
+
+ prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
+ react-dom@19.1.1:
+ resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==}
+ peerDependencies:
+ react: ^19.1.1
+
+ react-hook-form@7.62.0:
+ resolution: {integrity: sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==}
+ engines: {node: '>=18.0.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || ^18 || ^19
+
+ react-hot-toast@2.6.0:
+ resolution: {integrity: sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: '>=16'
+ react-dom: '>=16'
+
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react-is@19.1.1:
+ resolution: {integrity: sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==}
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react-transition-group@4.4.5:
+ resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
+ peerDependencies:
+ react: '>=16.6.0'
+ react-dom: '>=16.6.0'
+
+ react@19.1.1:
+ resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
+ engines: {node: '>=0.10.0'}
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
+ resolve@1.22.10:
+ resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
+ rollup@4.46.2:
+ resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
+ source-map-js@1.2.1:
+ resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
+ engines: {node: '>=0.10.0'}
+
+ source-map@0.5.7:
+ resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+ engines: {node: '>=0.10.0'}
+
+ stylis@4.2.0:
+ resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
+ typescript@5.9.2:
+ resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
+ engines: {node: '>=14.17'}
+ hasBin: true
+
+ undici-types@7.10.0:
+ resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==}
+
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
+ vite@5.4.19:
+ resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^18.0.0 || >=20.0.0
+ less: '*'
+ lightningcss: ^1.21.0
+ sass: '*'
+ sass-embedded: '*'
+ stylus: '*'
+ sugarss: '*'
+ terser: ^5.4.0
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yaml@1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+
+snapshots:
+
+ '@ampproject/remapping@2.3.0':
+ dependencies:
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.28.0': {}
+
+ '@babel/core@7.28.3':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3)
+ '@babel/helpers': 7.28.3
+ '@babel/parser': 7.28.3
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.28.3
+ '@babel/types': 7.28.2
+ convert-source-map: 2.0.0
+ debug: 4.4.1
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.28.3':
+ dependencies:
+ '@babel/parser': 7.28.3
+ '@babel/types': 7.28.2
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.30
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.28.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.25.2
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-globals@7.28.0': {}
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.28.3
+ '@babel/types': 7.28.2
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)':
+ dependencies:
+ '@babel/core': 7.28.3
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.28.3
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
+ '@babel/helper-string-parser@7.27.1': {}
+
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.28.3':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.2
+
+ '@babel/parser@7.28.3':
+ dependencies:
+ '@babel/types': 7.28.2
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.3)':
+ dependencies:
+ '@babel/core': 7.28.3
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.3)':
+ dependencies:
+ '@babel/core': 7.28.3
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/runtime@7.28.3': {}
+
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.28.3
+ '@babel/types': 7.28.2
+
+ '@babel/traverse@7.28.3':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.28.3
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.28.3
+ '@babel/template': 7.27.2
+ '@babel/types': 7.28.2
+ debug: 4.4.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/types@7.28.2':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
+ '@emotion/babel-plugin@11.13.5':
+ dependencies:
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/runtime': 7.28.3
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/serialize': 1.3.3
+ babel-plugin-macros: 3.1.0
+ convert-source-map: 1.9.0
+ escape-string-regexp: 4.0.0
+ find-root: 1.1.0
+ source-map: 0.5.7
+ stylis: 4.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/cache@11.14.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+ '@emotion/sheet': 1.4.0
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ stylis: 4.2.0
+
+ '@emotion/hash@0.9.2': {}
+
+ '@emotion/is-prop-valid@1.3.1':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
+ '@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.1)
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ hoist-non-react-statics: 3.3.2
+ react: 19.1.1
+ optionalDependencies:
+ '@types/react': 19.1.10
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/serialize@1.3.3':
+ dependencies:
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/unitless': 0.10.0
+ '@emotion/utils': 1.4.2
+ csstype: 3.1.3
+
+ '@emotion/sheet@1.4.0': {}
+
+ '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/is-prop-valid': 1.3.1
+ '@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.1.1)
+ '@emotion/utils': 1.4.2
+ react: 19.1.1
+ optionalDependencies:
+ '@types/react': 19.1.10
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/unitless@0.10.0': {}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.1.1)':
+ dependencies:
+ react: 19.1.1
+
+ '@emotion/utils@1.4.2': {}
+
+ '@emotion/weak-memoize@0.4.0': {}
+
+ '@esbuild/aix-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/android-arm@0.21.5':
+ optional: true
+
+ '@esbuild/android-x64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/darwin-x64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/freebsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-arm@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/linux-loong64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-mips64el@0.21.5':
+ optional: true
+
+ '@esbuild/linux-ppc64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-riscv64@0.21.5':
+ optional: true
+
+ '@esbuild/linux-s390x@0.21.5':
+ optional: true
+
+ '@esbuild/linux-x64@0.21.5':
+ optional: true
+
+ '@esbuild/netbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/openbsd-x64@0.21.5':
+ optional: true
+
+ '@esbuild/sunos-x64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-arm64@0.21.5':
+ optional: true
+
+ '@esbuild/win32-ia32@0.21.5':
+ optional: true
+
+ '@esbuild/win32-x64@0.21.5':
+ optional: true
+
+ '@jridgewell/gen-mapping@0.3.13':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@jridgewell/trace-mapping': 0.3.30
+
+ '@jridgewell/resolve-uri@3.1.2': {}
+
+ '@jridgewell/sourcemap-codec@1.5.5': {}
+
+ '@jridgewell/trace-mapping@0.3.30':
+ dependencies:
+ '@jridgewell/resolve-uri': 3.1.2
+ '@jridgewell/sourcemap-codec': 1.5.5
+
+ '@mui/core-downloads-tracker@6.5.0': {}
+
+ '@mui/icons-material@6.5.0(@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@mui/material': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ react: 19.1.1
+ optionalDependencies:
+ '@types/react': 19.1.10
+
+ '@mui/material@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@mui/core-downloads-tracker': 6.5.0
+ '@mui/system': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+ '@mui/types': 7.2.24(@types/react@19.1.10)
+ '@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
+ '@popperjs/core': 2.11.8
+ '@types/react-transition-group': 4.4.12(@types/react@19.1.10)
+ clsx: 2.1.1
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+ react-is: 19.1.1
+ react-transition-group: 4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+ '@types/react': 19.1.10
+
+ '@mui/private-theming@6.4.9(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
+ prop-types: 15.8.1
+ react: 19.1.1
+ optionalDependencies:
+ '@types/react': 19.1.10
+
+ '@mui/styled-engine@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/sheet': 1.4.0
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.1
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+
+ '@mui/system@6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@mui/private-theming': 6.4.9(@types/react@19.1.10)(react@19.1.1)
+ '@mui/styled-engine': 6.5.0(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1))(react@19.1.1)
+ '@mui/types': 7.2.24(@types/react@19.1.10)
+ '@mui/utils': 6.4.9(@types/react@19.1.10)(react@19.1.1)
+ clsx: 2.1.1
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.1.1
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.1.10)(react@19.1.1)
+ '@emotion/styled': 11.14.1(@emotion/react@11.14.0(@types/react@19.1.10)(react@19.1.1))(@types/react@19.1.10)(react@19.1.1)
+ '@types/react': 19.1.10
+
+ '@mui/types@7.2.24(@types/react@19.1.10)':
+ optionalDependencies:
+ '@types/react': 19.1.10
+
+ '@mui/utils@6.4.9(@types/react@19.1.10)(react@19.1.1)':
+ dependencies:
+ '@babel/runtime': 7.28.3
+ '@mui/types': 7.2.24(@types/react@19.1.10)
+ '@types/prop-types': 15.7.15
+ clsx: 2.1.1
+ prop-types: 15.8.1
+ react: 19.1.1
+ react-is: 19.1.1
+ optionalDependencies:
+ '@types/react': 19.1.10
+
+ '@popperjs/core@2.11.8': {}
+
+ '@rolldown/pluginutils@1.0.0-beta.27': {}
+
+ '@rollup/rollup-android-arm-eabi@4.46.2':
+ optional: true
+
+ '@rollup/rollup-android-arm64@4.46.2':
+ optional: true
+
+ '@rollup/rollup-darwin-arm64@4.46.2':
+ optional: true
+
+ '@rollup/rollup-darwin-x64@4.46.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-arm64@4.46.2':
+ optional: true
+
+ '@rollup/rollup-freebsd-x64@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-gnueabihf@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm-musleabihf@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-arm64-musl@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-loongarch64-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-ppc64-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-riscv64-musl@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-s390x-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-gnu@4.46.2':
+ optional: true
+
+ '@rollup/rollup-linux-x64-musl@4.46.2':
+ optional: true
+
+ '@rollup/rollup-win32-arm64-msvc@4.46.2':
+ optional: true
+
+ '@rollup/rollup-win32-ia32-msvc@4.46.2':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.46.2':
+ optional: true
+
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.28.3
+ '@babel/types': 7.28.2
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.28.0
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.28.2
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.28.3
+ '@babel/types': 7.28.2
+
+ '@types/babel__traverse@7.28.0':
+ dependencies:
+ '@babel/types': 7.28.2
+
+ '@types/estree@1.0.8': {}
+
+ '@types/node@24.3.0':
+ dependencies:
+ undici-types: 7.10.0
+
+ '@types/parse-json@4.0.2': {}
+
+ '@types/prop-types@15.7.15': {}
+
+ '@types/react-dom@19.1.7(@types/react@19.1.10)':
+ dependencies:
+ '@types/react': 19.1.10
+
+ '@types/react-transition-group@4.4.12(@types/react@19.1.10)':
+ dependencies:
+ '@types/react': 19.1.10
+
+ '@types/react@19.1.10':
+ dependencies:
+ csstype: 3.1.3
+
+ '@vitejs/plugin-react@4.7.0(vite@5.4.19(@types/node@24.3.0))':
+ dependencies:
+ '@babel/core': 7.28.3
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3)
+ '@rolldown/pluginutils': 1.0.0-beta.27
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 5.4.19(@types/node@24.3.0)
+ transitivePeerDependencies:
+ - supports-color
+
+ babel-plugin-macros@3.1.0:
+ dependencies:
+ '@babel/runtime': 7.28.3
+ cosmiconfig: 7.1.0
+ resolve: 1.22.10
+
+ browserslist@4.25.2:
+ dependencies:
+ caniuse-lite: 1.0.30001735
+ electron-to-chromium: 1.5.203
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.3(browserslist@4.25.2)
+
+ callsites@3.1.0: {}
+
+ caniuse-lite@1.0.30001735: {}
+
+ clsx@2.1.1: {}
+
+ convert-source-map@1.9.0: {}
+
+ convert-source-map@2.0.0: {}
+
+ cosmiconfig@7.1.0:
+ dependencies:
+ '@types/parse-json': 4.0.2
+ import-fresh: 3.3.1
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+
+ csstype@3.1.3: {}
+
+ debug@4.4.1:
+ dependencies:
+ ms: 2.1.3
+
+ dom-helpers@5.2.1:
+ dependencies:
+ '@babel/runtime': 7.28.3
+ csstype: 3.1.3
+
+ electron-to-chromium@1.5.203: {}
+
+ error-ex@1.3.2:
+ dependencies:
+ is-arrayish: 0.2.1
+
+ esbuild@0.21.5:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.21.5
+ '@esbuild/android-arm': 0.21.5
+ '@esbuild/android-arm64': 0.21.5
+ '@esbuild/android-x64': 0.21.5
+ '@esbuild/darwin-arm64': 0.21.5
+ '@esbuild/darwin-x64': 0.21.5
+ '@esbuild/freebsd-arm64': 0.21.5
+ '@esbuild/freebsd-x64': 0.21.5
+ '@esbuild/linux-arm': 0.21.5
+ '@esbuild/linux-arm64': 0.21.5
+ '@esbuild/linux-ia32': 0.21.5
+ '@esbuild/linux-loong64': 0.21.5
+ '@esbuild/linux-mips64el': 0.21.5
+ '@esbuild/linux-ppc64': 0.21.5
+ '@esbuild/linux-riscv64': 0.21.5
+ '@esbuild/linux-s390x': 0.21.5
+ '@esbuild/linux-x64': 0.21.5
+ '@esbuild/netbsd-x64': 0.21.5
+ '@esbuild/openbsd-x64': 0.21.5
+ '@esbuild/sunos-x64': 0.21.5
+ '@esbuild/win32-arm64': 0.21.5
+ '@esbuild/win32-ia32': 0.21.5
+ '@esbuild/win32-x64': 0.21.5
+
+ escalade@3.2.0: {}
+
+ escape-string-regexp@4.0.0: {}
+
+ find-root@1.1.0: {}
+
+ fsevents@2.3.3:
+ optional: true
+
+ function-bind@1.1.2: {}
+
+ gensync@1.0.0-beta.2: {}
+
+ goober@2.1.16(csstype@3.1.3):
+ dependencies:
+ csstype: 3.1.3
+
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ hoist-non-react-statics@3.3.2:
+ dependencies:
+ react-is: 16.13.1
+
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
+ is-arrayish@0.2.1: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
+ js-tokens@4.0.0: {}
+
+ jsesc@3.1.0: {}
+
+ json-parse-even-better-errors@2.3.1: {}
+
+ json5@2.2.3: {}
+
+ lines-and-columns@1.2.4: {}
+
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
+ ms@2.1.3: {}
+
+ nanoid@3.3.11: {}
+
+ node-releases@2.0.19: {}
+
+ object-assign@4.1.1: {}
+
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
+ path-parse@1.0.7: {}
+
+ path-type@4.0.0: {}
+
+ picocolors@1.1.1: {}
+
+ postcss@8.5.6:
+ dependencies:
+ nanoid: 3.3.11
+ picocolors: 1.1.1
+ source-map-js: 1.2.1
+
+ prop-types@15.8.1:
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ react-dom@19.1.1(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+ scheduler: 0.26.0
+
+ react-hook-form@7.62.0(react@19.1.1):
+ dependencies:
+ react: 19.1.1
+
+ react-hot-toast@2.6.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ csstype: 3.1.3
+ goober: 2.1.16(csstype@3.1.3)
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+
+ react-is@16.13.1: {}
+
+ react-is@19.1.1: {}
+
+ react-refresh@0.17.0: {}
+
+ react-transition-group@4.4.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1):
+ dependencies:
+ '@babel/runtime': 7.28.3
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 19.1.1
+ react-dom: 19.1.1(react@19.1.1)
+
+ react@19.1.1: {}
+
+ resolve-from@4.0.0: {}
+
+ resolve@1.22.10:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
+ rollup@4.46.2:
+ dependencies:
+ '@types/estree': 1.0.8
+ optionalDependencies:
+ '@rollup/rollup-android-arm-eabi': 4.46.2
+ '@rollup/rollup-android-arm64': 4.46.2
+ '@rollup/rollup-darwin-arm64': 4.46.2
+ '@rollup/rollup-darwin-x64': 4.46.2
+ '@rollup/rollup-freebsd-arm64': 4.46.2
+ '@rollup/rollup-freebsd-x64': 4.46.2
+ '@rollup/rollup-linux-arm-gnueabihf': 4.46.2
+ '@rollup/rollup-linux-arm-musleabihf': 4.46.2
+ '@rollup/rollup-linux-arm64-gnu': 4.46.2
+ '@rollup/rollup-linux-arm64-musl': 4.46.2
+ '@rollup/rollup-linux-loongarch64-gnu': 4.46.2
+ '@rollup/rollup-linux-ppc64-gnu': 4.46.2
+ '@rollup/rollup-linux-riscv64-gnu': 4.46.2
+ '@rollup/rollup-linux-riscv64-musl': 4.46.2
+ '@rollup/rollup-linux-s390x-gnu': 4.46.2
+ '@rollup/rollup-linux-x64-gnu': 4.46.2
+ '@rollup/rollup-linux-x64-musl': 4.46.2
+ '@rollup/rollup-win32-arm64-msvc': 4.46.2
+ '@rollup/rollup-win32-ia32-msvc': 4.46.2
+ '@rollup/rollup-win32-x64-msvc': 4.46.2
+ fsevents: 2.3.3
+
+ scheduler@0.26.0: {}
+
+ semver@6.3.1: {}
+
+ source-map-js@1.2.1: {}
+
+ source-map@0.5.7: {}
+
+ stylis@4.2.0: {}
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
+ typescript@5.9.2: {}
+
+ undici-types@7.10.0: {}
+
+ update-browserslist-db@1.1.3(browserslist@4.25.2):
+ dependencies:
+ browserslist: 4.25.2
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
+ vite@5.4.19(@types/node@24.3.0):
+ dependencies:
+ esbuild: 0.21.5
+ postcss: 8.5.6
+ rollup: 4.46.2
+ optionalDependencies:
+ '@types/node': 24.3.0
+ fsevents: 2.3.3
+
+ yallist@3.1.1: {}
+
+ yaml@1.10.2: {}
diff --git a/test/ui_example/src/App.tsx b/test/ui_example/src/App.tsx
new file mode 100644
index 0000000..733b211
--- /dev/null
+++ b/test/ui_example/src/App.tsx
@@ -0,0 +1,185 @@
+import React, { useState } from 'react';
+import {
+ Box,
+ Button,
+ Container,
+ Typography,
+ Paper,
+ Stack,
+ FormControl,
+ InputLabel,
+ Select,
+ MenuItem,
+ SelectChangeEvent,
+} from '@mui/material';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
+import CssBaseline from '@mui/material/CssBaseline';
+import { Model} from '@yokowu/modelkit-ui';
+import { localModelService } from './localService';
+import { ModelModal } from '@yokowu/modelkit-ui';
+import toast, { Toaster } from 'react-hot-toast';
+
+// 创建Material-UI主题
+const theme = createTheme({
+ palette: {
+ mode: 'light',
+ primary: {
+ main: '#1976d2',
+ },
+ secondary: {
+ main: '#dc004e',
+ },
+ },
+});
+
+function App() {
+ const [modalOpen, setModalOpen] = useState(false);
+ const [selectedType, setSelectedType] = useState('llm');
+ const [editingModel, setEditingModel] = useState(null);
+
+ // 使用react-hot-toast的消息组件
+ const messageComponent = {
+ error: (content: string | Error) => {
+ const message = content instanceof Error ? content.message : String(content);
+ return toast.error(message);
+ },
+ success: (content: string) => toast.success(String(content)),
+ info: (content: string) => toast(String(content)),
+ warning: (content: string) => toast(String(content), { icon: '⚠️' }),
+ };
+
+ const handleOpenEditModal = () => {
+ // 模拟编辑一个现有模型
+ const mockModel: Model = {
+ id: 'edit-example',
+ model_name: 'gpt-4',
+ show_name: 'GPT-4 示例',
+ provider: 'OpenAI' as any,
+ model_type: 'llm',
+ base_url: 'https://api.openai.com/v1',
+ api_key: 'sk-example-key',
+ api_version: '2023-05-15',
+ status: 'active' as any,
+ is_active: true,
+ created_at: Date.now(),
+ updated_at: Date.now(),
+ };
+ setEditingModel(mockModel);
+ setModalOpen(true);
+ };
+
+ const handleCloseModal = () => {
+ setModalOpen(false);
+ setEditingModel(null);
+ };
+
+ const handleRefresh = () => {
+ console.log('刷新模型列表');
+ };
+
+ const handleTypeChange = (event: SelectChangeEvent) => {
+ setSelectedType(event.target.value);
+ };
+
+
+
+ return (
+ <>
+
+
+
+
+
+
+ ModelModal 示例程序
+
+
+
+ 这是一个用于测试 ModelModal 组件的示例应用程序
+
+
+
+
+ 模型类型
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 功能说明:
+
+
+ 支持多种模型类型选择
+ 支持添加和编辑模型配置
+ 集成多个AI服务提供商
+ 实时模型验证和测试
+ 响应式设计,支持移动端
+
+
+
+
+ {/* SimpleModelModal 组件 */}
+
+
+
+
+
+ >
+ );
+}
+
+export default App;
\ No newline at end of file
diff --git a/test/ui_example/src/index.css b/test/ui_example/src/index.css
new file mode 100644
index 0000000..59ed942
--- /dev/null
+++ b/test/ui_example/src/index.css
@@ -0,0 +1,22 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
+
+#root {
+ width: 100vw;
+ height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #f5f5f5;
+}
\ No newline at end of file
diff --git a/test/ui_example/src/localService.ts b/test/ui_example/src/localService.ts
new file mode 100644
index 0000000..d410a75
--- /dev/null
+++ b/test/ui_example/src/localService.ts
@@ -0,0 +1,148 @@
+import {
+ Model,
+ ModelService,
+ CreateModelReq,
+ ListModelReq,
+ CheckModelReq,
+ UpdateModelReq,
+ ModelListItem,
+} from '@yokowu/modelkit-ui';
+
+
+// 本地Go服务的基础URL
+const BASE_URL = 'http://localhost:8080/api/v1/modelkit';
+
+// API响应格式
+interface ApiResponse {
+ success: boolean;
+ message: string;
+ data?: T;
+}
+
+// 模型列表响应
+interface ModelListResponse {
+ models: ModelListItem[];
+}
+
+// 模型检查响应
+interface CheckModelResponse {
+ model: Model;
+ error?: string;
+}
+
+export class LocalModelService implements ModelService {
+ private async request(url: string, options: RequestInit = {}): Promise {
+ const response = await fetch(`${BASE_URL}${url}`, {
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers,
+ },
+ ...options,
+ });
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const result: ApiResponse = await response.json();
+
+ if (!result.success) {
+ throw new Error(result.message || 'API request failed');
+ }
+
+ return result.data as T;
+ }
+
+ async createModel(data: CreateModelReq): Promise<{ model: Model }> {
+ // 转换为Go服务期望的格式
+ const requestData = {
+ model_name: data.model_name,
+ show_name: data.show_name,
+ provider: data.provider,
+ model_type: data.model_type,
+ base_url: data.base_url,
+ api_key: data.api_key,
+ api_version: data.api_version,
+ api_header: data.api_header,
+ param: data.param,
+ };
+
+ const result = await this.request<{ model: Model }>('/models', {
+ method: 'POST',
+ body: JSON.stringify(requestData),
+ });
+
+ return result;
+ }
+
+ async listModel(data: ListModelReq): Promise<{ models: ModelListItem[] }> {
+ try {
+ const queryParams = new URLSearchParams();
+ if (data.provider) queryParams.append('provider', data.provider);
+ if (data.model_type) queryParams.append('model_type', data.model_type);
+ if (data.base_url) queryParams.append('base_url', data.base_url);
+ if (data.api_key) queryParams.append('api_key', data.api_key);
+ if (data.api_header) queryParams.append('api_header', data.api_header);
+
+ const url = `/listmodel${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
+ const response = await this.request(url, {
+ method: 'GET',
+ });
+ return { models: response.models };
+ } catch (error) {
+ console.error('Failed to list models:', error);
+ throw error;
+ }
+ }
+
+ async checkModel(data: CheckModelReq): Promise<{ model: Model; error?: string }> {
+ try {
+ const queryParams = new URLSearchParams();
+ console.log('checkModel data:', data);
+ if (data.provider) queryParams.append('provider', data.provider);
+ if (data.model_name) queryParams.append('model_name', data.model_name);
+ if (data.base_url) queryParams.append('base_url', data.base_url);
+ if (data.api_key) queryParams.append('api_key', data.api_key);
+ if (data.api_header) queryParams.append('api_header', data.api_header);
+ if (data.model_type) queryParams.append('model_type', data.model_type);
+ const url = `/checkmodel${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
+ const response = await this.request(url, {
+ method: 'GET',
+ });
+
+ if (response.error) {
+ throw new Error(response.error);
+ }
+
+ return { model: response.model };
+ } catch (error) {
+ console.error('Failed to list models:', error);
+ throw error;
+ }
+ }
+
+ async updateModel(data: UpdateModelReq): Promise<{ model: Model }> {
+ const requestData = {
+ id: data.id,
+ model_name: data.model_name,
+ show_name: data.show_name,
+ provider: data.provider,
+ base_url: data.base_url,
+ api_key: data.api_key,
+ api_version: data.api_version,
+ api_header: data.api_header,
+ param: data.param,
+ status: data.status,
+ };
+
+ const result = await this.request<{ model: Model }>(`/models/${data.id}`, {
+ method: 'PUT',
+ body: JSON.stringify(requestData),
+ });
+
+ return result;
+ }
+}
+
+// 导出服务实例
+export const localModelService = new LocalModelService();
\ No newline at end of file
diff --git a/test/ui_example/src/main.tsx b/test/ui_example/src/main.tsx
new file mode 100644
index 0000000..24a16b6
--- /dev/null
+++ b/test/ui_example/src/main.tsx
@@ -0,0 +1,10 @@
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import App from './App';
+import './index.css';
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+
+
+ ,
+);
\ No newline at end of file
diff --git a/test/ui_example/tsconfig.json b/test/ui_example/tsconfig.json
new file mode 100644
index 0000000..ab4edaa
--- /dev/null
+++ b/test/ui_example/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "useDefineForClassFields": true,
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src"]
+}
\ No newline at end of file
diff --git a/test/ui_example/tsconfig.node.json b/test/ui_example/tsconfig.node.json
new file mode 100644
index 0000000..6cbe316
--- /dev/null
+++ b/test/ui_example/tsconfig.node.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "noEmit": true
+ },
+ "include": ["vite.config.ts"],
+ "exclude": ["node_modules"]
+}
\ No newline at end of file
diff --git a/test/ui_example/vite.config.ts b/test/ui_example/vite.config.ts
new file mode 100644
index 0000000..964a592
--- /dev/null
+++ b/test/ui_example/vite.config.ts
@@ -0,0 +1,19 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import path from 'path';
+
+export default defineConfig({
+ plugins: [react()],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, '../ui/ModelModal/src'),
+ },
+ },
+ server: {
+ host: '0.0.0.0',
+ port: 3301,
+ },
+ define: {
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
+ },
+});
\ No newline at end of file
diff --git a/ui/ModelModal/src/ModelModal.tsx b/ui/ModelModal/src/ModelModal.tsx
index 476454d..4a296df 100644
--- a/ui/ModelModal/src/ModelModal.tsx
+++ b/ui/ModelModal/src/ModelModal.tsx
@@ -335,7 +335,7 @@ export const ModelModal: React.FC = ({
disabled: !success && providerBrand !== 'Other',
}}
>
-
+
= ({
bgcolor: 'background.paper2',
borderRadius: '10px',
p: 1,
+ height: '100%',
+ display: 'flex',
+ flexDirection: 'column',
}}
>
模型供应商
- {Object.values(providers)
- .filter((it) => {
- // 当model_type为chat或llm时显示所有供应商
- if (model_type === 'chat' || model_type === 'llm' || model_type === 'code' || model_type === 'coder') {
- return true;
- }
- // 其他情况只显示百智云和其它
- return it.label === 'BaiZhiCloud' || it.label === 'Other';
- })
- .map((it) => (
- {
- if (data && data.provider === it.label) {
- resetCurData(data);
- } else {
- setModelUserList([]);
- setError('');
- setModelLoading(false);
- setSuccess(false);
- reset({
- provider: it.label as keyof typeof DEFAULT_MODEL_PROVIDERS,
- base_url:
- it.label === 'AzureOpenAI' ? '' : it.defaultBaseUrl,
- model_name: '',
- api_version: '',
- api_key: '',
- api_header_key: '',
- api_header_value: '',
- show_name: '',
- // 重置高级设置
- context_window_size: 64000,
- max_output_tokens: 8192,
- enable_r1_params: false,
- support_image: false,
- support_compute: false,
- support_prompt_caching: false,
- });
- }
- }}
- >
-
- {it.cn || it.label || '其他'}
+
+
+ {Object.values(providers)
+ .filter((it) => {
+ // 当model_type为chat或llm时显示所有供应商
+ if (model_type === 'chat' || model_type === 'llm' || model_type === 'code' || model_type === 'coder') {
+ return true;
+ }
+ // 其他情况只显示百智云和其它
+ return it.label === 'BaiZhiCloud' || it.label === 'Other';
+ })
+ .map((it) => (
+ {
+ if (data && data.provider === it.label) {
+ resetCurData(data);
+ } else {
+ setModelUserList([]);
+ setError('');
+ setModelLoading(false);
+ setSuccess(false);
+ reset({
+ provider: it.label as keyof typeof DEFAULT_MODEL_PROVIDERS,
+ base_url:
+ it.label === 'AzureOpenAI' ? '' : it.defaultBaseUrl,
+ model_name: '',
+ api_version: '',
+ api_key: '',
+ api_header_key: '',
+ api_header_value: '',
+ show_name: '',
+ // 重置高级设置
+ context_window_size: 64000,
+ max_output_tokens: 8192,
+ enable_r1_params: false,
+ support_image: false,
+ support_compute: false,
+ support_prompt_caching: false,
+ });
+ }
+ }}
+ >
+
+ {it.cn || it.label || '其他'}
+
+ ))}
- ))}
+
-
+
API 地址{' '}
diff --git a/ui/ModelModal/src/constants/providers.ts b/ui/ModelModal/src/constants/providers.ts
index ea721d8..d58e245 100644
--- a/ui/ModelModal/src/constants/providers.ts
+++ b/ui/ModelModal/src/constants/providers.ts
@@ -19,7 +19,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://open.bigmodel.cn/usercenter/apikeys',
+ modelDocumentUrl: 'https://docs.bigmodel.cn/',
defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4',
},
DeepSeek: {
@@ -29,7 +29,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://platform.deepseek.com/api_keys',
+ modelDocumentUrl: 'https://platform.deepseek.com/api-docs/',
defaultBaseUrl: 'https://api.deepseek.com/v1',
},
Hunyuan: {
@@ -39,7 +39,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://console.cloud.tencent.com/hunyuan/start',
+ modelDocumentUrl: 'https://cloud.tencent.com/document/product/1729/111007',
defaultBaseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',
},
BaiLian: {
@@ -49,7 +49,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://bailian.console.aliyun.com/?tab=model#/api-key',
+ modelDocumentUrl: 'https://help.aliyun.com/zh/model-studio/getting-started/',
defaultBaseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
},
Volcengine: {
@@ -59,7 +59,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey',
+ modelDocumentUrl: 'https://www.volcengine.com/docs/82379/1182403',
defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3',
},
OpenAI: {
@@ -69,7 +69,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://platform.openai.com/api-keys',
+ modelDocumentUrl: 'https://platform.openai.com/docs',
defaultBaseUrl: 'https://api.openai.com/v1',
},
Ollama: {
@@ -79,7 +79,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: true,
secretRequired: false,
customHeader: true,
- modelDocumentUrl: '',
+ modelDocumentUrl: 'https://github.com/ollama/ollama/tree/main/docs',
defaultBaseUrl: 'http://127.0.0.1:11434',
},
SiliconFlow: {
@@ -89,7 +89,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://cloud.siliconflow.cn/account/ak',
+ modelDocumentUrl: 'https://docs.siliconflow.cn/',
defaultBaseUrl: 'https://api.siliconflow.cn/v1',
},
Moonshot: {
@@ -99,7 +99,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: false,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://platform.moonshot.cn/console/api-keys',
+ modelDocumentUrl: 'https://platform.moonshot.cn/docs/',
defaultBaseUrl: 'https://api.moonshot.cn/v1',
},
AzureOpenAI: {
@@ -109,7 +109,7 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
urlWrite: true,
secretRequired: true,
customHeader: false,
- modelDocumentUrl: 'https://portal.azure.com/#view/Microsoft_Azure_ProjectOxford/CognitiveServicesHub/~/OpenAI',
+ modelDocumentUrl: 'https://learn.microsoft.com/en-us/azure/ai-services/openai/',
defaultBaseUrl: 'https://.openai.azure.com',
},
Gemini: {
@@ -122,6 +122,377 @@ export const DEFAULT_MODEL_PROVIDERS: ModelProviderMap = {
modelDocumentUrl: 'https://ai.google.dev/gemini-api/docs',
defaultBaseUrl: 'https://generativelanguage.googleapis.com',
},
+ Qiniu: {
+ label: 'Qiniu',
+ cn: '七牛云',
+ icon: 'icon-qiniu',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://developer.qiniu.com/aitokenapi',
+ defaultBaseUrl: 'https://api.qnaigc.com/v1',
+ },
+ // NewAPI: {
+ // label: 'NewAPI',
+ // cn: 'New API',
+ // icon: 'icon-newapi',
+ // urlWrite: true,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'http://localhost:3000/v1',
+ // },
+ // LMStudio: {
+ // label: 'LMStudio',
+ // cn: 'LM Studio',
+ // icon: 'icon-lmstudio',
+ // urlWrite: true,
+ // secretRequired: false,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'http://localhost:1234/v1',
+ // },
+ // Anthropic: {
+ // label: 'Anthropic',
+ // cn: 'Anthropic',
+ // icon: 'icon-anthropic',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://console.anthropic.com/account/keys',
+ // defaultBaseUrl: 'https://api.anthropic.com',
+ // },
+ // GitHub: {
+ // label: 'GitHub',
+ // cn: 'GitHub Models',
+ // icon: 'icon-github',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://github.com/settings/tokens',
+ // defaultBaseUrl: 'https://models.github.ai/catalog',
+ // },
+ Yi: {
+ label: 'Yi',
+ cn: '零一万物',
+ icon: 'icon-yi',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://platform.lingyiwanwu.com/docs',
+ defaultBaseUrl: 'https://api.lingyiwanwu.com/v1',
+ },
+ // Baichuan: {
+ // label: 'Baichuan',
+ // cn: '百川智能',
+ // icon: 'icon-baichuan',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://platform.baichuan-ai.com/console/apikey',
+ // defaultBaseUrl: 'https://api.baichuan-ai.com/v1',
+ // },
+ // Ph8: {
+ // label: 'Ph8',
+ // cn: 'PH8大模型开放平台',
+ // icon: 'icon-ph8',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'https://ph8.co/v1',
+ // },
+ // MiniMax: {
+ // label: 'MiniMax',
+ // cn: 'MiniMax',
+ // icon: 'icon-minimax',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://api.minimax.chat/user-center/basic-information/interface-key',
+ // defaultBaseUrl: 'https://api.minimaxi.com/v1',
+ // },
+ // Groq: {
+ // label: 'Groq',
+ // cn: 'Groq',
+ // icon: 'icon-groq',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://console.groq.com/keys',
+ // defaultBaseUrl: 'https://api.groq.com/openai/v1',
+ // },
+ // Together: {
+ // label: 'Together',
+ // cn: 'Together',
+ // icon: 'icon-together',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: 'https://api.together.xyz/settings/api-keys',
+ // defaultBaseUrl: 'https://api.together.xyz/v1',
+ // },
+ // Jina: {
+ // label: 'Jina',
+ // cn: 'Jina',
+ // icon: 'icon-hyperbolic',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'https://api.jina.ai/v1',
+ // },
+
+ CTYun: {
+ label: 'CTYun',
+ cn: '天翼云息壤',
+ icon: 'icon-ctyun',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://www.ctyun.cn/products/ctxirang',
+ defaultBaseUrl: 'https://wishub-x1.ctyun.cn/v1',
+ },
+ TencentTI: {
+ label: 'TencentTI',
+ cn: '腾讯云TI',
+ icon: 'icon-tencentcloud',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://cloud.tencent.com/document/product/1772',
+ defaultBaseUrl: 'https://api.lkeap.cloud.tencent.com/v1',
+ },
+ BaiDuQianFan: {
+ label: 'BaiDuQianFan',
+ cn: '百度云千帆',
+ icon: 'icon-baiduqianfan',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://cloud.baidu.com/doc/index.html',
+ defaultBaseUrl: 'https://qianfan.baidubce.com/v2',
+ },
+ ModelScope: {
+ label: 'ModelScope',
+ cn: '魔搭社区',
+ icon: 'icon-modelscope',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://modelscope.cn/docs/model-service/API-Inference/intro',
+ defaultBaseUrl: 'https://api-inference.modelscope.cn/v1',
+ },
+ Infini: {
+ label: 'Infini',
+ cn: '无问芯穹',
+ icon: 'icon-infini',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.infini-ai.com/gen-studio/api/maas.html#/operations/chatCompletions',
+ defaultBaseUrl: 'https://cloud.infini-ai.com/maas/v1',
+ },
+ StepFun: {
+ label: 'StepFun',
+ cn: '阶跃星辰',
+ icon: 'icon-stepfun',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://platform.stepfun.com/docs/overview/concept',
+ defaultBaseUrl: 'https://api.stepfun.com/v1',
+ },
+ LanYun: {
+ label: 'LanYun',
+ cn: '蓝耘科技',
+ icon: 'icon-lanyun',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://archive.lanyun.net/#/maas/',
+ defaultBaseUrl: 'https://maas-api.lanyun.net/v1',
+ },
+ AlayaNew: {
+ label: 'AlayaNew',
+ cn: '九章智算云',
+ icon: 'icon-alayanew',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.alayanew.com/docs/modelService/interview?utm_source=cherrystudio',
+ defaultBaseUrl: 'https://deepseek.alayanew.com/v1',
+ },
+ PPIO: {
+ label: 'PPIO',
+ cn: '欧派云',
+ icon: 'icon-ppio',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.cherry-ai.com/pre-basic/providers/ppio?invited_by=JYT9GD&utm_source=github_cherry-studio',
+ defaultBaseUrl: 'https://api.ppinfra.com/v3/openai',
+ },
+ AiHubMix: {
+ label: 'AiHubMix',
+ cn: 'AiHubMix',
+ icon: 'icon-aihubmix',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://doc.aihubmix.com/',
+ defaultBaseUrl: 'https://aihubmix.com/v1',
+ },
+ OcoolAI: {
+ label: 'OcoolAI',
+ cn: 'OcoolAI',
+ icon: 'icon-ocoolai',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.ocoolai.com/',
+ defaultBaseUrl: 'https://api.ocoolai.com/v1',
+ },
+ DMXAPI: {
+ label: 'DMXAPI',
+ cn: 'DMXAPI',
+ icon: 'icon-dmxapi',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://dmxapi.cn/models.html#code-block',
+ defaultBaseUrl: 'https://www.dmxapi.cn/v1',
+ },
+ BurnCloud: {
+ label: 'BurnCloud',
+ cn: 'BurnCloud',
+ icon: 'icon-burncloud',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://ai.burncloud.com/docs',
+ defaultBaseUrl: 'https://ai.burncloud.com/v1',
+ },
+ Grok: {
+ label: 'Grok',
+ cn: 'Grok',
+ icon: 'icon-grok',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.x.ai/',
+ defaultBaseUrl: 'https://api.x.ai/v1',
+ },
+ Nvidia: {
+ label: 'Nvidia',
+ cn: '英伟达',
+ icon: 'icon-nvidia',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.api.nvidia.com/nim/reference/llm-apis',
+ defaultBaseUrl: 'https://integrate.api.nvidia.com/v1',
+ },
+ TokenFlux: {
+ label: 'TokenFlux',
+ cn: 'TokenFlux',
+ icon: 'icon-tokenflux',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://tokenflux.ai/docs',
+ defaultBaseUrl: 'https://tokenflux.ai/v1',
+ },
+ AI302: {
+ label: 'AI302',
+ cn: '302.AI',
+ icon: 'icon-302ai',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://302ai.apifox.cn/api-147522039',
+ defaultBaseUrl: 'https://api.302.ai/v1',
+ },
+ Cephalon: {
+ label: 'Cephalon',
+ cn: 'Cephalon',
+ icon: 'icon-cephalon',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://cephalon.cloud/apitoken/1864244127731589124',
+ defaultBaseUrl: 'https://cephalon.cloud/user-center/v1/model',
+ },
+ OpenRouter: {
+ label: 'OpenRouter',
+ cn: 'OpenRouter',
+ icon: 'icon-openrouter',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://openrouter.ai/docs/quick-start',
+ defaultBaseUrl: 'https://openrouter.ai/api/v1',
+ },
+ Fireworks: {
+ label: 'Fireworks',
+ cn: 'Fireworks',
+ icon: 'icon-fireworks',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.fireworks.ai/getting-started/introduction',
+ defaultBaseUrl: 'https://api.fireworks.ai/inference/v1',
+ },
+ Mistral: {
+ label: 'Mistral',
+ cn: 'Mistral',
+ icon: 'icon-mistral',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.mistral.ai',
+ defaultBaseUrl: 'https://api.mistral.ai/v1',
+ },
+ Perplexity: {
+ label: 'Perplexity',
+ cn: 'Perplexity',
+ icon: 'icon-perplexity',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.perplexity.ai/home',
+ defaultBaseUrl: 'https://api.perplexity.ai',
+ },
+ Hyperbolic: {
+ label: 'Hyperbolic',
+ cn: 'Hyperbolic',
+ icon: 'icon-hyperbolic',
+ urlWrite: false,
+ secretRequired: true,
+ customHeader: false,
+ modelDocumentUrl: 'https://docs.hyperbolic.xyz',
+ defaultBaseUrl: 'https://api.hyperbolic.xyz/v1',
+ },
+ // VoyageAI: {
+ // label: 'VoyageAI',
+ // cn: 'Voyage AI',
+ // icon: 'icon-voyageai',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'https://api.voyageai.com/v1',
+ // },
+ // Poe: {
+ // label: 'Poe',
+ // cn: 'Poe',
+ // icon: 'icon-poe',
+ // urlWrite: false,
+ // secretRequired: true,
+ // customHeader: false,
+ // modelDocumentUrl: '',
+ // defaultBaseUrl: 'https://api.poe.com/v1',
+ // },
Other: {
label: 'Other',
cn: '其他',
diff --git a/usecase/modelkit.go b/usecase/modelkit.go
index 109dc65..59d004e 100644
--- a/usecase/modelkit.go
+++ b/usecase/modelkit.go
@@ -31,6 +31,36 @@ import (
"github.com/chaitin/ModelKit/utils"
)
+// reqModelListApi 获取OpenAI兼容API的模型列表
+// 使用泛型和接口抽象来支持不同供应商的响应格式
+func reqModelListApi[T domain.ModelResponseParser](req *domain.ModelListReq, httpClient *http.Client, responseType T) ([]domain.ModelListItem, error) {
+ u, err := url.Parse(req.BaseURL)
+ if err != nil {
+ return nil, err
+ }
+ u.Path = path.Join(u.Path, "/models")
+
+ client := request.NewClient(u.Scheme, u.Host, httpClient.Timeout, request.WithClient(httpClient))
+ query, err := utils.GetQuery(req)
+ if err != nil {
+ return nil, err
+ }
+ resp, err := request.Get[T](
+ client, u.Path,
+ request.WithHeader(
+ request.Header{
+ "Authorization": fmt.Sprintf("Bearer %s", req.APIKey),
+ },
+ ),
+ request.WithQuery(query),
+ )
+ if err != nil {
+ return nil, err
+ }
+
+ return (*resp).ParseModels(), nil
+}
+
func ModelList(ctx context.Context, req *domain.ModelListReq) (*domain.ModelListResp, error) {
httpClient := &http.Client{
Timeout: time.Second * 30,
@@ -44,49 +74,14 @@ func ModelList(ctx context.Context, req *domain.ModelListReq) (*domain.ModelList
provider := consts.ParseModelProvider(req.Provider)
switch provider {
+ // 人工返回模型列表
case consts.ModelProviderAzureOpenAI,
consts.ModelProviderZhiPu,
consts.ModelProviderVolcengine:
return &domain.ModelListResp{
Models: domain.From(domain.ModelProviders[provider]),
}, nil
- case consts.ModelProviderOpenAI,
- consts.ModelProviderHunyuan,
- consts.ModelProviderMoonshot,
- consts.ModelProviderDeepSeek,
- consts.ModelProviderSiliconFlow,
- consts.ModelProviderBaiZhiCloud,
- consts.ModelProviderBaiLian:
- u, err := url.Parse(req.BaseURL)
- if err != nil {
- return nil, err
- }
- u.Path = path.Join(u.Path, "/models")
-
- client := request.NewClient(u.Scheme, u.Host, httpClient.Timeout, request.WithClient(httpClient))
- query := utils.GetQuery(req)
- resp, err := request.Get[domain.OpenAIResp](
- client, u.Path,
- request.WithHeader(
- request.Header{
- "Authorization": fmt.Sprintf("Bearer %s", req.APIKey),
- },
- ),
- request.WithQuery(query),
- )
- if err != nil {
- return nil, err
- }
-
- var models []domain.ModelListItem
- for _, item := range resp.Data {
- models = append(models, domain.ModelListItem{Model: item.ID})
- }
-
- return &domain.ModelListResp{
- Models: models,
- }, nil
-
+ // 以下模型供应商需要特殊处理
case consts.ModelProviderOllama:
// get from ollama http://10.10.16.24:11434/api/tags
u, err := url.Parse(req.BaseURL)
@@ -143,18 +138,30 @@ func ModelList(ctx context.Context, req *domain.ModelListReq) (*domain.ModelList
return &domain.ModelListResp{
Models: modelsList,
}, nil
+ case consts.ModelProviderGithub:
+ models, err := reqModelListApi(req, httpClient, &domain.GithubResp{})
+ if err != nil {
+ return nil, err
+ }
+ return &domain.ModelListResp{
+ Models: models,
+ }, nil
+ // openai 兼容模型
default:
- return nil, fmt.Errorf("invalid provider: %s", req.Provider)
+ models, err := reqModelListApi(req, httpClient, &domain.OpenAIResp{})
+
+ if err != nil {
+ return nil, err
+ }
+ return &domain.ModelListResp{
+ Models: models,
+ }, nil
}
}
func CheckModel(ctx context.Context, req *domain.CheckModelReq) (*domain.CheckModelResp, error) {
checkResp := &domain.CheckModelResp{}
- modelType, err := consts.ParseModelType(req.Type)
- if err != nil {
- checkResp.Error = err.Error()
- return checkResp, nil
- }
+ modelType := consts.ParseModelType(req.Type)
if modelType == consts.ModelTypeEmbedding || modelType == consts.ModelTypeRerank {
url := req.BaseURL
@@ -261,6 +268,7 @@ func GetChatModel(ctx context.Context, model *domain.ModelMetadata) (model.BaseC
config.HTTPClient = client
}
}
+
switch modelProvider {
case consts.ModelProviderDeepSeek:
chatModel, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
@@ -311,6 +319,7 @@ func GetChatModel(ctx context.Context, model *domain.ModelMetadata) (model.BaseC
return nil, fmt.Errorf("create chat model failed: %w", err)
}
return chatModel, nil
+ // 兼容 openai api
default:
chatModel, err := openai.NewChatModel(ctx, config)
if err != nil {
diff --git a/utils/utils.go b/utils/utils.go
index 16bdd00..62e6a92 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -297,12 +297,13 @@ func GetHttpClientWithAPIHeaderMap(header string) *http.Client {
return nil
}
-func GetQuery(req *domain.ModelListReq) request.Query {
+func GetQuery(req *domain.ModelListReq) (request.Query, error) {
q := make(request.Query, 0)
- provider := consts.ModelProvider(req.Provider)
- modelType := consts.ModelType(req.Type)
+ provider := consts.ParseModelProvider(req.Provider)
+ modelType := consts.ParseModelType(req.Type)
+
if provider != consts.ModelProviderBaiZhiCloud && provider != consts.ModelProviderSiliconFlow {
- return q
+ return q, nil
}
q["type"] = "text"
q["sub_type"] = string(req.Type)
@@ -313,5 +314,5 @@ func GetQuery(req *domain.ModelListReq) request.Query {
if provider == consts.ModelProviderSiliconFlow && modelType == consts.ModelTypeCoder {
q["sub_type"] = "chat"
}
- return q
+ return q, nil
}