From c4b76a8e89f7c429d6957914d05b8d3fcf5d09ec Mon Sep 17 00:00:00 2001 From: ssongliu Date: Fri, 23 Oct 2026 18:39:22 +0800 Subject: [PATCH] feat(ai): unify model services and inference engine management (#14175) --- agent/app/dto/agents.go | 1 + agent/app/dto/container.go | 3 +- agent/app/dto/request/app.go | 3 + agent/app/model/agent_account.go | 1 + agent/app/repo/agent_account.go | 21 + agent/app/service/agents.go | 52 +- agent/app/service/agents_local.go | 171 ++++ agent/app/service/agents_utils.go | 4 +- agent/app/service/ai.go | 10 +- agent/app/service/app.go | 12 + agent/app/service/app_utils.go | 7 +- agent/app/service/container.go | 8 +- agent/init/migration/migrate.go | 1 + agent/init/migration/migrations/init.go | 10 + core/constant/common.go | 1 + core/init/migration/helper/menu.go | 22 +- core/init/migration/migrate.go | 1 + core/init/migration/migrations/init.go | 15 + frontend/src/api/interface/ai.ts | 3 +- frontend/src/api/interface/app.ts | 2 + frontend/src/api/interface/container.ts | 1 + frontend/src/api/modules/ai.ts | 9 +- frontend/src/api/modules/container.ts | 10 +- .../src/assets/images/ai-providers/nvidia.ico | Bin 0 -> 25214 bytes .../components/container-resource/index.vue | 51 ++ frontend/src/lang/modules/en.ts | 33 +- frontend/src/lang/modules/es-es.ts | 33 +- frontend/src/lang/modules/fa.ts | 33 +- frontend/src/lang/modules/ja.ts | 33 +- frontend/src/lang/modules/ko.ts | 33 +- frontend/src/lang/modules/lo.ts | 33 +- frontend/src/lang/modules/ms.ts | 33 +- frontend/src/lang/modules/pt-br.ts | 33 +- frontend/src/lang/modules/ru.ts | 33 +- frontend/src/lang/modules/tr.ts | 33 +- frontend/src/lang/modules/zh-Hant.ts | 33 +- frontend/src/lang/modules/zh.ts | 33 +- frontend/src/routers/modules/ai.ts | 33 +- frontend/src/utils/agent-provider-logo.ts | 8 + frontend/src/utils/app.ts | 3 + .../src/views/ai/agents/agent/add/index.vue | 2 +- frontend/src/views/ai/agents/model/index.vue | 221 ----- .../components/account-address/index.vue | 88 ++ .../components/account-form}/index.vue | 27 +- .../ai/model/components/connection/index.vue | 273 +++++++ .../ai/model/components/create/index.vue | 315 +++++++ .../components/deployment-manage/index.vue | 402 +++++++++ .../components/model-pool}/index.vue | 11 +- frontend/src/views/ai/model/deployment.ts | 106 +++ frontend/src/views/ai/model/index.vue | 772 +++++++++++++++++- frontend/src/views/ai/model/local/index.vue | 121 +-- .../src/views/ai/model/ollama/add/index.vue | 4 +- .../src/views/ai/model/ollama/conn/index.vue | 145 ---- .../views/ai/model/ollama/domain/index.vue | 4 +- .../ai/model/ollama/{ => models}/index.vue | 237 ++---- .../views/ai/model/ollama/operate/index.vue | 113 +++ .../views/ai/model/ollama/terminal/index.vue | 31 +- .../src/views/ai/model/tensorrt/index.vue | 4 +- .../views/ai/model/tensorrt/operate/index.vue | 31 +- frontend/src/views/app-store/apps/index.vue | 4 +- .../src/views/app-store/detail/form/index.vue | 12 +- .../src/views/container/container/index.vue | 107 +-- 62 files changed, 3033 insertions(+), 856 deletions(-) create mode 100644 agent/app/service/agents_local.go create mode 100644 frontend/src/assets/images/ai-providers/nvidia.ico create mode 100644 frontend/src/components/container-resource/index.vue delete mode 100644 frontend/src/views/ai/agents/model/index.vue create mode 100644 frontend/src/views/ai/model/components/account-address/index.vue rename frontend/src/views/ai/{agents/model/add => model/components/account-form}/index.vue (97%) create mode 100644 frontend/src/views/ai/model/components/connection/index.vue create mode 100644 frontend/src/views/ai/model/components/create/index.vue create mode 100644 frontend/src/views/ai/model/components/deployment-manage/index.vue rename frontend/src/views/ai/{agents/model/pool => model/components/model-pool}/index.vue (94%) create mode 100644 frontend/src/views/ai/model/deployment.ts delete mode 100644 frontend/src/views/ai/model/ollama/conn/index.vue rename frontend/src/views/ai/model/ollama/{ => models}/index.vue (59%) create mode 100644 frontend/src/views/ai/model/ollama/operate/index.vue diff --git a/agent/app/dto/agents.go b/agent/app/dto/agents.go index 45b63f924..8cda5d933 100644 --- a/agent/app/dto/agents.go +++ b/agent/app/dto/agents.go @@ -386,6 +386,7 @@ type AgentAccountProviderCountReq struct { } type AgentAccountInfo struct { + AppInstallID uint `json:"appInstallId"` ID uint `json:"id"` MasterAccountID uint `json:"masterAccountId"` Provider string `json:"provider"` diff --git a/agent/app/dto/container.go b/agent/app/dto/container.go index be5274fba..e3d1502d4 100644 --- a/agent/app/dto/container.go +++ b/agent/app/dto/container.go @@ -171,7 +171,8 @@ type ContainerItemStats struct { BuildCacheReclaimable int64 `json:"buildCacheReclaimable"` } type ContainerListStats struct { - ContainerID string `json:"containerID"` + ContainerID string `json:"containerID"` + ContainerName string `json:"containerName"` CPUTotalUsage uint64 `json:"cpuTotalUsage"` SystemUsage uint64 `json:"systemUsage"` diff --git a/agent/app/dto/request/app.go b/agent/app/dto/request/app.go index 0091a50f6..eeaea57df 100644 --- a/agent/app/dto/request/app.go +++ b/agent/app/dto/request/app.go @@ -23,6 +23,9 @@ type AppInstallCreate struct { Services map[string]string `json:"services"` TaskID string `json:"taskID"` + ModelAccountBaseURLType string `json:"modelAccountBaseURLType" validate:"omitempty,oneof=container localhost systemIP custom"` + ModelAccountBaseURL string `json:"modelAccountBaseURL"` + AppContainerConfig NodePushConfig } diff --git a/agent/app/model/agent_account.go b/agent/app/model/agent_account.go index afae905ac..27cca6abe 100644 --- a/agent/app/model/agent_account.go +++ b/agent/app/model/agent_account.go @@ -2,6 +2,7 @@ package model type AgentAccount struct { BaseModel + AppInstallID uint `json:"appInstallId"` Provider string `json:"provider"` Name string `json:"name"` APIKey string `json:"apiKey"` diff --git a/agent/app/repo/agent_account.go b/agent/app/repo/agent_account.go index 18246cab5..dde50b4d9 100644 --- a/agent/app/repo/agent_account.go +++ b/agent/app/repo/agent_account.go @@ -4,6 +4,7 @@ import ( "strings" "github.com/1Panel-dev/1Panel/agent/app/model" + "github.com/1Panel-dev/1Panel/agent/global" "gorm.io/gorm" ) @@ -18,6 +19,7 @@ type IAgentAccountRepo interface { DeleteByID(id uint) error List(opts ...DBOption) ([]model.AgentAccount, error) CountTextByProviders(providers []string) (map[string]int64, error) + SaveLocal(account *model.AgentAccount, models []model.AgentAccountModel) error } func NewIAgentAccountRepo() IAgentAccountRepo { @@ -97,6 +99,25 @@ func (a AgentAccountRepo) CountTextByProviders(providers []string) (map[string]i return counts, nil } +func (a AgentAccountRepo) SaveLocal(account *model.AgentAccount, models []model.AgentAccountModel) error { + return global.DB.Transaction(func(tx *gorm.DB) error { + if err := tx.Save(account).Error; err != nil { + return err + } + if err := tx.Where("account_id = ?", account.ID).Delete(&model.AgentAccountModel{}).Error; err != nil { + return err + } + if len(models) == 0 { + return nil + } + for i := range models { + models[i].AccountID = account.ID + models[i].SortOrder = i + 1 + } + return tx.Create(&models).Error + }) +} + func normalizeProviders(providers []string) []string { seen := make(map[string]struct{}, len(providers)) result := make([]string, 0, len(providers)) diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index d49f1ddb9..bf90f4d24 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -1055,7 +1055,7 @@ func (a AgentService) CreateAccount(req dto.AgentAccountCreateReq) error { return err } validateAvailability := req.ValidateAvailability == nil || *req.ValidateAvailability - resolvedInput, err := resolveAgentAccountInput(provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, verifyModel, validateAvailability) + resolvedInput, err := resolveAgentAccountInput(provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, verifyModel, validateAvailability, false) if err != nil { return err } @@ -1108,12 +1108,15 @@ func (a AgentService) UpdateAccount(req dto.AgentAccountUpdateReq) error { if strings.TrimSpace(requestedVerifyModel) == "" { requestedVerifyModel = account.VerifyModel } - verifyModel, err := resolveAgentAccountVerifyModel(provider, requestedVerifyModel, models) - if err != nil { - return err + verifyModel := "" + if account.AppInstallID == 0 || len(models) > 0 { + verifyModel, err = resolveAgentAccountVerifyModel(provider, requestedVerifyModel, models) + if err != nil { + return err + } } validateAvailability := req.ValidateAvailability == nil || *req.ValidateAvailability - resolvedInput, err := resolveAgentAccountInput(provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, verifyModel, validateAvailability) + resolvedInput, err := resolveAgentAccountInput(provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, verifyModel, validateAvailability, account.AppInstallID != 0 && len(models) == 0) if err != nil { return err } @@ -1127,7 +1130,7 @@ func (a AgentService) UpdateAccount(req dto.AgentAccountUpdateReq) error { account.Remark = req.Remark account.Verified = true - if err := global.DB.Save(account).Error; err != nil { + if err := agentAccountRepo.Save(account); err != nil { return err } terminalai.InvalidateTerminalRuntimeCache() @@ -1158,13 +1161,34 @@ func (a AgentService) PageAccounts(req dto.AgentAccountSearch) (int64, []dto.Age if err != nil { return 0, nil, err } + installIDs := make([]uint, 0, len(list)) + for _, account := range list { + if account.AppInstallID != 0 { + installIDs = append(installIDs, account.AppInstallID) + } + } + localInstalls := make(map[uint]bool, len(installIDs)) + if len(installIDs) > 0 { + installs, err := appInstallRepo.ListBy(context.Background(), repo.WithByIDs(installIDs)) + if err != nil { + return 0, nil, err + } + for _, install := range installs { + localInstalls[install.ID] = true + } + } items := make([]dto.AgentAccountInfo, 0, len(list)) for _, item := range list { apiKey := "" if item.RememberAPIKey { apiKey = item.APIKey } + appInstallID := uint(0) + if localInstalls[item.AppInstallID] { + appInstallID = item.AppInstallID + } items = append(items, dto.AgentAccountInfo{ + AppInstallID: appInstallID, ID: item.ID, MasterAccountID: item.MasterAccountID, Provider: item.Provider, @@ -1362,13 +1386,27 @@ func (a AgentService) SyncAgentsByAccount(account *model.AgentAccount) error { } func (a AgentService) VerifyAccount(req dto.AgentAccountVerifyReq) error { - _, err := resolveAgentAccountInput(req.Provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, req.Model, true) + _, err := resolveAgentAccountInput(req.Provider, req.APIType, req.AuthMode, req.APIKey, req.BaseURL, req.Model, true, false) return err } func (a AgentService) DeleteAccount(req dto.AgentAccountDeleteReq) error { agentAccountMutationMu.Lock() defer agentAccountMutationMu.Unlock() + account, err := agentAccountRepo.GetFirst(repo.WithByID(req.ID)) + if err != nil { + return err + } + if account.AppInstallID != 0 && account.Provider != "ollama" { + _, err := appInstallRepo.GetFirst(repo.WithByID(account.AppInstallID)) + if err == nil { + return buserr.WithDetail("ErrInvalidParams", "Delete the local inference engine instead", nil) + } + if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } + } + if err := global.DB.Transaction(func(tx *gorm.DB) error { var agentCount int64 if err := tx.Model(&model.Agent{}).Where("account_id = ?", req.ID).Count(&agentCount).Error; err != nil { diff --git a/agent/app/service/agents_local.go b/agent/app/service/agents_local.go new file mode 100644 index 000000000..f2f7ae90d --- /dev/null +++ b/agent/app/service/agents_local.go @@ -0,0 +1,171 @@ +package service + +import ( + "errors" + "fmt" + "strings" + + "github.com/1Panel-dev/1Panel/agent/app/dto" + "github.com/1Panel-dev/1Panel/agent/app/model" + "github.com/1Panel-dev/1Panel/agent/app/repo" + "github.com/1Panel-dev/1Panel/agent/constant" + "github.com/1Panel-dev/1Panel/agent/global" + terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai" + "gorm.io/gorm" +) + +func SyncLocalModelAccount(install model.AppInstall, accountID uint, baseURL string, models []dto.AgentAccountModel, updateBaseURL, createIfMissing bool) (*model.AgentAccount, error) { + if install.ID == 0 || (install.App.Key != "ollama" && install.App.Key != "vllm") { + return nil, fmt.Errorf("invalid local model installation") + } + agentAccountMutationMu.Lock() + defer agentAccountMutationMu.Unlock() + account, err := agentAccountRepo.GetFirst(repo.WithByAppInstallID(install.ID)) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + if errors.Is(err, gorm.ErrRecordNotFound) && accountID != 0 { + account, err = agentAccountRepo.GetFirst(repo.WithByID(accountID), repo.WithByProvider(install.App.Key)) + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return nil, err + } + if err == nil && account.AppInstallID != 0 && account.AppInstallID != install.ID { + return nil, fmt.Errorf("model account belongs to another installation") + } + } + if errors.Is(err, gorm.ErrRecordNotFound) { + if !createIfMissing { + return nil, nil + } + name := install.Name + for suffix := 1; ; suffix++ { + existing, err := agentAccountRepo.List(repo.WithByProvider(install.App.Key), repo.WithByName(name)) + if err != nil { + return nil, err + } + if len(existing) == 0 { + break + } + name = fmt.Sprintf("%s-%d", install.Name, suffix) + } + apiType, apiKey := "openai-completions", "vllm-local" + if install.App.Key == "ollama" { + apiType, apiKey = "openai-responses", "ollama-local" + } + account = &model.AgentAccount{Name: name, Provider: install.App.Key, BaseURL: baseURL, APIType: apiType, APIKey: apiKey, RememberAPIKey: true, Verified: true} + } + accountChanged := account.ID == 0 || account.AppInstallID != install.ID || (updateBaseURL && account.BaseURL != baseURL) + account.AppInstallID = install.ID + if updateBaseURL { + account.BaseURL = baseURL + } + rows := make([]model.AgentAccountModel, 0, len(models)) + verifyModelExists := account.VerifyModel == "" + for _, item := range models { + rows = append(rows, model.AgentAccountModel{Model: item.ID, Name: item.Name}) + if item.ID == account.VerifyModel { + verifyModelExists = true + } + } + if !verifyModelExists { + account.VerifyModel = "" + accountChanged = true + } + var previous []model.AgentAccountModel + if account.ID != 0 { + previous, err = agentAccountModelRepo.List(repo.WithByAccountID(account.ID), repo.WithOrderAsc("sort_order"), repo.WithOrderAsc("id")) + if err != nil { + return nil, err + } + } + modelsChanged := len(previous) != len(rows) + if !modelsChanged { + for i := range rows { + if previous[i].Model != rows[i].Model || previous[i].Name != rows[i].Name { + modelsChanged = true + break + } + } + } + if modelsChanged { + err = agentAccountRepo.SaveLocal(account, rows) + } else if accountChanged { + err = agentAccountRepo.Save(account) + } else { + return account, nil + } + if err != nil { + return nil, err + } + terminalai.InvalidateTerminalRuntimeCache() + terminalai.InvalidateFileAIRuntimeCache() + return account, nil +} + +func SyncOllamaModelAccount(createIfMissing bool) error { + app, err := appRepo.GetFirst(appRepo.WithKey("ollama")) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil + } + if err != nil { + return err + } + install, err := appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID)) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil + } + if err != nil { + return err + } + models, err := aiRepo.List(repo.WithByStatus(constant.StatusSuccess), repo.WithOrderAsc("name")) + if err != nil { + return err + } + items := make([]dto.AgentAccountModel, 0, len(models)) + for _, item := range models { + items = append(items, dto.AgentAccountModel{ID: item.Name, Name: item.Name}) + } + _, err = SyncLocalModelAccount(install, 0, fmt.Sprintf("http://%s:11434/v1", install.ContainerName), items, false, createIfMissing) + return err +} + +func CleanupLocalModelAccount(installID uint) { + if installID == 0 { + return + } + accounts, err := agentAccountRepo.List(repo.WithByAppInstallID(installID)) + if err != nil { + global.LOG.Errorf("load local model accounts: %v", err) + return + } + for _, account := range accounts { + if err := (AgentService{}).DeleteAccount(dto.AgentAccountDeleteReq{ID: account.ID}); err != nil { + global.LOG.Warnf("keep local model account %d after uninstall: %v", account.ID, err) + } + } +} + +func ResolveLocalModelAccountBaseURL(addressType, customURL, containerName, containerPort string, hostPort int) (string, error) { + switch addressType { + case "custom": + baseURL := strings.TrimRight(strings.TrimSpace(customURL), "/") + if !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") { + return "", fmt.Errorf("model account base URL must start with http:// or https://") + } + return baseURL, nil + case "localhost": + return fmt.Sprintf("http://127.0.0.1:%d/v1", hostPort), nil + case "systemIP": + systemIP, err := settingRepo.GetValueByKey("SystemIP") + if err != nil { + return "", err + } + systemIP = strings.TrimSpace(systemIP) + if systemIP == "" { + systemIP = "127.0.0.1" + } + return fmt.Sprintf("http://%s:%d/v1", systemIP, hostPort), nil + default: + return fmt.Sprintf("http://%s:%s/v1", containerName, containerPort), nil + } +} diff --git a/agent/app/service/agents_utils.go b/agent/app/service/agents_utils.go index 1386f91fe..0d549cf26 100644 --- a/agent/app/service/agents_utils.go +++ b/agent/app/service/agents_utils.go @@ -98,7 +98,7 @@ func ensureContainerRunning(containerName string) error { return nil } -func resolveAgentAccountInput(provider, apiType, authMode, apiKey, baseURL, modelID string, validateAvailability bool) (resolvedAgentAccountInput, error) { +func resolveAgentAccountInput(provider, apiType, authMode, apiKey, baseURL, modelID string, validateAvailability, allowEmptyModel bool) (resolvedAgentAccountInput, error) { resolvedAPIKey := strings.TrimSpace(apiKey) resolvedAPIType := strings.TrimSpace(apiType) resolvedAuthMode, err := providercatalog.ResolveAuthMode(provider, resolvedAPIType, authMode) @@ -113,7 +113,7 @@ func resolveAgentAccountInput(provider, apiType, authMode, apiKey, baseURL, mode return resolvedAgentAccountInput{}, err } modelID = strings.TrimSpace(modelID) - if modelID == "" { + if modelID == "" && !allowEmptyModel { return resolvedAgentAccountInput{}, buserr.New("ErrAgentAccountModelsRequired") } imageAPI := providercatalog.IsImageAPIType(resolvedAPIType) diff --git a/agent/app/service/ai.go b/agent/app/service/ai.go index 5ab8af8be..ce567f63c 100644 --- a/agent/app/service/ai.go +++ b/agent/app/service/ai.go @@ -125,6 +125,9 @@ func (u *AIToolService) Create(req dto.OllamaModelName) error { if err := taskItem.Execute(); err != nil { _ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) } + if err := SyncOllamaModelAccount(false); err != nil { + global.LOG.Errorf("sync Ollama model account after pull: %v", err) + } }() return nil } @@ -179,6 +182,9 @@ func (u *AIToolService) Recreate(req dto.OllamaModelName) error { if err := taskItem.Execute(); err != nil { _ = aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) } + if err := SyncOllamaModelAccount(false); err != nil { + global.LOG.Errorf("sync Ollama model account after pull: %v", err) + } }() return nil } @@ -202,7 +208,7 @@ func (u *AIToolService) Delete(req dto.ForceDelete) error { logItem := path.Join(global.Dir.DataDir, "log", "AITools", item.Name) _ = os.Remove(logItem) } - return nil + return SyncOllamaModelAccount(false) } func (u *AIToolService) Sync() ([]dto.OllamaModelDropList, error) { @@ -250,7 +256,7 @@ func (u *AIToolService) Sync() ([]dto.OllamaModelDropList, error) { _ = aiRepo.Create(&item) } - return dropList, nil + return dropList, SyncOllamaModelAccount(false) } func (u *AIToolService) BindDomain(req dto.OllamaBindDomain) error { diff --git a/agent/app/service/app.go b/agent/app/service/app.go index f919235e5..3ae08288a 100644 --- a/agent/app/service/app.go +++ b/agent/app/service/app.go @@ -499,6 +499,14 @@ func (a AppService) installWithHooks(req request.AppInstallCreate, executeScript req.Params[constant.ContainerName] = containerName appInstall.ContainerName = containerName + modelAccountBaseURL := "" + if app.Key == "ollama" { + modelAccountBaseURL, err = ResolveLocalModelAccountBaseURL(req.ModelAccountBaseURLType, req.ModelAccountBaseURL, containerName, "11434", httpPort) + if err != nil { + return + } + } + index := 0 serviceName := "" for k := range servicesMap { @@ -609,6 +617,10 @@ func (a AppService) installWithHooks(req request.AppInstallCreate, executeScript return err } updateToolApp(appInstall) + if app.Key == "ollama" { + _, err := SyncLocalModelAccount(*appInstall, 0, modelAccountBaseURL, nil, false, true) + return err + } return nil } diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go index a8b5db48b..585202d74 100644 --- a/agent/app/service/app_utils.go +++ b/agent/app/service/app_utils.go @@ -469,7 +469,12 @@ func deleteAppInstall(deleteReq request.AppInstallDelete) error { if err == nil && len(entries) == 0 { _ = op.DeleteDir(parentDir) } - tx.Commit() + if err := tx.Commit().Error; err != nil { + return err + } + if install.App.Key == "ollama" || install.App.Key == "vllm" { + CleanupLocalModelAccount(install.ID) + } existApps, _ := appInstallRepo.ListBy(context.Background(), appInstallRepo.WithAppId(install.AppId)) if len(existApps) == 0 { diff --git a/agent/app/service/container.go b/agent/app/service/container.go index 07529ac18..0d823f411 100644 --- a/agent/app/service/container.go +++ b/agent/app/service/container.go @@ -324,10 +324,12 @@ func (u *ContainerService) ContainerListStats(ctx context.Context, ids []string) defer wg.Done() for index := range jobs { datas[index].ContainerID = list[index].ID - if ctx.Err() != nil || list[index].State != "running" { - continue + if ctx.Err() == nil && list[index].State == "running" { + datas[index] = loadCpuAndMem(ctx, client, list[index].ID) + } + if len(list[index].Names) > 0 { + datas[index].ContainerName = strings.TrimPrefix(list[index].Names[0], "/") } - datas[index] = loadCpuAndMem(ctx, client, list[index].ID) } }() } diff --git a/agent/init/migration/migrate.go b/agent/init/migration/migrate.go index c15edb197..86f9a8920 100644 --- a/agent/init/migration/migrate.go +++ b/agent/init/migration/migrate.go @@ -117,6 +117,7 @@ func agentDBMigrations() []*gormigrate.Migration { migrations.AddVLLMSampleInterval, migrations.AddNativeAgentInstalls, migrations.AddQuickDirectory, + migrations.AddLocalModelAccountLink, } } diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go index b5b821c2f..3b520fbc9 100644 --- a/agent/init/migration/migrations/init.go +++ b/agent/init/migration/migrations/init.go @@ -1895,3 +1895,13 @@ var AddQuickDirectory = &gormigrate.Migration{ return tx.AutoMigrate(&model.QuickDirectory{}) }, } + +var AddLocalModelAccountLink = &gormigrate.Migration{ + ID: "20261023-add-local-model-account-link", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.AgentAccount{}); err != nil { + return err + } + return service.SyncOllamaModelAccount(true) + }, +} diff --git a/core/constant/common.go b/core/constant/common.go index fff4d09c5..39fa6cff2 100644 --- a/core/constant/common.go +++ b/core/constant/common.go @@ -73,6 +73,7 @@ var WebUrlMap = map[string]struct{}{ "/ai/benchmark": {}, "/ai/model/account": {}, "/ai/model/local": {}, + "/ai/model/files": {}, "/ai/gpu": {}, "/ai/gpu/current": {}, "/ai/gpu/history": {}, diff --git a/core/init/migration/helper/menu.go b/core/init/migration/helper/menu.go index c7598d4b6..b09471ab3 100644 --- a/core/init/migration/helper/menu.go +++ b/core/init/migration/helper/menu.go @@ -98,8 +98,8 @@ func LoadMenus() string { {ID: "2", Disabled: true, Title: "menu.apps", IsShow: true, Label: "App-Menu", Path: "/apps/all", Sort: 200}, {ID: "3", Disabled: false, Title: "menu.aiTools", IsShow: true, Label: "AI-Menu", Path: "/ai/model/account", Sort: 300, Children: []dto.ShowMenu{ - {ID: "44", Disabled: false, Title: "aiTools.agents.agent", IsShow: true, Label: "Agents", Path: "/ai/agents/agent", Sort: 50}, - {ID: "41", Disabled: false, Title: "aiTools.model.model", IsShow: true, Label: "AIModel", Path: "/ai/model/account", Sort: 100}, + {ID: "41", Disabled: false, Title: "aiTools.model.model", IsShow: true, Label: "AIModel", Path: "/ai/model/account", Sort: 50}, + {ID: "44", Disabled: false, Title: "aiTools.agents.agent", IsShow: true, Label: "Agents", Path: "/ai/agents/agent", Sort: 100}, {ID: "42", Disabled: false, Title: "menu.mcp", IsShow: true, Label: "MCPServer", Path: "/ai/mcp", Sort: 200}, {ID: "43", Disabled: false, Title: "aiTools.gpu.gpu", IsShow: true, Label: "GPU", Path: "/ai/gpu", Sort: 300}, }}, @@ -149,7 +149,7 @@ func LoadMenus() string { IsShow: true, Label: "AIProxyManagement", Path: "/ai/ai-proxy/model-pool", - Sort: 150, + Sort: 75, }, "AIModel") item[i].Children = UpsertMenuByLabel(item[i].Children, dto.ShowMenu{ ID: "47", @@ -158,8 +158,8 @@ func LoadMenus() string { IsShow: true, Label: "SkillsHub", Path: "/ai/skills-hub", - Sort: 155, - }, "AIProxyManagement") + Sort: 225, + }, "MCPServer") item[i].Children = UpsertMenuByLabel(item[i].Children, dto.ShowMenu{ ID: "45", Disabled: false, @@ -167,7 +167,7 @@ func LoadMenus() string { IsShow: true, Label: "AIBenchmark", Path: "/ai/benchmark", - Sort: 160, + Sort: 250, }, "SkillsHub") continue } @@ -204,12 +204,12 @@ func MenuSort() []dto.MenuLabelSort { {Label: "Home-Menu", Sort: 100}, {Label: "App-Menu", Sort: 200}, {Label: "AI-Menu", Sort: 300}, - {Label: "Agents", Sort: 50}, - {Label: "AIModel", Sort: 100}, - {Label: "AIProxyManagement", Sort: 150}, - {Label: "SkillsHub", Sort: 155}, - {Label: "AIBenchmark", Sort: 160}, + {Label: "AIModel", Sort: 50}, + {Label: "AIProxyManagement", Sort: 75}, + {Label: "Agents", Sort: 100}, {Label: "MCPServer", Sort: 200}, + {Label: "SkillsHub", Sort: 225}, + {Label: "AIBenchmark", Sort: 250}, {Label: "GPU", Sort: 300}, {Label: "Website-Menu", Sort: 400}, {Label: "Website", Sort: 100}, diff --git a/core/init/migration/migrate.go b/core/init/migration/migrate.go index 6b3ab9186..b0f1aa5e0 100644 --- a/core/init/migration/migrate.go +++ b/core/init/migration/migrate.go @@ -69,5 +69,6 @@ func coreMigrations() []*gormigrate.Migration { migrations.MoveVirtualMachineMenuToXpack, migrations.AddAPIKeys, migrations.AddOperationLogAPIKey, + migrations.UpdateAiMenuOrder, } } diff --git a/core/init/migration/migrations/init.go b/core/init/migration/migrations/init.go index 5f5bdf1ff..4c505c219 100644 --- a/core/init/migration/migrations/init.go +++ b/core/init/migration/migrations/init.go @@ -1376,6 +1376,21 @@ var RemoveUpageHideMenu = &gormigrate.Migration{ Migrate: reconcileHideMenuSetting, } +var UpdateAiMenuOrder = &gormigrate.Migration{ + ID: "20261023-update-ai-menu-order", + Migrate: func(tx *gorm.DB) error { + return helper.UpdateChildMenuSortByLabel(tx, "AI-Menu", []dto.MenuLabelSort{ + {Label: "AIModel", Sort: 50}, + {Label: "AIProxyManagement", Sort: 75}, + {Label: "Agents", Sort: 100}, + {Label: "MCPServer", Sort: 200}, + {Label: "SkillsHub", Sort: 225}, + {Label: "AIBenchmark", Sort: 250}, + {Label: "GPU", Sort: 300}, + }) + }, +} + var UpdateFirewallMenuPath = &gormigrate.Migration{ ID: "20260819-update-firewall-menu-path", Migrate: func(tx *gorm.DB) error { diff --git a/frontend/src/api/interface/ai.ts b/frontend/src/api/interface/ai.ts index bbaa9a1cb..b1157258a 100644 --- a/frontend/src/api/interface/ai.ts +++ b/frontend/src/api/interface/ai.ts @@ -18,7 +18,7 @@ export namespace AI { name: string; } export interface OllamaModelSearch extends ReqPage { - info: string; + info?: string; } export interface Info { @@ -738,6 +738,7 @@ export namespace AI { } export interface AgentAccountItem { + appInstallId?: number; id: number; provider: string; providerName: string; diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts index 314b880e8..7e37f1c0e 100644 --- a/frontend/src/api/interface/app.ts +++ b/frontend/src/api/interface/app.ts @@ -136,6 +136,8 @@ export namespace App { } export interface AppInstall { + modelAccountBaseURLType?: string; + modelAccountBaseURL?: string; appDetailId: number; params: any; taskID: string; diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index ebc50dbac..cb1f65718 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -177,6 +177,7 @@ export namespace Container { } export interface ContainerListStats { containerID: string; + containerName: string; cpuTotalUsage: number; systemUsage: number; cpuPercent: number; diff --git a/frontend/src/api/modules/ai.ts b/frontend/src/api/modules/ai.ts index 68a0ba51b..96b041dcb 100644 --- a/frontend/src/api/modules/ai.ts +++ b/frontend/src/api/modules/ai.ts @@ -22,8 +22,13 @@ export const loadOllamaModel = (name: string) => { export const syncOllamaModel = () => { return http.post>(`/ai/ollama/model/sync`); }; -export const closeOllamaModel = (name: string) => { - return http.post(`/ai/ollama/close`, { name: name }); +export const closeOllamaModel = (name: string, currentNode?: string) => { + return http.post( + `/ai/ollama/close`, + { name: name }, + undefined, + currentNode ? { CurrentNode: currentNode } : undefined, + ); }; export const bindDomain = (req: AI.BindDomain) => { diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index a98ab5fa7..7a48f2ab1 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -90,10 +90,14 @@ export const containerItemStats = (containerID: string, currentNode?: string) => currentNode ? { CurrentNode: currentNode } : undefined, ); }; -export const containerListStats = (currentNode?: string, ids?: string[], signal?: AbortSignal) => { +export const containerListStats = ( + currentNode?: string, + ids?: string[], + config?: AxiosRequestConfig & { skipErrorMessage?: boolean }, +) => { return http.get>(`/containers/list/stats`, ids ? { ids: ids.join(',') } : {}, { - headers: currentNode ? { CurrentNode: currentNode } : undefined, - signal, + ...config, + headers: { ...config?.headers, ...(currentNode ? { CurrentNode: currentNode } : {}) }, }); }; export const containerStats = (id: string) => { diff --git a/frontend/src/assets/images/ai-providers/nvidia.ico b/frontend/src/assets/images/ai-providers/nvidia.ico new file mode 100644 index 0000000000000000000000000000000000000000..424df87200c706460f9ad1c7722ef0d35f286f2b GIT binary patch literal 25214 zcmeHP33MFAnf_ZXd&ZV!naGC>!X8`L#s@^339*=AG3F%%2(Td`0YYHKZfwp41JlG< zfZ7Zop2Zoiut~6CAT|+s5lq4~av)>Gz1)X6mVj6i!b{kVI1-e^So?idUDG|%Sh8iv zVs^^ullRHy1IHiB9@Gi#>NTAE9Jz|BG-vXET-#kRfuc`ZNday-`x^9UJMedqPeqBFtl*n;24S!75%@TQVj^Rfge5W01_+xTnrO4#tM0SS{ zFd@wV{bF);rpm=1E*e2`U7g_*MZlGOK97ce^(X!PECKjO5j<(oQS!wW=KN zXcRk>iRV~@NJl2ik`1y{wYPwv8nW?36ASS;$ZJr@#xtx(JK|)pVKb7UKhl*{2JH^| zPxfRo63@6IiG*q=KiTb!Tb0S8A(Bm?Rq?0eosw-5I}y)R7LDp|y3Y&=eWNh&1^J3+QH_*CNnxv^}dM=*(!ok?QU7|(WcVWzhy*e5+~ zDzYj9Rq;$5)5Qfgn}vOmvyxmF(pdT8^cUS-gDO`f|2`y$M@KTAp?;OBIL2uDvCqeHz{h?d2R-&fIrOm`s=BfpP>!9sw+|BNr}9 zemoIaFni0Xl*Q_biVCafFR0a(5ZG4!n(FF^wS_cgp#FwhY-x3h)l~XkZONb65jt-8 znKz85NNN7L^rAW@^%E!6#R8%EH6hhQ9{RkpL$f3jLi;3UpRjb6HY!t)H&Z5In9YU3uyUYgbm-SgWYYf9T*K z&92a0R`G;wU7HV=tlE0o!5<|jqc9UWoW-a1r$)%3T?aq@0)83-+dNP;zb?!L*%wf* zs1Nv457`@LErsOsQymUa;CG|AJSqVnW;hF7fhnZYQ$iDFuxkBh#5y64(&@U zhz(0dDRhp*gx;0LI9}saiE3!5C_ZG-iH(sOP6DJ^ zSP-iXIT0!rf^E2woB3HneYn2`2{k``&xi3}$!shC+*rfR1`R(m)tR{Z%4r9SfPT#6 za~9J`au-X+5a&GQbE_faT6}KhKc`lPCJ`4Hv&irn_3rP=Xg;HM;Td&(i;OqVsC+)X zr&T?lPQCX6nU=p$W^QPcIe0$Zy?d3+@4nQ3M!iBl_rR617oJm_9=clgdH7n{56`KK z@tk_VfBd_8PCfXsAIV{l-zZ;y@+Lf|X5=V5rylprTKQ)@qaF_|#WU(jct$-H�&2 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 nWL_H +
+
CPU: {{ stats.cpuPercent.toFixed(2) }}%
+
{{ $t('monitor.memory') }}: {{ stats.memoryPercent.toFixed(2) }}%
+ + + + +
+ + + + + diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index f9871eaa4..8962f92c6 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1017,6 +1017,37 @@ const message = { validateImageAvailabilityHelper: 'Generates one minimal image before saving and may incur charges', }, model: { + modelCategory: 'Model category', + modelName: 'Model name', + modelArchitecture: 'Model type', + backboneParams: 'MoE backbone parameters', + activeParams: 'Active parameters', + engram: 'Engram', + weightFootprint: 'Weight size', + undisclosed: 'Undisclosed', + featuredModels: 'Featured models', + deploy: 'Deploy', + approxWeightSize: 'Approx. {0} GB', + services: 'Model services', + addService: 'Add model service', + addEngine: 'Add inference engine', + onlineModel: 'Online models', + instanceDeployment: 'Deploy by instance', + nvidiaDeployment: 'NVIDIA-optimized deployment', + engines: 'Inference engines', + modelManagement: 'Model management', + serviceDetails: 'Service details', + deployments: 'Local deployments', + files: 'Model files', + connectExternal: 'Connect external service', + deploymentTemplates: 'Startup command templates', + engineProvider: 'Engine / Provider', + endpoint: 'Endpoint', + cloudAccount: 'Cloud account', + connectionStatus: 'Connection status', + unverified: 'Unverified', + manage: 'Manage', + loadFailed: 'Failed to load. Refresh to retry.', model: 'Models', localModel: 'Local Models', create_helper: 'Pull "{0}"', @@ -1032,7 +1063,6 @@ const message = { vllmCommandPortHelper: 'The startup command must use port {0}; otherwise, the service will be inaccessible.', ascendVisibleDevices: 'Ascend visible devices (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Sync to model account', modelAccountAddressHelper: 'Container address is for agent containers; 127.0.0.1, system IP, or custom address is for AI Gateway or external services.', containerAddress: 'Container address', @@ -1055,7 +1085,6 @@ const message = { sortCreated: 'Newest', downloadsCount: 'Downloads', likes: 'Likes', - taskQueue: 'Download Queue', progress: 'Progress', localDownloaded: 'Downloaded', modelInfo: 'Model Details', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 695edc8a1..00ed9d4fa 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -1019,6 +1019,37 @@ const message = { validateImageAvailabilityHelper: 'Genera una imagen mínima antes de guardar y puede generar costes', }, model: { + modelCategory: 'Categoría del modelo', + modelName: 'Nombre del modelo', + modelArchitecture: 'Tipo de modelo', + backboneParams: 'Parámetros base de MoE', + activeParams: 'Parámetros activos', + engram: 'Engram', + weightFootprint: 'Tamaño de los pesos', + undisclosed: 'No divulgado', + featuredModels: 'Modelos destacados', + deploy: 'Desplegar', + approxWeightSize: 'Aprox. {0} GB', + services: 'Servicios de modelos', + addService: 'Añadir servicio de modelo', + addEngine: 'Añadir motor de inferencia', + onlineModel: 'Modelos en línea', + instanceDeployment: 'Despliegue por instancia', + nvidiaDeployment: 'Despliegue optimizado para NVIDIA', + engines: 'Motores de inferencia', + modelManagement: 'Gestión de modelos', + serviceDetails: 'Detalles del servicio', + deployments: 'Despliegues locales', + files: 'Archivos de modelos', + connectExternal: 'Conectar servicio externo', + deploymentTemplates: 'Plantillas de comandos de inicio', + engineProvider: 'Motor / Proveedor', + endpoint: 'Punto de conexión', + cloudAccount: 'Cuenta en la nube', + connectionStatus: 'Estado de conexión', + unverified: 'Sin verificar', + manage: 'Gestionar', + loadFailed: 'No se pudo cargar. Actualice la página e inténtelo de nuevo.', model: 'Modelo', localModel: 'Modelos locales', create_helper: 'Descargar "{0}"', @@ -1035,7 +1066,6 @@ const message = { vllmCommandPortHelper: 'El comando de inicio debe usar el puerto {0}; de lo contrario, no se podrá acceder al servicio.', ascendVisibleDevices: 'Dispositivos Ascend visibles (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Sincronizar con cuenta de modelo', modelAccountAddressHelper: 'La dirección del contenedor es para contenedores de agentes; 127.0.0.1, IP del sistema o dirección personalizada es para AI Gateway o servicios externos.', containerAddress: 'Dirección del contenedor', @@ -1058,7 +1088,6 @@ const message = { sortCreated: 'Más recientes', downloadsCount: 'Descargas', likes: 'Me gusta', - taskQueue: 'Cola de descargas', progress: 'Progreso', localDownloaded: 'Descargados', modelInfo: 'Detalles del modelo', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index c5862f365..2c3494bea 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -1002,6 +1002,37 @@ const message = { validateImageAvailabilityHelper: 'پیش از ذخیره یک تصویر حداقلی تولید می‌شود و ممکن است هزینه داشته باشد', }, model: { + modelCategory: 'دسته‌بندی مدل', + modelName: 'نام مدل', + modelArchitecture: 'نوع مدل', + backboneParams: 'پارامترهای پایه MoE', + activeParams: 'پارامترهای فعال', + engram: 'Engram', + weightFootprint: 'حجم وزن‌ها', + undisclosed: 'اعلام نشده', + featuredModels: 'مدل‌های برگزیده', + deploy: 'استقرار', + approxWeightSize: 'حدود {0} گیگابایت', + services: 'سرویس‌های مدل', + addService: 'افزودن سرویس مدل', + addEngine: 'افزودن موتور استنتاج', + onlineModel: 'مدل‌های آنلاین', + instanceDeployment: 'استقرار بر اساس نمونه', + nvidiaDeployment: 'استقرار بهینه‌شده برای NVIDIA', + engines: 'موتورهای استنتاج', + modelManagement: 'مدیریت مدل‌ها', + serviceDetails: 'جزئیات سرویس', + deployments: 'استقرارهای محلی', + files: 'فایل‌های مدل', + connectExternal: 'اتصال به سرویس خارجی', + deploymentTemplates: 'الگوهای فرمان راه‌اندازی', + engineProvider: 'موتور / ارائه‌دهنده', + endpoint: 'نقطه پایانی', + cloudAccount: 'حساب ابری', + connectionStatus: 'وضعیت اتصال', + unverified: 'تأیید نشده', + manage: 'مدیریت', + loadFailed: 'بارگذاری ناموفق بود. صفحه را تازه‌سازی کرده و دوباره تلاش کنید.', model: 'مدل‌ها', localModel: 'مدل‌های محلی', create_helper: 'دریافت "{0}"', @@ -1017,7 +1048,6 @@ const message = { vllmCommandPortHelper: 'فرمان راه‌اندازی باید از پورت {0} استفاده کند؛ در غیر این صورت سرویس قابل دسترسی نخواهد بود.', ascendVisibleDevices: 'دستگاه‌های قابل مشاهده Ascend (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'همگام‌سازی با حساب مدل', modelAccountAddressHelper: 'آدرس کانتینر برای کانتینرهای عامل است؛ 127.0.0.1، IP سیستم یا آدرس سفارشی برای دروازه AI یا خدمات خارجی است.', containerAddress: 'آدرس کانتینر', @@ -1040,7 +1070,6 @@ const message = { sortCreated: 'جدیدترین', downloadsCount: 'دانلودها', likes: 'لایک‌ها', - taskQueue: 'صف دانلود', progress: 'پیشرفت', localDownloaded: 'دانلود شده', modelInfo: 'جزئیات مدل', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 6d8ebf1a2..509e17dae 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -1006,6 +1006,37 @@ const message = { validateImageAvailabilityHelper: '保存前に最小画像を1枚生成するため、料金が発生する場合があります', }, model: { + modelCategory: 'モデルカテゴリ', + modelName: 'モデル名', + modelArchitecture: 'モデルの種類', + backboneParams: 'MoE バックボーンパラメータ数', + activeParams: 'アクティブパラメータ数', + engram: 'Engram', + weightFootprint: '重みのサイズ', + undisclosed: '非公開', + featuredModels: '注目のモデル', + deploy: 'デプロイ', + approxWeightSize: '約 {0} GB', + services: 'モデルサービス', + addService: 'モデルサービスを追加', + addEngine: '推論エンジンを追加', + onlineModel: 'オンラインモデル', + instanceDeployment: 'インスタンス単位でデプロイ', + nvidiaDeployment: 'NVIDIA 向け最適化デプロイ', + engines: '推論エンジン', + modelManagement: 'モデル管理', + serviceDetails: 'サービス詳細', + deployments: 'ローカルデプロイ', + files: 'モデルファイル', + connectExternal: '外部サービスに接続', + deploymentTemplates: '起動コマンドテンプレート', + engineProvider: 'エンジン / プロバイダー', + endpoint: 'エンドポイント', + cloudAccount: 'クラウドアカウント', + connectionStatus: '接続状態', + unverified: '未検証', + manage: '管理', + loadFailed: '読み込みに失敗しました。更新して再試行してください。', model: 'モデル', localModel: 'ローカルモデル', create_helper: 'を取得 "{0}"', @@ -1021,7 +1052,6 @@ const message = { vllmCommandPortHelper: '起動コマンドではポート {0} を使用する必要があります。使用しない場合、サービスにアクセスできません。', ascendVisibleDevices: 'Ascend 可視デバイス(ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'モデルアカウントに同期', modelAccountAddressHelper: 'コンテナアドレスはエージェントコンテナ向けです。127.0.0.1、システム IP、カスタムアドレスは AI Gateway または外部サービス向けです。', containerAddress: 'コンテナアドレス', @@ -1044,7 +1074,6 @@ const message = { sortCreated: '新規作成', downloadsCount: 'ダウンロード数', likes: 'いいね', - taskQueue: 'ダウンロードキュー', progress: '進捗', localDownloaded: 'ダウンロード済み', modelInfo: 'モデル詳細', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 4643d6cb9..10205091b 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -996,6 +996,37 @@ const message = { validateImageAvailabilityHelper: '저장 전에 최소 이미지 한 장을 생성하며 비용이 발생할 수 있습니다', }, model: { + modelCategory: '모델 카테고리', + modelName: '모델 이름', + modelArchitecture: '모델 유형', + backboneParams: 'MoE 백본 매개변수 수', + activeParams: '활성 매개변수 수', + engram: 'Engram', + weightFootprint: '가중치 크기', + undisclosed: '비공개', + featuredModels: '추천 모델', + deploy: '배포', + approxWeightSize: '약 {0} GB', + services: '모델 서비스', + addService: '모델 서비스 추가', + addEngine: '추론 엔진 추가', + onlineModel: '온라인 모델', + instanceDeployment: '인스턴스별 배포', + nvidiaDeployment: 'NVIDIA 최적화 배포', + engines: '추론 엔진', + modelManagement: '모델 관리', + serviceDetails: '서비스 상세 정보', + deployments: '로컬 배포', + files: '모델 파일', + connectExternal: '외부 서비스 연결', + deploymentTemplates: '시작 명령 템플릿', + engineProvider: '엔진 / 공급자', + endpoint: '엔드포인트', + cloudAccount: '클라우드 계정', + connectionStatus: '연결 상태', + unverified: '미검증', + manage: '관리', + loadFailed: '불러오지 못했습니다. 새로 고침 후 다시 시도하세요.', model: '모델', localModel: '로컬 모델', create_helper: '가져오기 "{0}"', @@ -1010,7 +1041,6 @@ const message = { vllmProfileVisionExp: 'DeepSeek V4 Flash Vision Exp', vllmCommandPortHelper: '시작 명령은 {0} 포트를 사용해야 하며, 그렇지 않으면 서비스에 접근할 수 없습니다.', ascendVisibleDevices: 'Ascend 표시 장치 (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: '모델 계정에 동기화', modelAccountAddressHelper: '컨테이너 주소는 에이전트 컨테이너 호출에 적합합니다. 127.0.0.1, 시스템 IP 또는 사용자 지정 주소는 AI Gateway 또는 외부 서비스 호출에 적합합니다.', containerAddress: '컨테이너 주소', @@ -1033,7 +1063,6 @@ const message = { sortCreated: '최신 생성', downloadsCount: '다운로드 수', likes: '좋아요', - taskQueue: '다운로드 대기열', progress: '진행률', localDownloaded: '다운로드됨', modelInfo: '모델 상세 정보', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index 2b9e893a9..8ccf38423 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -993,6 +993,37 @@ const message = { validateImageAvailabilityHelper: 'ສ້າງຮູບຂະໜາດນ້ອຍໜຶ່ງຮູບກ່ອນບັນທຶກ ແລະ ອາດມີຄ່າໃຊ້ຈ່າຍ', }, model: { + modelCategory: 'ໝວດໝູ່ໂມເດວ', + modelName: 'ຊື່ໂມເດວ', + modelArchitecture: 'ປະເພດໂມເດວ', + backboneParams: 'ພາຣາມິເຕີຫຼັກຂອງ MoE', + activeParams: 'ພາຣາມິເຕີທີ່ໃຊ້ງານ', + engram: 'Engram', + weightFootprint: 'ຂະໜາດນ້ຳໜັກ', + undisclosed: 'ບໍ່ເປີດເຜີຍ', + featuredModels: 'ໂມເດວແນະນຳ', + deploy: 'ນຳໃຊ້', + approxWeightSize: 'ປະມານ {0} GB', + services: 'ບໍລິການໂມເດວ', + addService: 'ເພີ່ມບໍລິການໂມເດວ', + addEngine: 'ເພີ່ມເຄື່ອງຈັກອະນຸມານ', + onlineModel: 'ໂມເດວອອນລາຍ', + instanceDeployment: 'ນຳໃຊ້ຕາມອິນສະແຕນ', + nvidiaDeployment: 'ການນຳໃຊ້ທີ່ປັບໃຫ້ເໝາະກັບ NVIDIA', + engines: 'ເຄື່ອງຈັກອະນຸມານ', + modelManagement: 'ຈັດການໂມເດວ', + serviceDetails: 'ລາຍລະອຽດບໍລິການ', + deployments: 'ການນຳໃຊ້ພາຍໃນເຄື່ອງ', + files: 'ໄຟລ໌ໂມເດວ', + connectExternal: 'ເຊື່ອມຕໍ່ບໍລິການພາຍນອກ', + deploymentTemplates: 'ແມ່ແບບຄຳສັ່ງເລີ່ມຕົ້ນ', + engineProvider: 'ເຄື່ອງຈັກ / ຜູ້ໃຫ້ບໍລິການ', + endpoint: 'ຈຸດເຊື່ອມຕໍ່', + cloudAccount: 'ບັນຊີຄລາວ', + connectionStatus: 'ສະຖານະການເຊື່ອມຕໍ່', + unverified: 'ຍັງບໍ່ໄດ້ຢືນຢັນ', + manage: 'ຈັດການ', + loadFailed: 'ໂຫຼດບໍ່ສຳເລັດ. ກະລຸນາໂຫຼດໜ້າຄືນແລ້ວລອງອີກຄັ້ງ.', model: 'ໂມເດວ', localModel: 'ໂມເດວໃນເຄື່ອງ', create_helper: 'ດຶງ (Pull) "{0}"', @@ -1007,7 +1038,6 @@ const message = { vllmProfileVisionExp: 'DeepSeek V4 Flash Vision Exp', vllmCommandPortHelper: 'ຄຳສັ່ງເລີ່ມຕົ້ນຕ້ອງໃຊ້ພອດ {0}; ບໍ່ດັ່ງນັ້ນຈະບໍ່ສາມາດເຂົ້າເຖິງບໍລິການໄດ້.', ascendVisibleDevices: 'ອຸປະກອນ Ascend ທີ່ເຫັນໄດ້ (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'ຊິ້ງຄ໌ໄປຍັງບັນຊີໂມເດວ', modelAccountAddressHelper: 'ທີ່ຢູ່ຄອນເທນເນີແມ່ນສຳລັບຄອນເທນເນີຕົວແທນ; 127.0.0.1, IP ລະບົບ, ຫຼື ທີ່ຢູ່ກຳນົດເອງແມ່ນສຳລັບ AI Gateway ຫຼື ບໍລິການພາຍນອກ.', containerAddress: 'ທີ່ຢູ່ຄອນເທນເນີ', @@ -1030,7 +1060,6 @@ const message = { sortCreated: 'ໃໝ່ລ່າສຸດ', downloadsCount: 'ດາວໂຫຼດ', likes: 'ຖືກໃຈ', - taskQueue: 'ຄິວດາວໂຫຼດ', progress: 'ຄວາມຄືບໜ້າ', localDownloaded: 'ດາວໂຫຼດແລ້ວ', modelInfo: 'ລາຍລະອຽດໂມເດວ', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 9ef15c9e7..8c4886008 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -1028,6 +1028,37 @@ const message = { validateImageAvailabilityHelper: 'Menjana satu imej minimum sebelum menyimpan dan mungkin dikenakan caj', }, model: { + modelCategory: 'Kategori model', + modelName: 'Nama model', + modelArchitecture: 'Jenis model', + backboneParams: 'Parameter teras MoE', + activeParams: 'Parameter aktif', + engram: 'Engram', + weightFootprint: 'Saiz pemberat', + undisclosed: 'Tidak didedahkan', + featuredModels: 'Model pilihan', + deploy: 'Kerahkan', + approxWeightSize: 'Kira-kira {0} GB', + services: 'Perkhidmatan model', + addService: 'Tambah perkhidmatan model', + addEngine: 'Tambah enjin inferens', + onlineModel: 'Model dalam talian', + instanceDeployment: 'Pengerahan mengikut instans', + nvidiaDeployment: 'Pengerahan dioptimumkan untuk NVIDIA', + engines: 'Enjin inferens', + modelManagement: 'Pengurusan model', + serviceDetails: 'Butiran perkhidmatan', + deployments: 'Pengerahan setempat', + files: 'Fail model', + connectExternal: 'Sambungkan perkhidmatan luaran', + deploymentTemplates: 'Templat arahan permulaan', + engineProvider: 'Enjin / Pembekal', + endpoint: 'Titik akhir', + cloudAccount: 'Akaun awan', + connectionStatus: 'Status sambungan', + unverified: 'Belum disahkan', + manage: 'Urus', + loadFailed: 'Gagal memuatkan. Muat semula dan cuba lagi.', model: 'Model', localModel: 'Model Tempatan', create_helper: 'Tarik "{0}"', @@ -1044,7 +1075,6 @@ const message = { vllmCommandPortHelper: 'Perintah permulaan mesti menggunakan port {0}; jika tidak, perkhidmatan tidak dapat diakses.', ascendVisibleDevices: 'Peranti Ascend boleh dilihat (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Segerakkan ke akaun model', modelAccountAddressHelper: 'Alamat kontena sesuai untuk kontena agen; 127.0.0.1, IP sistem, atau alamat tersuai sesuai untuk AI Gateway atau perkhidmatan luaran.', containerAddress: 'Alamat kontena', @@ -1067,7 +1097,6 @@ const message = { sortCreated: 'Terbaru dibuat', downloadsCount: 'Muat turun', likes: 'Suka', - taskQueue: 'Baris Gilir Muat Turun', progress: 'Kemajuan', localDownloaded: 'Dimuat turun', modelInfo: 'Butiran Model', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 1386e8e0f..9afb7875a 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -1023,6 +1023,37 @@ const message = { validateImageAvailabilityHelper: 'Gera uma imagem mínima antes de salvar e pode gerar custos', }, model: { + modelCategory: 'Categoria do modelo', + modelName: 'Nome do modelo', + modelArchitecture: 'Tipo de modelo', + backboneParams: 'Parâmetros base do MoE', + activeParams: 'Parâmetros ativos', + engram: 'Engram', + weightFootprint: 'Tamanho dos pesos', + undisclosed: 'Não divulgado', + featuredModels: 'Modelos em destaque', + deploy: 'Implantar', + approxWeightSize: 'Aprox. {0} GB', + services: 'Serviços de modelos', + addService: 'Adicionar serviço de modelo', + addEngine: 'Adicionar mecanismo de inferência', + onlineModel: 'Modelos online', + instanceDeployment: 'Implantação por instância', + nvidiaDeployment: 'Implantação otimizada para NVIDIA', + engines: 'Mecanismos de inferência', + modelManagement: 'Gerenciamento de modelos', + serviceDetails: 'Detalhes do serviço', + deployments: 'Implantações locais', + files: 'Arquivos de modelos', + connectExternal: 'Conectar serviço externo', + deploymentTemplates: 'Modelos de comandos de inicialização', + engineProvider: 'Mecanismo / Provedor', + endpoint: 'Endpoint', + cloudAccount: 'Conta na nuvem', + connectionStatus: 'Status da conexão', + unverified: 'Não verificado', + manage: 'Gerenciar', + loadFailed: 'Falha ao carregar. Atualize a página e tente novamente.', model: 'Modelo', localModel: 'Modelos locais', create_helper: 'Puxar "{0}"', @@ -1039,7 +1070,6 @@ const message = { vllmCommandPortHelper: 'O comando de inicialização deve usar a porta {0}; caso contrário, o serviço ficará inacessível.', ascendVisibleDevices: 'Dispositivos Ascend visíveis (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Sincronizar com conta de modelo', modelAccountAddressHelper: 'Use o endereço do contêiner para agentes; 127.0.0.1, IP do sistema ou endereço personalizado para AI Gateway ou serviços externos.', containerAddress: 'Endereço do contêiner', @@ -1062,7 +1092,6 @@ const message = { sortCreated: 'Criados recentemente', downloadsCount: 'Downloads', likes: 'Curtidas', - taskQueue: 'Fila de downloads', progress: 'Progresso', localDownloaded: 'Baixados', modelInfo: 'Detalhes do modelo', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index e13aaa2eb..8400f0e9b 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -1017,6 +1017,37 @@ const message = { 'Перед сохранением создаётся одно минимальное изображение; возможна оплата', }, model: { + modelCategory: 'Категория модели', + modelName: 'Название модели', + modelArchitecture: 'Тип модели', + backboneParams: 'Параметры основы MoE', + activeParams: 'Активные параметры', + engram: 'Engram', + weightFootprint: 'Размер весов', + undisclosed: 'Не раскрыто', + featuredModels: 'Рекомендуемые модели', + deploy: 'Развернуть', + approxWeightSize: 'Около {0} ГБ', + services: 'Сервисы моделей', + addService: 'Добавить сервис модели', + addEngine: 'Добавить движок инференса', + onlineModel: 'Онлайн-модели', + instanceDeployment: 'Развертывание по экземплярам', + nvidiaDeployment: 'Развертывание с оптимизацией для NVIDIA', + engines: 'Движки инференса', + modelManagement: 'Управление моделями', + serviceDetails: 'Сведения о сервисе', + deployments: 'Локальные развертывания', + files: 'Файлы моделей', + connectExternal: 'Подключить внешний сервис', + deploymentTemplates: 'Шаблоны команд запуска', + engineProvider: 'Движок / Поставщик', + endpoint: 'Конечная точка', + cloudAccount: 'Облачная учетная запись', + connectionStatus: 'Состояние подключения', + unverified: 'Не проверено', + manage: 'Управление', + loadFailed: 'Не удалось загрузить. Обновите страницу и повторите попытку.', model: 'Модель', localModel: 'Локальные модели', create_helper: 'Загрузить "{0}"', @@ -1032,7 +1063,6 @@ const message = { vllmProfileVisionExp: 'DeepSeek V4 Flash Vision Exp', vllmCommandPortHelper: 'Команда запуска должна использовать порт {0}, иначе сервис будет недоступен.', ascendVisibleDevices: 'Видимые устройства Ascend (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Синхронизировать с аккаунтом модели', modelAccountAddressHelper: 'Адрес контейнера подходит для контейнеров агентов; 127.0.0.1, системный IP или пользовательский адрес подходит для AI Gateway или внешних сервисов.', containerAddress: 'Адрес контейнера', @@ -1055,7 +1085,6 @@ const message = { sortCreated: 'Недавно создано', downloadsCount: 'Загрузки', likes: 'Лайки', - taskQueue: 'Очередь загрузок', progress: 'Прогресс', localDownloaded: 'Загружено', modelInfo: 'Сведения о модели', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 94483c987..420df9647 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -1027,6 +1027,37 @@ const message = { validateImageAvailabilityHelper: 'Kaydetmeden önce bir küçük görsel üretir ve ücret doğurabilir', }, model: { + modelCategory: 'Model kategorisi', + modelName: 'Model adı', + modelArchitecture: 'Model türü', + backboneParams: 'MoE omurga parametreleri', + activeParams: 'Etkin parametreler', + engram: 'Engram', + weightFootprint: 'Ağırlık boyutu', + undisclosed: 'Açıklanmadı', + featuredModels: 'Öne çıkan modeller', + deploy: 'Dağıt', + approxWeightSize: 'Yaklaşık {0} GB', + services: 'Model hizmetleri', + addService: 'Model hizmeti ekle', + addEngine: 'Çıkarım motoru ekle', + onlineModel: 'Çevrimiçi modeller', + instanceDeployment: 'Örnek bazında dağıtım', + nvidiaDeployment: 'NVIDIA için optimize edilmiş dağıtım', + engines: 'Çıkarım motorları', + modelManagement: 'Model yönetimi', + serviceDetails: 'Hizmet ayrıntıları', + deployments: 'Yerel dağıtımlar', + files: 'Model dosyaları', + connectExternal: 'Harici hizmete bağlan', + deploymentTemplates: 'Başlatma komutu şablonları', + engineProvider: 'Motor / Sağlayıcı', + endpoint: 'Uç nokta', + cloudAccount: 'Bulut hesabı', + connectionStatus: 'Bağlantı durumu', + unverified: 'Doğrulanmadı', + manage: 'Yönet', + loadFailed: 'Yüklenemedi. Yenileyip tekrar deneyin.', model: 'Model', localModel: 'Yerel Modeller', create_helper: '"{0}" çek', @@ -1043,7 +1074,6 @@ const message = { vllmCommandPortHelper: 'Başlatma komutu {0} numaralı bağlantı noktasını kullanmalıdır; aksi halde hizmete erişilemez.', ascendVisibleDevices: 'Görünür Ascend cihazları (ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: 'Model hesabına senkronize et', modelAccountAddressHelper: 'Konteyner adresi ajan konteynerleri içindir; 127.0.0.1, sistem IP veya özel adres AI Gateway ya da harici servisler içindir.', containerAddress: 'Konteyner adresi', @@ -1066,7 +1096,6 @@ const message = { sortCreated: 'Yeni oluşturulanlar', downloadsCount: 'İndirmeler', likes: 'Beğeniler', - taskQueue: 'İndirme Kuyruğu', progress: 'İlerleme', localDownloaded: 'İndirilenler', modelInfo: 'Model ayrıntıları', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index e94a5a616..7e0b33557 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -959,6 +959,37 @@ const message = { validateImageAvailabilityHelper: '儲存前會實際產生一張最小圖片,可能產生費用', }, model: { + modelCategory: '模型類別', + modelName: '模型名稱', + modelArchitecture: '模型類型', + backboneParams: 'MoE 骨幹參數', + activeParams: '啟用參數', + engram: 'Engram', + weightFootprint: '權重體積', + undisclosed: '未公開', + featuredModels: '精選模型', + deploy: '部署', + approxWeightSize: '約 {0} GB', + services: '模型服務', + addService: '新增模型服務', + addEngine: '新增推理引擎', + onlineModel: '線上模型', + instanceDeployment: '按執行個體部署', + nvidiaDeployment: 'NVIDIA 最佳化部署', + engines: '推理引擎', + modelManagement: '模型管理', + serviceDetails: '服務詳情', + deployments: '本機部署', + files: '模型檔案', + connectExternal: '接入外部服務', + deploymentTemplates: '啟動命令範本', + engineProvider: '引擎 / 供應商', + endpoint: '端點', + cloudAccount: '雲端帳號', + connectionStatus: '連線狀態', + unverified: '未驗證', + manage: '管理', + loadFailed: '載入失敗,請重新整理後重試', model: '模型', localModel: '本地模型', create_helper: '拉取 "{0}"', @@ -973,7 +1004,6 @@ const message = { vllmProfileVisionExp: 'DeepSeek V4 Flash Vision Exp', vllmCommandPortHelper: '啟動命令必須使用 {0} 連接埠,否則服務將無法存取。', ascendVisibleDevices: 'Ascend 可見裝置(ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: '同步到模型帳號', modelAccountAddressHelper: '容器地址適合智能體容器呼叫;127.0.0.1、本機 IP 或自訂地址適合 AI 閘道或外部服務呼叫。', containerAddress: '容器地址', @@ -995,7 +1025,6 @@ const message = { sortCreated: '最新建立', downloadsCount: '下載量', likes: '點讚', - taskQueue: '下載佇列', progress: '進度', localDownloaded: '已下載', modelInfo: '模型詳情', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 5d9858eee..bc7289603 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -972,6 +972,37 @@ const message = { validateImageAvailabilityHelper: '保存前会真实生成一张最小图片,可能产生费用', }, model: { + modelCategory: '模型类别', + modelName: '模型名称', + modelArchitecture: '模型类型', + backboneParams: 'MoE 骨干参数', + activeParams: '激活参数', + engram: 'Engram', + weightFootprint: '权重体积', + undisclosed: '未公开', + featuredModels: '精选模型', + deploy: '部署', + approxWeightSize: '约 {0} GB', + services: '模型服务', + addService: '添加模型服务', + addEngine: '添加推理引擎', + onlineModel: '在线模型', + instanceDeployment: '按实例部署', + nvidiaDeployment: 'NVIDIA 优化部署', + engines: '推理引擎', + modelManagement: '模型管理', + serviceDetails: '服务详情', + deployments: '本地部署', + files: '模型文件', + connectExternal: '接入外部服务', + deploymentTemplates: '启动命令模板', + engineProvider: '引擎 / 供应商', + endpoint: '端点', + cloudAccount: '云端账号', + connectionStatus: '连接状态', + unverified: '未验证', + manage: '管理', + loadFailed: '加载失败,请刷新重试', model: '模型', localModel: '本地模型', create_helper: '拉取 "{0}"', @@ -986,7 +1017,6 @@ const message = { vllmProfileVisionExp: 'DeepSeek V4 Flash Vision Exp', vllmCommandPortHelper: '启动命令必须使用 {0} 端口,否则服务将无法访问。', ascendVisibleDevices: 'Ascend 可见设备(ASCEND_RT_VISIBLE_DEVICES)', - syncModelAccount: '同步到模型账号', modelAccountAddressHelper: '容器地址适合智能体容器调用;127.0.0.1、本机 IP 或自定义地址适合 AI 网关或外部服务调用。', containerAddress: '容器地址', @@ -1008,7 +1038,6 @@ const message = { sortCreated: '最新创建', downloadsCount: '下载量', likes: '点赞', - taskQueue: '下载队列', progress: '进度', localDownloaded: '已下载', modelInfo: '模型详情', diff --git a/frontend/src/routers/modules/ai.ts b/frontend/src/routers/modules/ai.ts index 9fd582635..5077c1f6d 100644 --- a/frontend/src/routers/modules/ai.ts +++ b/frontend/src/routers/modules/ai.ts @@ -11,16 +11,6 @@ const aiRouter = { title: 'menu.aiTools', }, children: [ - { - path: '/ai/agents/agent', - name: 'Agents', - component: () => import('@/views/ai/agents/agent/index.vue'), - meta: { - icon: 'p-jiqiren2', - title: 'aiTools.agents.agent', - permission: 'ai_agent_view', - }, - }, { path: '/ai/model/account', name: 'AIModel', @@ -37,11 +27,32 @@ const aiRouter = { name: 'LocalModel', component: () => import('@/views/ai/model/index.vue'), meta: { - title: 'aiTools.model.localModel', + title: 'aiTools.model.deployments', activeMenu: '/ai/model/account', permission: 'ai_model_view', }, }, + { + path: '/ai/model/files', + hidden: true, + name: 'ModelFiles', + component: () => import('@/views/ai/model/index.vue'), + meta: { + title: 'aiTools.model.files', + activeMenu: '/ai/model/account', + permission: 'ai_model_view', + }, + }, + { + path: '/ai/agents/agent', + name: 'Agents', + component: () => import('@/views/ai/agents/agent/index.vue'), + meta: { + icon: 'p-jiqiren2', + title: 'aiTools.agents.agent', + permission: 'ai_agent_view', + }, + }, { path: '/ai/mcp', name: 'MCPServer', diff --git a/frontend/src/utils/agent-provider-logo.ts b/frontend/src/utils/agent-provider-logo.ts index cb0bde4a9..e7cc96b28 100644 --- a/frontend/src/utils/agent-provider-logo.ts +++ b/frontend/src/utils/agent-provider-logo.ts @@ -28,6 +28,14 @@ const volcengineLogo: AgentProviderLogo = { }; const providerLogos: Record = { + nvidia: { + src: asset('nvidia.ico'), + mark: 'NV', + background: '#ffffff', + color: '#76b900', + borderColor: '#dcdfe6', + source: 'https://www.nvidia.com/favicon.ico', + }, ollama: { src: asset('ollama.webp'), mark: 'OL', diff --git a/frontend/src/utils/app.ts b/frontend/src/utils/app.ts index aae22f57f..6bd854e74 100644 --- a/frontend/src/utils/app.ts +++ b/frontend/src/utils/app.ts @@ -38,6 +38,9 @@ export const jumpToInstall = (type: string, key: string) => { }, }); return true; + case 'ollama': + router.push({ path: '/ai/model/local', query: { engine: 'ollama', uncached: 'true', open: 'create' } }); + return true; case 'vllm': if (globalStore.isProductPro) { router.push({ diff --git a/frontend/src/views/ai/agents/agent/add/index.vue b/frontend/src/views/ai/agents/agent/add/index.vue index 2482663e1..7227def47 100644 --- a/frontend/src/views/ai/agents/agent/add/index.vue +++ b/frontend/src/views/ai/agents/agent/add/index.vue @@ -156,7 +156,7 @@ import { } from '@/utils/agent'; import { App } from '@/api/interface/app'; import AdvancedSetting from '@/components/advanced-setting/index.vue'; -import AccountAddDialog from '@/views/ai/agents/model/add/index.vue'; +import AccountAddDialog from '@/views/ai/model/components/account-form/index.vue'; import { useGlobalStore } from '@/composables/useGlobalStore'; import i18n from '@/lang'; diff --git a/frontend/src/views/ai/agents/model/index.vue b/frontend/src/views/ai/agents/model/index.vue deleted file mode 100644 index c18031415..000000000 --- a/frontend/src/views/ai/agents/model/index.vue +++ /dev/null @@ -1,221 +0,0 @@ - - - - - diff --git a/frontend/src/views/ai/model/components/account-address/index.vue b/frontend/src/views/ai/model/components/account-address/index.vue new file mode 100644 index 000000000..f9070da68 --- /dev/null +++ b/frontend/src/views/ai/model/components/account-address/index.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/frontend/src/views/ai/agents/model/add/index.vue b/frontend/src/views/ai/model/components/account-form/index.vue similarity index 97% rename from frontend/src/views/ai/agents/model/add/index.vue rename to frontend/src/views/ai/model/components/account-form/index.vue index f955e83da..ecb3f7d88 100644 --- a/frontend/src/views/ai/agents/model/add/index.vue +++ b/frontend/src/views/ai/model/components/account-form/index.vue @@ -1,5 +1,10 @@ diff --git a/frontend/src/views/ai/model/ollama/operate/index.vue b/frontend/src/views/ai/model/ollama/operate/index.vue new file mode 100644 index 000000000..b4310c09a --- /dev/null +++ b/frontend/src/views/ai/model/ollama/operate/index.vue @@ -0,0 +1,113 @@ + + + diff --git a/frontend/src/views/ai/model/ollama/terminal/index.vue b/frontend/src/views/ai/model/ollama/terminal/index.vue index 1fb15f94e..ac1110f55 100644 --- a/frontend/src/views/ai/model/ollama/terminal/index.vue +++ b/frontend/src/views/ai/model/ollama/terminal/index.vue @@ -1,13 +1,6 @@ diff --git a/frontend/src/views/app-store/apps/index.vue b/frontend/src/views/app-store/apps/index.vue index a1ef3fb2b..5acc99476 100644 --- a/frontend/src/views/app-store/apps/index.vue +++ b/frontend/src/views/app-store/apps/index.vue @@ -258,7 +258,9 @@ onMounted(async () => { key: installKey.value, }, }; - installRef.value.acceptParams(params); + if (!['ollama', 'vllm'].includes(installKey.value) || !jumpToInstall('', installKey.value)) { + installRef.value.acceptParams(params); + } } search(req); if (isProductPro.value) { diff --git a/frontend/src/views/app-store/detail/form/index.vue b/frontend/src/views/app-store/detail/form/index.vue index c4a962d85..fbe1488af 100644 --- a/frontend/src/views/app-store/detail/form/index.vue +++ b/frontend/src/views/app-store/detail/form/index.vue @@ -48,6 +48,8 @@ :propStart="'params.'" /> + + @@ -320,19 +322,23 @@ const loadInstallDefaultConfig = async () => { } }; -const initForm = async (appKey: string) => { +const initForm = async (appKey: string, allowPort?: boolean) => { operateNode.value = undefined; env.value = undefined; masterNodeAddr.value = undefined; formData.value.name = appKey.replace(/^local/, ''); - await loadInstallDefaultConfig(); + if (allowPort === undefined) { + await loadInstallDefaultConfig(); + } else { + formData.value.allowPort = allowPort; + } const res = await getAppByKey(appKey); currentApp.value = res.data; appVersions.value = currentApp.value.versions; if (appVersions.value.length > 0) { const defaultVersion = appVersions.value[0]; formData.value.version = defaultVersion; - getVersionDetail(defaultVersion); + await getVersionDetail(defaultVersion); } if (isOffline.value) { formData.value.pullImage = false; diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index e2e209fba..e80bea076 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -178,72 +178,38 @@ >