From 93ebc6a8b92006a0dda5006db1b7d87fcc8fa034 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Fri, 30 Oct 2026 23:50:11 +0800 Subject: [PATCH] feat(ai): streamline Ollama model pool management (#14259) --- agent/app/dto/agents.go | 6 +- agent/app/service/agents.go | 76 ++++++++++++++ agent/app/service/agents_local.go | 98 +++++++++++++++++++ agent/app/service/agents_utils.go | 8 ++ agent/app/service/ai.go | 42 ++++---- frontend/src/api/interface/ai.ts | 2 + frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/es-es.ts | 3 + frontend/src/lang/modules/fa.ts | 2 + frontend/src/lang/modules/ja.ts | 2 + frontend/src/lang/modules/ko.ts | 2 + frontend/src/lang/modules/lo.ts | 2 + frontend/src/lang/modules/ms.ts | 3 + frontend/src/lang/modules/pt-br.ts | 3 + frontend/src/lang/modules/ru.ts | 3 + frontend/src/lang/modules/tr.ts | 2 + frontend/src/lang/modules/zh-Hant.ts | 2 + frontend/src/lang/modules/zh.ts | 2 + .../ai/model/components/model-pool/index.vue | 73 ++++++++++---- .../src/views/ai/model/ollama/add/index.vue | 12 ++- 20 files changed, 305 insertions(+), 41 deletions(-) diff --git a/agent/app/dto/agents.go b/agent/app/dto/agents.go index 5cac7ece8..a218c8618 100644 --- a/agent/app/dto/agents.go +++ b/agent/app/dto/agents.go @@ -318,6 +318,7 @@ type AgentAccountModelDiscoverReq struct { } type AgentAccountModelCreateReq struct { + TaskID string `json:"taskID"` AccountID uint `json:"accountId" validate:"required"` Model AgentAccountModel `json:"model" validate:"required"` } @@ -328,8 +329,9 @@ type AgentAccountModelUpdateReq struct { } type AgentAccountModelDeleteReq struct { - AccountID uint `json:"accountId" validate:"required"` - RecordID uint `json:"recordId" validate:"required"` + DeleteFiles bool `json:"deleteFiles"` + AccountID uint `json:"accountId" validate:"required"` + RecordID uint `json:"recordId" validate:"required"` } type AgentAccountCreateReq struct { diff --git a/agent/app/service/agents.go b/agent/app/service/agents.go index 9796114d7..13cdfbcae 100644 --- a/agent/app/service/agents.go +++ b/agent/app/service/agents.go @@ -1298,6 +1298,31 @@ func (a AgentService) CreateAccountModel(req dto.AgentAccountModelCreateReq) err if _, ok := findAgentAccountModelForProvider(account.Provider, models, nextModel.ID); ok { return buserr.New("ErrRecordExist") } + if account.Provider == "ollama" { + if account.AppInstallID != 0 { + install, err := appInstallRepo.GetFirst(repo.WithByID(account.AppInstallID)) + if err != nil { + return err + } + if install.App.Key != "ollama" || !install.SyncModelAccount { + return buserr.New("ErrAgentAccountUnavailable") + } + localModels, err := aiRepo.List() + if err != nil { + return err + } + for _, item := range localModels { + if sameProviderModelID("ollama", item.Name, nextModel.ID) { + return (&AIToolService{}).Recreate(dto.OllamaModelName{Name: item.Name, TaskID: req.TaskID}) + } + } + return (&AIToolService{}).Create(dto.OllamaModelName{Name: nextModel.ID, TaskID: req.TaskID}) + } + nextModel.ID, err = resolveExistingOllamaModel(account, nextModel.ID) + if err != nil { + return err + } + } sortOrder := len(models) + 1 record := &model.AgentAccountModel{ AccountID: account.ID, @@ -1328,6 +1353,15 @@ func (a AgentService) UpdateAccountModel(req dto.AgentAccountModelUpdateReq) err if err != nil { return err } + if account.Provider == "ollama" && !sameProviderModelID("ollama", record.Model, nextModel.ID) { + if account.AppInstallID != 0 { + return buserr.New("ErrInvalidParams") + } + nextModel.ID, err = resolveExistingOllamaModel(account, nextModel.ID) + if err != nil { + return err + } + } nextModel.RecordID = req.Model.RecordID for _, item := range models { if item.RecordID == req.Model.RecordID { @@ -1366,6 +1400,10 @@ func (a AgentService) UpdateAccountModel(req dto.AgentAccountModelUpdateReq) err } func (a AgentService) DeleteAccountModel(req dto.AgentAccountModelDeleteReq) error { + ollamaModelMu.Lock() + defer ollamaModelMu.Unlock() + agentAccountMutationMu.Lock() + defer agentAccountMutationMu.Unlock() account, err := agentAccountRepo.GetFirst(repo.WithByID(req.AccountID)) if err != nil { return err @@ -1391,6 +1429,44 @@ func (a AgentService) DeleteAccountModel(req dto.AgentAccountModelDeleteReq) err if err := ensureAccountModelsNotBound(account, nextModels); err != nil { return err } + if req.DeleteFiles && account.Provider != "ollama" { + return buserr.New("ErrAgentProviderNotSupported") + } + if req.DeleteFiles { + if account.AppInstallID != 0 { + install, err := appInstallRepo.GetFirst(repo.WithByID(account.AppInstallID)) + if err != nil { + return err + } + if install.App.Key != "ollama" { + return buserr.New("ErrAgentAccountUnavailable") + } + localModels, err := aiRepo.List() + if err != nil { + return err + } + localIDs := make([]uint, 0) + for _, item := range localModels { + if !sameProviderModelID("ollama", item.Name, record.Model) { + continue + } + if item.Status == constant.StatusWaiting { + return buserr.New("TaskIsExecuting") + } + localIDs = append(localIDs, item.ID) + } + if err := cmd.NewCommandMgr().Run("docker", "exec", install.ContainerName, "ollama", "rm", record.Model); err != nil { + return err + } + if len(localIDs) > 0 { + if err := aiRepo.Delete(repo.WithByIDs(localIDs)); err != nil { + return err + } + } + } else if err := deleteRemoteOllamaModel(account, record.Model); err != nil { + return err + } + } if err := agentAccountModelRepo.DeleteByID(req.RecordID); err != nil { return err } diff --git a/agent/app/service/agents_local.go b/agent/app/service/agents_local.go index 885acd0c4..090cd5b84 100644 --- a/agent/app/service/agents_local.go +++ b/agent/app/service/agents_local.go @@ -1,13 +1,19 @@ package service import ( + "bytes" + "encoding/json" "errors" "fmt" + "net/http" "strings" + "time" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/app/model" + providercatalog "github.com/1Panel-dev/1Panel/agent/app/provider" "github.com/1Panel-dev/1Panel/agent/app/repo" + "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai" @@ -136,6 +142,62 @@ func syncOllamaModelAccount(install model.AppInstall, baseURL string, updateBase return err } +func updateOllamaModelPool(modelName string, remove bool) error { + install, err := appInstallRepo.LoadInstallAppByKeyAndName("ollama", "") + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil + } + if err != nil { + return err + } + if !install.SyncModelAccount { + return nil + } + agentAccountMutationMu.Lock() + defer agentAccountMutationMu.Unlock() + account, err := agentAccountRepo.GetFirst(repo.WithByAppInstallID(install.ID), repo.WithByProvider("ollama")) + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil + } + if err != nil { + return err + } + models, err := loadAgentAccountModels(account) + if err != nil { + return err + } + if remove { + for _, item := range models { + if !sameProviderModelID("ollama", item.ID, modelName) { + continue + } + if err := agentAccountModelRepo.DeleteByID(item.RecordID); err != nil { + return err + } + } + if sameProviderModelID("ollama", account.VerifyModel, modelName) { + account.VerifyModel = "" + if err := agentAccountRepo.Save(account); err != nil { + return err + } + } + if err := compactPersistedAgentAccountModelSortOrder(account.ID); err != nil { + return err + } + } else { + if _, exists := findAgentAccountModelForProvider("ollama", models, modelName); exists { + return nil + } + record := &model.AgentAccountModel{AccountID: account.ID, Model: modelName, Name: modelName, SortOrder: len(models) + 1} + if err := agentAccountModelRepo.Create(record); err != nil { + return err + } + } + terminalai.InvalidateTerminalRuntimeCache() + terminalai.InvalidateFileAIRuntimeCache() + return nil +} + func loadOllamaModelAccountAddress(install model.AppInstall) (string, string, error) { addressType := install.ModelAccountBaseURLType if addressType == "" { @@ -200,3 +262,39 @@ func ResolveLocalModelAccountBaseURL(addressType, customURL, containerName, cont return fmt.Sprintf("http://%s:%s/v1", containerName, containerPort), nil } } + +func deleteRemoteOllamaModel(account *model.AgentAccount, modelName string) error { + body, err := json.Marshal(map[string]string{"model": modelName}) + if err != nil { + return err + } + baseURL := strings.TrimSuffix(strings.TrimRight(account.BaseURL, "/"), "/v1") + req, err := http.NewRequest(http.MethodDelete, baseURL+"/api/delete", bytes.NewReader(body)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Bearer "+account.APIKey) + resp, err := (&http.Client{Timeout: 30 * time.Second}).Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + return fmt.Errorf("delete Ollama model failed: %s", resp.Status) + } + return nil +} + +func resolveExistingOllamaModel(account *model.AgentAccount, modelID string) (string, error) { + available, err := providercatalog.DiscoverModels(account.BaseURL, account.APIKey) + if err != nil { + return "", buserr.WithErr("ErrAgentAccountUnavailable", err) + } + for _, id := range available { + if sameProviderModelID("ollama", id, modelID) { + return id, nil + } + } + return "", buserr.New("ErrRecordNotFound") +} diff --git a/agent/app/service/agents_utils.go b/agent/app/service/agents_utils.go index c2f1119d5..518340e5d 100644 --- a/agent/app/service/agents_utils.go +++ b/agent/app/service/agents_utils.go @@ -1517,6 +1517,14 @@ func sameProviderModelID(provider, left, right string) bool { } leftComparable := providercatalog.NormalizeModelID(provider, leftTrimmed) rightComparable := providercatalog.NormalizeModelID(provider, rightTrimmed) + if provider == "ollama" { + if leftComparable != "" && !strings.Contains(path.Base(leftComparable), ":") { + leftComparable += ":latest" + } + if rightComparable != "" && !strings.Contains(path.Base(rightComparable), ":") { + rightComparable += ":latest" + } + } return leftComparable != "" && leftComparable == rightComparable } diff --git a/agent/app/service/ai.go b/agent/app/service/ai.go index f8bb0f5c5..3bab2d784 100644 --- a/agent/app/service/ai.go +++ b/agent/app/service/ai.go @@ -117,6 +117,7 @@ func (u *AIToolService) Create(req dto.OllamaModelName) error { } taskItem, err := task.NewTaskWithOps(fmt.Sprintf("ollama-model-%s", req.Name), task.TaskPull, task.TaskScopeAI, req.TaskID, info.ID) if err != nil { + _ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) global.LOG.Errorf("new task for exec shell failed, err: %v", err) return err } @@ -126,19 +127,17 @@ func (u *AIToolService) Create(req dto.OllamaModelName) error { }, nil) taskItem.AddSubTask(i18n.GetWithName("OllamaModelSize", req.Name), func(t *task.Task) error { itemSize, err := loadModelSize(info.Name, containerName) - if len(itemSize) != 0 { - _ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize}) - } else { - _ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + if err != nil { + return err } - return nil + return aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize}) + }, nil) + taskItem.AddSubTask(i18n.GetMsgByKey("TaskSync"), func(t *task.Task) error { + return updateOllamaModelPool(info.Name, false) }, nil) 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 } @@ -167,6 +166,9 @@ func (u *AIToolService) Recreate(req dto.OllamaModelName) error { if modelInfo.ID == 0 { return buserr.New("ErrRecordNotFound") } + if modelInfo.Status == constant.StatusWaiting { + return buserr.New("TaskIsExecuting") + } containerName, err := LoadContainerName() if err != nil { return err @@ -176,6 +178,7 @@ func (u *AIToolService) Recreate(req dto.OllamaModelName) error { } taskItem, err := task.NewTaskWithOps(fmt.Sprintf("ollama-model-%s", req.Name), task.TaskPull, task.TaskScopeAI, req.TaskID, modelInfo.ID) if err != nil { + _ = aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) global.LOG.Errorf("new task for exec shell failed, err: %v", err) return err } @@ -185,19 +188,17 @@ func (u *AIToolService) Recreate(req dto.OllamaModelName) error { }, nil) taskItem.AddSubTask(i18n.GetWithName("OllamaModelSize", req.Name), func(t *task.Task) error { itemSize, err := loadModelSize(modelInfo.Name, containerName) - if len(itemSize) != 0 { - _ = aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize}) - } else { - _ = aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()}) + if err != nil { + return err } - return nil + return aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize}) + }, nil) + taskItem.AddSubTask(i18n.GetMsgByKey("TaskSync"), func(t *task.Task) error { + return updateOllamaModelPool(modelInfo.Name, false) }, nil) 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 } @@ -219,11 +220,16 @@ func (u *AIToolService) Delete(req dto.ForceDelete) error { return fmt.Errorf("handle ollama rm %s failed, %v", item.Name, err) } } - _ = aiRepo.Delete(repo.WithByID(item.ID)) + if err := aiRepo.Delete(repo.WithByID(item.ID)); err != nil { + return err + } + if err := updateOllamaModelPool(item.Name, true); err != nil { + return err + } logItem := path.Join(global.Dir.DataDir, "log", "AITools", item.Name) _ = os.Remove(logItem) } - return SyncOllamaModelAccount(false) + return nil } func (u *AIToolService) SyncAccount(req dto.OllamaModelAccountSync) error { diff --git a/frontend/src/api/interface/ai.ts b/frontend/src/api/interface/ai.ts index 5100e601f..8e6fd205b 100644 --- a/frontend/src/api/interface/ai.ts +++ b/frontend/src/api/interface/ai.ts @@ -677,6 +677,7 @@ export namespace AI { } export interface AgentAccountModelCreateReq { + taskID?: string; accountId: number; model: AgentAccountModel; } @@ -687,6 +688,7 @@ export namespace AI { } export interface AgentAccountModelDeleteReq { + deleteFiles?: boolean; accountId: number; recordId: number; } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index ba78691a0..5d81e7c92 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -844,6 +844,9 @@ const message = { discoverModelsFailedUseDefaults: 'Failed to get models. Default models are being used.', accountModelsDuplicate: 'Duplicate models were found in the catalog', modelPool: 'Model Pool', + ollamaRegisterOnly: + 'Only register models already available on this Ollama service. No download will be started.', + deleteModelFiles: 'Also delete model files from the Ollama service', fallbackModels: 'Fallback Models', addFallbackModel: 'Add Fallback Model', fallbackModelsEmpty: 'No fallback models configured', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 2b41b80ee..270c85477 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -849,6 +849,9 @@ const message = { 'No se pudieron obtener los modelos. Se usarán los modelos predeterminados.', accountModelsDuplicate: 'Existen modelos duplicados en el catálogo', modelPool: 'Pool de modelos', + ollamaRegisterOnly: + 'Solo se registran modelos ya disponibles en este servicio Ollama. No se iniciará ninguna descarga.', + deleteModelFiles: 'Eliminar también los archivos del modelo del servicio Ollama', fallbackModels: 'Modelos de respaldo', addFallbackModel: 'Agregar modelo de respaldo', fallbackModelsEmpty: 'No hay modelos de respaldo configurados', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index b86d16aa5..b6d3c4585 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -839,6 +839,8 @@ const message = { discoverModelsFailedUseDefaults: 'دریافت مدل‌ها ناموفق بود. از مدل‌های پیش‌فرض استفاده می‌شود.', accountModelsDuplicate: 'مدل‌های تکراری در کاتالوگ یافت شد', modelPool: 'مجموعه مدل‌ها', + ollamaRegisterOnly: 'فقط مدل‌های موجود در این سرویس Ollama ثبت می‌شوند. دانلودی آغاز نخواهد شد.', + deleteModelFiles: 'فایل‌های مدل نیز از سرویس Ollama حذف شوند', fallbackModels: 'مدل‌های جایگزین', addFallbackModel: 'افزودن مدل جایگزین', fallbackModelsEmpty: 'هیچ مدل جایگزینی پیکربندی نشده است', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index e6c505574..e45e1da2b 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -843,6 +843,8 @@ const message = { discoverModelsFailedUseDefaults: 'モデルを取得できませんでした。デフォルトモデルを使用しています。', accountModelsDuplicate: 'カタログに重複したモデルがあります', modelPool: 'モデルプール', + ollamaRegisterOnly: 'この Ollama サービスに存在するモデルのみを登録します。ダウンロードは開始されません。', + deleteModelFiles: 'Ollama サービス上のモデルファイルも削除する', fallbackModels: 'フォールバックモデル', addFallbackModel: 'フォールバックモデルを追加', fallbackModelsEmpty: 'フォールバックモデルは未設定です', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 7fd7cf28c..6627603c5 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -833,6 +833,8 @@ const message = { discoverModelsFailedUseDefaults: '모델을 가져오지 못했습니다. 기본 모델을 사용합니다.', accountModelsDuplicate: '카탈로그에 중복된 모델이 있습니다', modelPool: '모델 풀', + ollamaRegisterOnly: '이 Ollama 서비스에 이미 있는 모델만 등록합니다. 다운로드는 시작되지 않습니다.', + deleteModelFiles: 'Ollama 서비스의 모델 파일도 삭제', fallbackModels: '폴백 모델', addFallbackModel: '폴백 모델 추가', fallbackModelsEmpty: '구성된 폴백 모델이 없습니다', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index efcbda156..fee995160 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -831,6 +831,8 @@ const message = { discoverModelsFailedUseDefaults: 'ດຶງລາຍການໂມເດວບໍ່ສຳເລັດ. ກຳລັງໃຊ້ໂມເດວເລີ່ມຕົ້ນ.', accountModelsDuplicate: 'ພົບໂມເດວທີ່ຊ້ຳກັນໃນລາຍການ', modelPool: 'ກຸ່ມໂມເດວ (Model Pool)', + ollamaRegisterOnly: 'ລົງທະບຽນສະເພາະໂມເດວທີ່ມີຢູ່ໃນບໍລິການ Ollama ນີ້ແລ້ວ. ຈະບໍ່ເລີ່ມດາວໂຫຼດ.', + deleteModelFiles: 'ລຶບໄຟລ໌ໂມເດວອອກຈາກບໍລິການ Ollama ນຳ', fallbackModels: 'ໂມເດວສຳຮອງ (Fallback)', addFallbackModel: 'ເພີ່ມໂມເດວສຳຮອງ', fallbackModelsEmpty: 'ຍັງບໍ່ໄດ້ຕັ້ງຄ່າໂມເດວສຳຮອງ', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 29ccfa760..a83b0861b 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -853,6 +853,9 @@ const message = { discoverModelsFailedUseDefaults: 'Gagal mendapatkan model. Model lalai sedang digunakan.', accountModelsDuplicate: 'Terdapat model pendua dalam katalog', modelPool: 'Katalog model', + ollamaRegisterOnly: + 'Daftar hanya model yang sudah tersedia pada perkhidmatan Ollama ini. Tiada muat turun akan dimulakan.', + deleteModelFiles: 'Padam juga fail model daripada perkhidmatan Ollama', fallbackModels: 'Model fallback', addFallbackModel: 'Tambah model fallback', fallbackModelsEmpty: 'Tiada model fallback dikonfigurasikan', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index 39ea98415..1cd0b58f6 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -846,6 +846,9 @@ const message = { discoverModelsFailedUseDefaults: 'Não foi possível obter os modelos. Os modelos padrão estão em uso.', accountModelsDuplicate: 'Há modelos duplicados no catálogo', modelPool: 'Catálogo de modelos', + ollamaRegisterOnly: + 'Registre apenas modelos já disponíveis neste serviço Ollama. Nenhum download será iniciado.', + deleteModelFiles: 'Excluir também os arquivos do modelo do serviço Ollama', fallbackModels: 'Modelos de fallback', addFallbackModel: 'Adicionar modelo de fallback', fallbackModelsEmpty: 'Nenhum modelo de fallback configurado', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 60f029c72..c7795e5a3 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -841,6 +841,9 @@ const message = { discoverModelsFailedUseDefaults: 'Не удалось получить модели. Используются модели по умолчанию.', accountModelsDuplicate: 'В каталоге обнаружены повторяющиеся модели', modelPool: 'Каталог моделей', + ollamaRegisterOnly: + 'Регистрируются только модели, уже доступные в этом сервисе Ollama. Загрузка не запускается.', + deleteModelFiles: 'Также удалить файлы модели из сервиса Ollama', fallbackModels: 'Резервные модели', addFallbackModel: 'Добавить резервную модель', fallbackModelsEmpty: 'Резервные модели не настроены', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index 9d236f310..fbe6f057f 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -849,6 +849,8 @@ const message = { discoverModelsFailedUseDefaults: 'Modeller alınamadı. Varsayılan modeller kullanılıyor.', accountModelsDuplicate: 'Katalogda yinelenen modeller bulundu', modelPool: 'Model kataloğu', + ollamaRegisterOnly: 'Yalnızca bu Ollama hizmetinde mevcut modeller kaydedilir. İndirme başlatılmaz.', + deleteModelFiles: 'Model dosyalarını da Ollama hizmetinden sil', fallbackModels: 'Yedek modeller', addFallbackModel: 'Yedek model ekle', fallbackModelsEmpty: 'Yapılandırılmış yedek model yok', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 288116a1f..750cd12f0 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -804,6 +804,8 @@ const message = { discoverModelsFailedUseDefaults: '無法取得模型,已改用預設模型', accountModelsDuplicate: '模型清單中有重複項目,請檢查後再試一次', modelPool: '模型池', + ollamaRegisterOnly: '僅登記此 Ollama 服務上已存在的模型,不會觸發下載。', + deleteModelFiles: '同時刪除 Ollama 服務上的模型檔案', fallbackModels: '備用模型', addFallbackModel: '新增備用模型', fallbackModelsEmpty: '尚未設定備用模型', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 3a6c602dd..3df0b30d9 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -821,6 +821,8 @@ const message = { discoverModelsFailedUseDefaults: '获取模型失败,已使用默认模型', accountModelsDuplicate: '模型池中存在重复模型,请检查后重试', modelPool: '模型池', + ollamaRegisterOnly: '仅登记此 Ollama 服务上已存在的模型,不会触发下载。', + deleteModelFiles: '同时删除 Ollama 服务上的模型文件', fallbackModels: '备用模型', addFallbackModel: '新增备用模型', fallbackModelsEmpty: '尚未配置备用模型', diff --git a/frontend/src/views/ai/model/components/model-pool/index.vue b/frontend/src/views/ai/model/components/model-pool/index.vue index 9a5ddccec..ab4763e63 100644 --- a/frontend/src/views/ai/model/components/model-pool/index.vue +++ b/frontend/src/views/ai/model/components/model-pool/index.vue @@ -26,10 +26,13 @@ - - + + + + {{ $t('aiTools.agents.ollamaRegisterOnly') }} + @@ -39,17 +42,28 @@ {{ $t('commons.button.cancel') }} - {{ $t('commons.button.confirm') }} + {{ form.recordId ? $t('commons.button.confirm') : $t('commons.button.add') }} - + + + + + +