feat(ai): improve model preparation and download progress refresh (#14297)

This commit is contained in:
ssongliu
2026-11-04 16:11:16 +08:00
committed by GitHub
parent 89787a55ee
commit b07afd3785
22 changed files with 880 additions and 269 deletions
+1
View File
@@ -54,6 +54,7 @@ type ModelInfo struct {
}
type ModelDownloadTaskSearch struct {
IDs []uint `json:"ids"`
IncludeLocal bool `json:"includeLocal"`
DownloadType string `json:"downloadType" validate:"omitempty,oneof=all tokenizer"`
PageInfo
+8 -2
View File
@@ -1238,13 +1238,19 @@ func rebuildApp(appInstall model.AppInstall) error {
return handleErr(appInstall, err, "")
}
buildTask.AddSubTaskWithOps(buildTask.Name, func(t *task.Task) error {
t.Log(task.GetTaskName(appInstall.Name, "Stop", task.TaskScopeApp))
out, err := compose.Down(appInstall.GetComposePath())
t.Log(out)
if strings.TrimSpace(out) != "" {
t.Log(out)
}
if err != nil {
return handleErr(appInstall, err, out)
}
t.Log(task.GetTaskName(appInstall.Name, "Run", task.TaskScopeApp))
out, err = compose.Up(appInstall.GetComposePath())
t.Log(out)
if strings.TrimSpace(out) != "" {
t.Log(out)
}
if err != nil {
return handleErr(appInstall, err, out)
}
+25 -16
View File
@@ -268,6 +268,9 @@ func (m *ModelDownloaderService) PageTasks(req dto.ModelDownloadTaskSearch) (int
return pageModelDownloads(req)
}
var opts []repo.DBOption
if len(req.IDs) > 0 {
opts = append(opts, repo.WithByIDs(req.IDs))
}
if req.DownloadType != "" {
opts = append(opts, modelDownloadTaskRepo.WithByDownloadType(req.DownloadType))
}
@@ -469,6 +472,9 @@ func (m *ModelDownloaderService) deleteLocalModel(target, downloadType string, w
func pageModelDownloads(req dto.ModelDownloadTaskSearch) (int64, []dto.ModelDownloadTaskItem, error) {
var opts []repo.DBOption
if len(req.IDs) > 0 {
opts = append(opts, repo.WithByIDs(req.IDs))
}
if req.DownloadType != "" {
opts = append(opts, modelDownloadTaskRepo.WithByDownloadType(req.DownloadType))
}
@@ -502,24 +508,27 @@ func pageModelDownloads(req dto.ModelDownloadTaskSearch) (int64, []dto.ModelDown
}
items = append(items, item)
}
for _, local := range localByPath {
repoID := local.RepoID
if repoID == "" {
repoID = local.Name
if len(req.IDs) == 0 {
for _, local := range localByPath {
repoID := local.RepoID
if repoID == "" {
repoID = local.Name
}
items = append(items, dto.ModelDownloadTaskItem{
DownloadType: local.DownloadType,
Source: local.Source,
RepoID: repoID,
TargetDir: local.Path,
Status: constant.StatusSuccess,
Progress: 100,
TotalSize: local.Size,
DownloadedSize: local.Size,
CreatedAt: local.CreatedAt,
LocalModel: &local,
})
}
items = append(items, dto.ModelDownloadTaskItem{
DownloadType: local.DownloadType,
Source: local.Source,
RepoID: repoID,
TargetDir: local.Path,
Status: constant.StatusSuccess,
Progress: 100,
TotalSize: local.Size,
DownloadedSize: local.Size,
CreatedAt: local.CreatedAt,
LocalModel: &local,
})
}
filtered := items[:0]
for _, item := range items {
if req.Status != "" && item.Status != req.Status {
@@ -76,6 +76,7 @@ export namespace ModelDownloader {
}
export interface TaskSearch extends ReqPage {
ids?: number[];
includeLocal?: boolean;
downloadType?: DownloadType | '';
info: string;
+36 -8
View File
@@ -1041,6 +1041,29 @@ const message = {
validateImageAvailabilityHelper: 'Generates one minimal image before saving and may incur charges',
},
model: {
searchTitle: 'Search and download models',
searchHelper:
'Find models on ModelScope or Hugging Face, then deploy them or create a Recipe in Model Preparation.',
modelScopeSearchHelper: 'Reliable access in mainland China',
huggingFaceSearchHelper: 'Extensive model collection',
searchPlaceholder: 'Enter a model name or repository ID, e.g. Qwen/Qwen3-8B',
popularSearches: 'Popular searches',
searchSort: 'Sort by',
onlyTokenizer: 'Tokenizer only',
downloadStatus: 'Download Status',
downloaded: 'Downloaded',
alreadyExists: 'Already exists',
downloadCompleted: 'Download completed',
localFilesMissing: 'Local files not found',
ollamaNameHelper:
'Enter the full model name from the Ollama library. If no tag is specified, latest is used.',
downloadHelper: 'Click “Search” to find and download models from ModelScope and Hugging Face.',
serviceHelper:
'Connect model services from public clouds, local inference engines, and AI gateways for use by built-in 1Panel agents and external agents such as WorkBuddy.',
gpuType: 'GPU Type',
vllmVersion: 'vLLM Version',
vllmImage: 'vLLM Image',
servicePort: 'Service Port',
gpuAcceleration: 'GPU acceleration',
gpuMode: 'Accelerator selection',
gpuAll: 'All accelerators',
@@ -1072,7 +1095,13 @@ const message = {
approxWeightSize: 'Approx. {0} GB',
services: 'Model services',
addInstance: 'Add instance',
addService: 'Add model service',
modelScopeEndpointHelper: 'Used to search and download ModelScope models. Defaults to the official URL.',
modelTokenHelper: 'Optional. Use a token with access permissions for private or restricted models.',
modelDirHelper: 'Directory for model downloads and the local model list.',
featuredModelsHelper:
'Official 1Panel featured model catalog. Refresh manually or enable auto-sync every 24 hours. Sync updates only the catalog, without downloading model files.',
addInstanceHelper: 'Create a vLLM instance to serve downloaded models.',
addService: 'Add',
onlineModel: 'Online models',
instanceDeployment: 'Deploy by instance',
engines: 'Local inference engines',
@@ -1094,11 +1123,11 @@ const message = {
recipeArguments: 'Launch arguments',
recipeImportCommand: 'Import command',
recipeImportPlaceholder:
'Paste a pip/uv or Docker launch command here. 1Panel will automatically parse it and fill in the Recipe.',
'Paste a pip/uv or docker launch command here. 1Panel will automatically parse it and fill in the form.',
recipeVariablesNotSupported:
'Variable references are not supported in commands. Use explicit values; configure environment variables in the environment field.',
recipeImportError:
'Unable to convert. Include a Docker or vllm serve launch command with a model; paste pip/uv installation commands together with the launch command.',
'No valid launch command detected. Paste a pip/uv or docker command that includes a model.',
engineProvider: 'Engine / Provider',
endpoint: 'Endpoint',
cloudAccount: 'Cloud account',
@@ -1109,7 +1138,8 @@ const message = {
model: 'Models',
localModel: 'Local Models',
create_helper: 'Pull "{0}"',
ollama_doc: 'You can visit the Ollama official website to search and find more models.',
ollama_doc:
'Find models at {link}. The model will be pulled automatically after adding it. Make sure Ollama is running and sufficient disk space is available.',
container_conn_helper: 'Use this address for inter-container access or connection',
from_remote: 'This model was not downloaded via 1Panel, no related pull logs.',
no_logs: 'The pull logs for this model have been deleted and cannot be viewed.',
@@ -1129,7 +1159,7 @@ const message = {
'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',
customAddress: 'Custom address',
downloader: 'Downloads',
downloader: 'Model Downloads',
modelDirectoryHelper:
'The model list defaults to the model directory configured in Model Preparation > Settings and shows models downloaded to that directory.',
modelDirectoryPlaceholder: 'Search models or enter a full path',
@@ -1140,8 +1170,7 @@ const message = {
endpointLabel: '{0} endpoint',
acceleratedEndpointLabel: '{0} acceleration endpoint',
tokenLabel: '{0} Token',
hfEndpointHelper:
'Configure an acceleration endpoint when HuggingFace access is unstable. Search, details, and downloads will use it.',
hfEndpointHelper: 'Optional mirror URL for HuggingFace model searches, details, and downloads.',
sortDefault: 'Default sort',
sortMostParameters: 'Most parameters',
sortLeastParameters: 'Least parameters',
@@ -5046,7 +5075,6 @@ const message = {
customScriptHelper:
'Enter the complete startup command, for example: npm run start. For PM2 startup commands, please replace with pm2-runtime, otherwise it will fail to start.',
portError: "Don't repeat the same port.",
systemRestartHelper: 'Status description: Interruption - status acquisition failed due to system restart',
javaScriptHelper: 'Provide a full startup command. For example, "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'The directory must contain jar files, subdirectories are also acceptable',
goHelper: 'Provide a full startup command. For example, "go run main.go" or "./main".',
+36 -9
View File
@@ -1043,6 +1043,29 @@ const message = {
validateImageAvailabilityHelper: 'Genera una imagen mínima antes de guardar y puede generar costes',
},
model: {
searchTitle: 'Buscar y descargar modelos',
searchHelper:
'Busca modelos en ModelScope o Hugging Face y luego despliégalos o crea una Recipe en Preparación de modelos.',
modelScopeSearchHelper: 'Acceso estable en China continental',
huggingFaceSearchHelper: 'Amplia colección de modelos',
searchPlaceholder: 'Introduce el nombre o ID del repositorio, p. ej. Qwen/Qwen3-8B',
popularSearches: 'Búsquedas populares',
searchSort: 'Ordenar por',
onlyTokenizer: 'Solo tokenizador',
downloadStatus: 'Estado de descarga',
downloaded: 'Descargado',
alreadyExists: 'Ya existe',
downloadCompleted: 'Descarga completada',
localFilesMissing: 'No se encontraron los archivos locales',
ollamaNameHelper:
'Introduzca el nombre completo del modelo de la biblioteca de Ollama. Si no especifica una etiqueta, se usará latest.',
downloadHelper: 'Haga clic en «Buscar» para encontrar y descargar modelos de ModelScope y Hugging Face.',
serviceHelper:
'Conecte servicios de modelos de nubes públicas, motores de inferencia locales y puertas de enlace de IA para que los utilicen los agentes integrados de 1Panel y agentes externos como WorkBuddy.',
gpuType: 'Tipo de GPU',
vllmVersion: 'Versión de vLLM',
vllmImage: 'Imagen de vLLM',
servicePort: 'Puerto del servicio',
gpuAcceleration: 'Aceleración GPU',
gpuMode: 'Selección de aceleradores',
gpuAll: 'Todos los aceleradores',
@@ -1074,7 +1097,13 @@ const message = {
approxWeightSize: 'Aprox. {0} GB',
services: 'Servicios de modelos',
addInstance: 'Añadir instancia',
addService: 'Añadir servicio de modelo',
modelScopeEndpointHelper: 'Para buscar y descargar modelos de ModelScope. Usa la URL oficial por defecto.',
modelTokenHelper: 'Opcional. Use un token con permisos para acceder a modelos privados o restringidos.',
modelDirHelper: 'Directorio de descarga y listado de modelos locales.',
featuredModelsHelper:
'Catálogo oficial de modelos destacados de 1Panel. Actualícelo manualmente o active la sincronización automática cada 24 horas. Solo se actualiza el catálogo, sin descargar modelos.',
addInstanceHelper: 'Cree una instancia de vLLM para servir los modelos descargados.',
addService: 'Añadir',
onlineModel: 'Modelos en línea',
instanceDeployment: 'Despliegue por instancia',
engines: 'Motores de inferencia locales',
@@ -1096,11 +1125,11 @@ const message = {
recipeArguments: 'Argumentos de inicio',
recipeImportCommand: 'Importar comando',
recipeImportPlaceholder:
'Pegue aquí un comando de inicio en formato pip/uv o Docker. 1Panel lo analizará y completará la Recipe automáticamente.',
'Pegue aquí un comando de inicio en formato pip/uv o docker. 1Panel lo analizará y completará el formulario automáticamente.',
recipeVariablesNotSupported:
'No se admiten referencias a variables en los comandos. Use valores concretos; configure las variables de entorno en su campo correspondiente.',
recipeImportError:
'No se puede convertir. Incluya un comando de inicio Docker o vllm serve con un modelo; pegue los comandos de instalación pip/uv junto con el comando de inicio.',
'No se detectó un comando de inicio válido. Pegue un comando pip/uv o docker que incluya un modelo.',
engineProvider: 'Motor / Proveedor',
endpoint: 'Punto de conexión',
cloudAccount: 'Cuenta en la nube',
@@ -1111,7 +1140,8 @@ const message = {
model: 'Modelo',
localModel: 'Modelos locales',
create_helper: 'Descargar "{0}"',
ollama_doc: 'Puede visitar el sitio oficial de Ollama para buscar y encontrar más modelos.',
ollama_doc:
'Busque modelos en {link}. El modelo se descargará automáticamente al añadirlo. Asegúrese de que Ollama esté funcionando y de que haya suficiente espacio en disco.',
container_conn_helper: 'Utilice esta dirección para el acceso o conexión entre contenedores',
from_remote: 'Este modelo no fue descargado vía 1Panel, no hay registros de descarga relacionados.',
no_logs: 'Los registros de descarga de este modelo han sido eliminados y no se pueden consultar.',
@@ -1132,7 +1162,7 @@ const message = {
'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',
customAddress: 'Dirección personalizada',
downloader: 'Gestión de descargas',
downloader: 'Descarga de modelos',
modelDirectoryHelper:
'La lista muestra de forma predeterminada los modelos descargados en el directorio configurado en Preparación de modelos > Configuración.',
modelDirectoryPlaceholder: 'Buscar modelos o introducir una ruta completa',
@@ -1143,8 +1173,7 @@ const message = {
endpointLabel: 'Endpoint de {0}',
acceleratedEndpointLabel: 'Endpoint de aceleración de {0}',
tokenLabel: 'Token de {0}',
hfEndpointHelper:
'Configure un endpoint de aceleración cuando el acceso a HuggingFace sea inestable. La búsqueda, los detalles y las descargas lo utilizarán.',
hfEndpointHelper: 'URL de espejo opcional para búsquedas, detalles y descargas de modelos de HuggingFace.',
sortDefault: 'Orden predeterminado',
sortMostParameters: 'Más parámetros',
sortLeastParameters: 'Menos parámetros',
@@ -5114,8 +5143,6 @@ const message = {
customScriptHelper:
'Por favor, ingresa el comando de inicio completo, por ejemplo: npm run start. Para comandos de inicio de PM2, por favor reemplaza con pm2-runtime, de lo contrario fallará al iniciar.',
portError: 'No repitas el mismo puerto.',
systemRestartHelper:
'Descripción de estado: Interrupción - fallo al obtener estado debido a reinicio del sistema',
javaScriptHelper:
'Proporciona un comando de inicio completo. Ejemplo: "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'El directorio debe contener archivos .jar, se permiten subdirectorios',
+36 -9
View File
@@ -1025,6 +1025,29 @@ const message = {
validateImageAvailabilityHelper: 'پیش از ذخیره یک تصویر حداقلی تولید می‌شود و ممکن است هزینه داشته باشد',
},
model: {
searchTitle: 'جستجو و دانلود مدل‌ها',
searchHelper:
'مدل‌ها را در ModelScope یا Hugging Face پیدا کنید، سپس در آماده‌سازی مدل آن‌ها را مستقر کنید یا یک Recipe بسازید.',
modelScopeSearchHelper: 'دسترسی پایدار در سرزمین اصلی چین',
huggingFaceSearchHelper: 'مجموعه گسترده مدل‌ها',
searchPlaceholder: 'نام مدل یا شناسه مخزن را وارد کنید، مانند Qwen/Qwen3-8B',
popularSearches: 'جستجوهای محبوب',
searchSort: 'مرتب‌سازی',
onlyTokenizer: 'فقط توکن‌ساز',
downloadStatus: 'وضعیت دانلود',
downloaded: 'دانلود شده',
alreadyExists: 'از قبل موجود',
downloadCompleted: 'دانلود تکمیل شد',
localFilesMissing: 'فایل‌های محلی یافت نشد',
ollamaNameHelper:
'نام کامل مدل را از کتابخانه Ollama وارد کنید. اگر برچسب مشخص نشود، latest استفاده می‌شود.',
downloadHelper: 'برای یافتن و دانلود مدل‌ها از ModelScope و Hugging Face روی «جستجو» کلیک کنید.',
serviceHelper:
'سرویس‌های مدل از ابرهای عمومی، موتورهای استنتاج محلی و درگاه‌های هوش مصنوعی را برای استفاده عامل‌های داخلی 1Panel و عامل‌های خارجی مانند WorkBuddy متصل کنید.',
gpuType: 'نوع GPU',
vllmVersion: 'نسخه vLLM',
vllmImage: 'ایمیج vLLM',
servicePort: 'پورت سرویس',
gpuAcceleration: 'شتاب‌دهی GPU',
gpuMode: 'انتخاب شتاب‌دهنده',
gpuAll: 'همه شتاب‌دهنده‌ها',
@@ -1055,7 +1078,13 @@ const message = {
approxWeightSize: 'حدود {0} گیگابایت',
services: 'سرویس‌های مدل',
addInstance: 'افزودن نمونه',
addService: 'افزودن سرویس مدل',
modelScopeEndpointHelper: 'برای جستجو و دانلود مدل‌های ModelScope؛ پیش‌فرض، نشانی رسمی است.',
modelTokenHelper: 'اختیاری. برای مدل‌های خصوصی یا محدود از توکن دارای مجوز دسترسی استفاده کنید.',
modelDirHelper: 'پوشهٔ دانلود مدل‌ها و منبع فهرست مدل‌های محلی.',
featuredModelsHelper:
'فهرست رسمی مدل‌های منتخب 1Panel. به‌صورت دستی به‌روز کنید یا همگام‌سازی خودکار هر ۲۴ ساعت را فعال کنید. فقط فهرست به‌روز می‌شود و فایل مدل‌ها دانلود نمی‌شود.',
addInstanceHelper: 'برای ارائهٔ مدل‌های دانلودشده، یک نمونهٔ vLLM ایجاد کنید.',
addService: 'افزودن',
onlineModel: 'مدل‌های آنلاین',
instanceDeployment: 'استقرار بر اساس نمونه',
engines: 'موتورهای استنتاج محلی',
@@ -1077,11 +1106,10 @@ const message = {
recipeArguments: 'آرگومان‌های راه‌اندازی',
recipeImportCommand: 'وارد کردن فرمان',
recipeImportPlaceholder:
'فرمان اجرا را با قالب pip/uv یا Docker اینجا جای‌گذاری کنید تا 1Panel آن را به‌طور خودکار تحلیل و Recipe را تکمیل کند.',
'فرمان اجرا را با قالب pip/uv یا docker اینجا جای‌گذاری کنید تا 1Panel آن را به‌طور خودکار تحلیل و فرم را تکمیل کند.',
recipeVariablesNotSupported:
'ارجاع به متغیرها در دستور پشتیبانی نمی‌شود. مقادیر مشخص وارد کنید؛ متغیرهای محیطی را در بخش مربوط به آن‌ها تنظیم کنید.',
recipeImportError:
'تبدیل ممکن نیست. فرمان راه‌اندازی Docker یا vllm serve همراه با مدل را وارد کنید؛ فرمان‌های نصب pip/uv را همراه با فرمان راه‌اندازی جای‌گذاری کنید.',
recipeImportError: 'فرمان اجرای معتبری شناسایی نشد. یک فرمان pip/uv یا docker شامل مدل را جای‌گذاری کنید.',
engineProvider: 'موتور / ارائه‌دهنده',
endpoint: 'نقطه پایانی',
cloudAccount: 'حساب ابری',
@@ -1092,7 +1120,8 @@ const message = {
model: 'مدل‌ها',
localModel: 'مدل‌های محلی',
create_helper: 'دریافت "{0}"',
ollama_doc: 'می‌توانید از وب‌سایت رسمی Ollama دیدن کنید و مدل‌های بیشتری را جستجو کنید.',
ollama_doc:
'مدل‌ها را در {link} بیابید. مدل پس از افزودن به‌طور خودکار دانلود می‌شود. مطمئن شوید سرویس Ollama در حال اجرا است و فضای دیسک کافی وجود دارد.',
container_conn_helper: 'از این آدرس برای دسترسی بین کانتینرها یا اتصال استفاده کنید',
from_remote: 'این مدل از طریق 1Panel دانلود نشده است، لاگ مربوط به دریافت وجود ندارد.',
no_logs: 'لاگ دریافت این مدل حذف شده است و قابل مشاهده نیست.',
@@ -1112,7 +1141,7 @@ const message = {
'آدرس کانتینر برای کانتینرهای عامل است؛ 127.0.0.1، IP سیستم یا آدرس سفارشی برای دروازه AI یا خدمات خارجی است.',
containerAddress: 'آدرس کانتینر',
customAddress: 'آدرس سفارشی',
downloader: 'مدیریت دانلودها',
downloader: 'دانلود مدل',
modelDirectoryHelper:
'فهرست مدل‌ها به‌طور پیش‌فرض مدل‌های دانلودشده در پوشه تنظیم‌شده در «آماده‌سازی مدل > تنظیمات» را نمایش می‌دهد.',
modelDirectoryPlaceholder: 'جستجوی مدل یا وارد کردن مسیر کامل',
@@ -1123,8 +1152,7 @@ const message = {
endpointLabel: 'نقطه پایانی {0}',
acceleratedEndpointLabel: 'نقطه پایانی شتاب‌دهنده {0}',
tokenLabel: 'توکن {0}',
hfEndpointHelper:
'هنگامی که دسترسی به HuggingFace ناپایدار است، یک نقطه پایانی شتاب‌دهنده پیکربندی کنید. جستجو، جزئیات و دانلود از آن استفاده خواهند کرد.',
hfEndpointHelper: 'نشانی آینهٔ اختیاری برای جستجو، دریافت جزئیات و دانلود مدل‌های HuggingFace.',
sortDefault: 'مرتب‌سازی پیش‌فرض',
sortMostParameters: 'بیشترین پارامتر',
sortLeastParameters: 'کمترین پارامتر',
@@ -5007,7 +5035,6 @@ const message = {
customScriptHelper:
'دستور راه‌اندازی کامل را وارد کنید، مثلاً: npm run start. برای دستورات راه‌اندازی PM2، لطفاً با pm2-runtime جایگزین کنید، در غیر این صورت راه‌اندازی ناموفق خواهد بود.',
portError: 'پورت تکراری نباشد.',
systemRestartHelper: 'توضیح وضعیت: وقفه - به دلیل راه‌اندازی مجدد سیستم، وضعیت قابل دریافت نیست',
javaScriptHelper: 'یک دستور راه‌اندازی کامل ارائه دهید. مثلاً "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'دایرکتوری باید شامل فایل‌های jar باشد، زیردایرکتوری‌ها نیز مجاز هستند',
goHelper: 'یک دستور راه‌اندازی کامل ارائه دهید. مثلاً "go run main.go" یا "./main".',
+37 -8
View File
@@ -1029,6 +1029,30 @@ const message = {
validateImageAvailabilityHelper: '保存前に最小画像を1枚生成するため、料金が発生する場合があります',
},
model: {
searchTitle: 'モデルを検索してダウンロード',
searchHelper:
'ModelScope または Hugging Face でモデルを検索し、ダウンロード後にモデル準備でデプロイまたは Recipe を作成できます。',
modelScopeSearchHelper: '中国本土から安定したアクセス',
huggingFaceSearchHelper: '豊富なモデル',
searchPlaceholder: 'モデル名またはリポジトリ ID を入力(例:Qwen/Qwen3-8B)',
popularSearches: '人気の検索',
searchSort: '並び順',
onlyTokenizer: 'トークナイザーのみ',
downloadStatus: 'ダウンロード状態',
downloaded: 'ダウンロード済み',
alreadyExists: '既存',
downloadCompleted: 'ダウンロード完了',
localFilesMissing: 'ローカルファイルが見つかりません',
ollamaNameHelper:
'Ollama ライブラリの完全なモデル名を入力してください。タグを省略すると latest が使用されます。',
downloadHelper:
'「検索」をクリックすると、ModelScope や Hugging Face のモデルを検索してダウンロードできます。',
serviceHelper:
'パブリッククラウド、ローカル推論エンジン、AI ゲートウェイなどのモデルサービスを統合し、1Panel 内蔵エージェントや WorkBuddy などの外部エージェントから利用できます。',
gpuType: 'GPU タイプ',
vllmVersion: 'vLLM バージョン',
vllmImage: 'vLLM イメージ',
servicePort: 'サービスポート',
gpuAcceleration: 'GPU アクセラレーション',
gpuMode: 'アクセラレーターの選択',
gpuAll: 'すべてのアクセラレーター',
@@ -1059,7 +1083,13 @@ const message = {
approxWeightSize: '約 {0} GB',
services: 'モデルサービス',
addInstance: 'インスタンスを追加',
addService: 'モデルサービスを追加',
modelScopeEndpointHelper: 'ModelScope モデルの検索とダウンロードに使用します。既定は公式 URL です。',
modelTokenHelper: '任意。非公開・制限付きモデルにはアクセス権のあるトークンが必要です。',
modelDirHelper: 'モデルの保存先とローカルモデル一覧の読み込み先です。',
featuredModelsHelper:
'1Panel 公式のおすすめモデル一覧です。手動更新または 24 時間ごとの自動同期が可能です。同期は一覧のみを更新し、モデルファイルはダウンロードしません。',
addInstanceHelper: 'vLLM インスタンスを作成し、ダウンロード済みモデルをモデルサービスとして公開します。',
addService: '追加',
onlineModel: 'オンラインモデル',
instanceDeployment: 'インスタンス単位でデプロイ',
engines: 'ローカル推論エンジン',
@@ -1081,11 +1111,11 @@ const message = {
recipeArguments: '起動引数',
recipeImportCommand: 'コマンドをインポート',
recipeImportPlaceholder:
'ここに pip/uv または Docker 形式の起動コマンドを貼り付けると、1Panel が自動的に解析し、Recipe に入力します。',
'ここに pip/uv または docker 形式の起動コマンドを貼り付けると、1Panel が自動的に解析し、フォームに入力します。',
recipeVariablesNotSupported:
'コマンド内の変数参照はサポートされていません。具体的な値を入力し、環境変数は環境変数欄で設定してください。',
recipeImportError:
'変換できません。モデルを含む Docker または vllm serve の起動コマンドを入力してください。pip/uv のインストールコマンドは起動コマンドと一緒に貼り付けてください。',
'有効な起動コマンドが見つかりません。モデルを含む pip/uv または docker コマンドを貼り付けてください。',
engineProvider: 'エンジン / プロバイダー',
endpoint: 'エンドポイント',
cloudAccount: 'クラウドアカウント',
@@ -1096,7 +1126,8 @@ const message = {
model: 'モデル',
localModel: 'ローカルモデル',
create_helper: 'を取得 "{0}"',
ollama_doc: 'Ollama の公式ウェブサイトを訪れて、さらに多くのモデルを検索して見つけることができます。',
ollama_doc:
'{link} でモデルを検索できます。追加後、モデルは自動的に取得されます。Ollama が正常に動作し、十分なディスク容量があることを確認してください。',
container_conn_helper: 'コンテナ間のアクセスまたは接続にこのアドレスを使用',
from_remote: 'このモデルは1Panelを介してダウンロードされておらず、関連するプルログはありません。',
no_logs: 'このモデルのプルログは削除されており、関連するログを表示できません。',
@@ -1117,7 +1148,7 @@ const message = {
'コンテナアドレスはエージェントコンテナ向けです。127.0.0.1、システム IP、カスタムアドレスは AI Gateway または外部サービス向けです。',
containerAddress: 'コンテナアドレス',
customAddress: 'カスタムアドレス',
downloader: 'ダウンロード管理',
downloader: 'モデルのダウンロード',
modelDirectoryHelper:
'モデル一覧には、デフォルトで「モデル準備 > 設定」で指定したモデルディレクトリにダウンロード済みのモデルが表示されます。',
modelDirectoryPlaceholder: 'モデルを検索するかフルパスを入力',
@@ -1128,8 +1159,7 @@ const message = {
endpointLabel: '{0} エンドポイント',
acceleratedEndpointLabel: '{0} アクセラレーションエンドポイント',
tokenLabel: '{0} Token',
hfEndpointHelper:
'HuggingFace へのアクセスが不安定な場合はアクセラレーションエンドポイントを設定してください。検索、詳細、ダウンロードで使用されます。',
hfEndpointHelper: '任意。HuggingFace モデルの検索・詳細取得・ダウンロード用のミラー URL です。',
sortDefault: '標準の並び順',
sortMostParameters: 'パラメータ数が多い順',
sortLeastParameters: 'パラメータ数が少ない順',
@@ -5027,7 +5057,6 @@ const message = {
customScriptHelper:
'完全な起動コマンドを入力してください。例:npm run start。PM2の起動コマンドはpm2-runtimeに置き換えてください。そうしないと起動に失敗します。',
portError: '同じポートを繰り返さないでください。',
systemRestartHelper: 'ステータスの説明:中断 - システムの再起動によりステータスの取得が失敗しました',
javaScriptHelper: '完全な起動コマンドを提供します。たとえば、「Java -Jar Halo.Jar -XMX1024M -XMS256M」。',
javaDirHelper: 'ディレクトリにはjarファイルが含まれている必要があり、サブディレクトリも受け入れられます',
goHelper: '完全な起動コマンドを提供します。たとえば、「Go Run Main.go」または「./Main」。',
+36 -8
View File
@@ -1019,6 +1019,29 @@ const message = {
validateImageAvailabilityHelper: '저장 전에 최소 이미지 한 장을 생성하며 비용이 발생할 수 있습니다',
},
model: {
searchTitle: '모델 검색 및 다운로드',
searchHelper:
'ModelScope 또는 Hugging Face에서 모델을 찾아 다운로드한 후 모델 준비에서 배포하거나 Recipe를 만들 수 있습니다.',
modelScopeSearchHelper: '중국 본토에서 안정적인 접속',
huggingFaceSearchHelper: '풍부한 모델 컬렉션',
searchPlaceholder: '모델 이름 또는 저장소 ID 입력, 예: Qwen/Qwen3-8B',
popularSearches: '인기 검색어',
searchSort: '정렬',
onlyTokenizer: '토크나이저만 다운로드',
downloadStatus: '다운로드 상태',
downloaded: '다운로드됨',
alreadyExists: '이미 존재함',
downloadCompleted: '다운로드 완료',
localFilesMissing: '로컬 파일을 찾을 수 없습니다',
ollamaNameHelper: 'Ollama 라이브러리의 전체 모델 이름을 입력하세요. 태그를 생략하면 latest가 사용됩니다.',
downloadHelper:
'“검색” 버튼을 클릭하여 ModelScope 및 Hugging Face의 모델을 검색하고 다운로드할 수 있습니다.',
serviceHelper:
'퍼블릭 클라우드, 로컬 추론 엔진, AI 게이트웨이 등의 모델 서비스를 통합하여 1Panel 내장 에이전트와 WorkBuddy 같은 외부 에이전트에서 사용할 수 있습니다.',
gpuType: 'GPU 유형',
vllmVersion: 'vLLM 버전',
vllmImage: 'vLLM 이미지',
servicePort: '서비스 포트',
gpuAcceleration: 'GPU 가속',
gpuMode: '가속기 선택',
gpuAll: '모든 가속기',
@@ -1049,7 +1072,13 @@ const message = {
approxWeightSize: '약 {0} GB',
services: '모델 서비스',
addInstance: '인스턴스 추가',
addService: '모델 서비스 추가',
modelScopeEndpointHelper: 'ModelScope 모델 검색 및 다운로드에 사용하며, 기본값은 공식 URL입니다.',
modelTokenHelper: '선택 사항. 비공개 또는 제한된 모델에는 접근 권한이 있는 토큰이 필요합니다.',
modelDirHelper: '모델 다운로드 저장 경로이자 로컬 모델 목록을 읽는 경로입니다.',
featuredModelsHelper:
'1Panel 공식 추천 모델 목록입니다. 수동으로 새로 고치거나 24시간마다 자동 동기화를 설정할 수 있습니다. 목록만 갱신하며 모델 파일은 다운로드하지 않습니다.',
addInstanceHelper: 'vLLM 인스턴스를 생성하여 다운로드한 모델을 모델 서비스로 배포합니다.',
addService: '추가',
onlineModel: '온라인 모델',
instanceDeployment: '인스턴스별 배포',
engines: '로컬 추론 엔진',
@@ -1071,11 +1100,11 @@ const message = {
recipeArguments: '시작 인수',
recipeImportCommand: '명령 가져오기',
recipeImportPlaceholder:
'여기에 pip/uv 또는 Docker 형식의 실행 명령을 붙여넣으면 1Panel이 자동으로 분석하여 Recipe를 채웁니다.',
'여기에 pip/uv 또는 docker 형식의 실행 명령을 붙여넣으면 1Panel이 자동으로 분석하여 양식을 채웁니다.',
recipeVariablesNotSupported:
'명령에서 변수 참조는 지원되지 않습니다. 구체적인 값을 입력하고 환경 변수는 환경 변수 필드에서 설정하세요.',
recipeImportError:
'변환할 수 없습니다. 모델이 포함된 Docker 또는 vllm serve 시작 명령을 입력하세요. pip/uv 설치 명령은 시작 명령과 함께 붙여넣으세요.',
'유효한 실행 명령을 찾지 못했습니다. 모델이 포함된 pip/uv 또는 docker 명령을 붙여넣으세요.',
engineProvider: '엔진 / 공급자',
endpoint: '엔드포인트',
cloudAccount: '클라우드 계정',
@@ -1086,7 +1115,8 @@ const message = {
model: '모델',
localModel: '로컬 모델',
create_helper: '가져오기 "{0}"',
ollama_doc: 'Ollama 공식 웹사이트를 방문하여 더 많은 모델을 검색하고 찾을 수 있습니다.',
ollama_doc:
'{link}에서 모델을 검색하세요. 추가 후 모델을 자동으로 가져옵니다. Ollama 서비스가 정상적으로 실행 중이고 디스크 공간이 충분한지 확인하세요.',
container_conn_helper: '컨테이너 간 접근 또는 연결에 이 주소를 사용',
from_remote: '이 모델은 1Panel을 통해 다운로드되지 않았으며 관련 풀 로그가 없습니다.',
no_logs: '이 모델의 풀 로그가 삭제되어 관련 로그를 볼 수 없습니다.',
@@ -1106,7 +1136,7 @@ const message = {
'컨테이너 주소는 에이전트 컨테이너 호출에 적합합니다. 127.0.0.1, 시스템 IP 또는 사용자 지정 주소는 AI Gateway 또는 외부 서비스 호출에 적합합니다.',
containerAddress: '컨테이너 주소',
customAddress: '사용자 지정 주소',
downloader: '다운로드 관리',
downloader: '모델 다운로드',
modelDirectoryHelper:
'모델 목록은 기본적으로 “모델 준비 > 설정”에서 구성한 모델 디렉터리에 다운로드된 모델을 표시합니다.',
modelDirectoryPlaceholder: '모델 검색 또는 전체 경로 입력',
@@ -1117,8 +1147,7 @@ const message = {
endpointLabel: '{0} 엔드포인트',
acceleratedEndpointLabel: '{0} 가속 엔드포인트',
tokenLabel: '{0} Token',
hfEndpointHelper:
'HuggingFace 접속이 불안정할 때 가속 엔드포인트를 설정하세요. 검색, 상세 정보, 다운로드에 사용됩니다.',
hfEndpointHelper: '선택 사항. HuggingFace 모델 검색, 상세 정보 조회 및 다운로드용 미러 URL입니다.',
sortDefault: '기본 정렬',
sortMostParameters: '매개변수 많은 순',
sortLeastParameters: '매개변수 적은 순',
@@ -4937,7 +4966,6 @@ const message = {
customScriptHelper:
'전체 시작 명령어를 입력해 주세요. 예: npm run start. PM2 시작 명령어는 pm2-runtime로 변경해 주세요. 그렇지 않으면 시작에 실패합니다.',
portError: '포트를 중복 사용하지 마세요.',
systemRestartHelper: '상태 설명: 중단 - 시스템 재시작으로 인해 상태 가져오기가 실패했습니다.',
javaScriptHelper: '전체 시작 명령을 제공하세요. 예: "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: '디렉터리는 jar 파일을 포함해야 하며, 하위 디렉터리도 허용됩니다.',
goHelper: '전체 시작 명령을 제공하세요. 예: "go run main.go" 또는 "./main".',
+34 -9
View File
@@ -1016,6 +1016,27 @@ const message = {
validateImageAvailabilityHelper: 'ສ້າງຮູບຂະໜາດນ້ອຍໜຶ່ງຮູບກ່ອນບັນທຶກ ແລະ ອາດມີຄ່າໃຊ້ຈ່າຍ',
},
model: {
searchTitle: 'ຄົ້ນຫາ ແລະ ດາວໂຫຼດໂມເດວ',
searchHelper: 'ຄົ້ນຫາໂມເດວໃນ ModelScope ຫຼື Hugging Face ແລ້ວນຳໃຊ້ ຫຼື ສ້າງ Recipe ໃນການກະກຽມໂມເດວ.',
modelScopeSearchHelper: 'ເຂົ້າເຖິງໄດ້ສະຖຽນໃນຈີນແຜ່ນດິນໃຫຍ່',
huggingFaceSearchHelper: 'ມີໂມເດວໃຫ້ເລືອກຫຼາກຫຼາຍ',
searchPlaceholder: 'ປ້ອນຊື່ໂມເດວ ຫຼື ID ຄັງ, ເຊັ່ນ Qwen/Qwen3-8B',
popularSearches: 'ການຄົ້ນຫາຍອດນິຍົມ',
searchSort: 'ຈັດລຽງ',
onlyTokenizer: 'ດາວໂຫຼດສະເພາະຕົວແບ່ງໂທເຄັນ',
downloadStatus: 'ສະຖານະດາວໂຫຼດ',
downloaded: 'ດາວໂຫຼດແລ້ວ',
alreadyExists: 'ມີຢູ່ແລ້ວ',
downloadCompleted: 'ດາວໂຫຼດສຳເລັດ',
localFilesMissing: 'ບໍ່ພົບໄຟລ໌ພາຍໃນ',
ollamaNameHelper: 'ກະລຸນາໃສ່ຊື່ໂມເດວເຕັມຈາກຄັງ Ollama. ຖ້າບໍ່ລະບຸແທັກ ຈະໃຊ້ latest.',
downloadHelper: 'ຄລິກ “ຄົ້ນຫາ” ເພື່ອຄົ້ນຫາ ແລະ ດາວໂຫຼດໂມເດວຈາກ ModelScope ແລະ Hugging Face.',
serviceHelper:
'ເຊື່ອມຕໍ່ບໍລິການໂມເດວຈາກຄລາວສາທາລະນະ, ເຄື່ອງຈັກອະນຸມານພາຍໃນ ແລະ ເກດເວ AI ເພື່ອໃຫ້ຕົວແທນໃນ 1Panel ແລະ ຕົວແທນພາຍນອກເຊັ່ນ WorkBuddy ໃຊ້ງານ.',
gpuType: 'ປະເພດ GPU',
vllmVersion: 'ເວີຊັນ vLLM',
vllmImage: 'ອິມເມຈ vLLM',
servicePort: 'ພອດບໍລິການ',
gpuAcceleration: 'ການເລັ່ງ GPU',
gpuMode: 'ເລືອກຕົວເລັ່ງ',
gpuAll: 'ຕົວເລັ່ງທັງໝົດ',
@@ -1046,7 +1067,13 @@ const message = {
approxWeightSize: 'ປະມານ {0} GB',
services: 'ບໍລິການໂມເດວ',
addInstance: 'ເພີ່ມອິນສະແຕນ',
addService: 'ເພີ່ມບໍລິການໂມເດວ',
modelScopeEndpointHelper: 'ໃຊ້ຄົ້ນຫາ ແລະ ດາວໂຫຼດໂມເດວ ModelScope. ຄ່າເລີ່ມຕົ້ນແມ່ນ URL ທາງການ.',
modelTokenHelper: 'ບໍ່ບັງຄັບ. ໂມເດວສ່ວນຕົວ ຫຼື ທີ່ຈຳກັດຕ້ອງໃຊ້ Token ທີ່ມີສິດເຂົ້າເຖິງ.',
modelDirHelper: 'ໂຟນເດີດາວໂຫຼດໂມເດວ ແລະ ແຫຼ່ງລາຍການໂມເດວພາຍໃນເຄື່ອງ.',
featuredModelsHelper:
'ລາຍການໂມເດວແນະນຳທາງການຂອງ 1Panel. ສາມາດໂຫຼດຄືນດ້ວຍຕົນເອງ ຫຼື ເປີດການຊິງຄ໌ອັດຕະໂນມັດທຸກ 24 ຊົ່ວໂມງ. ອັບເດດສະເພາະລາຍການ ໂດຍບໍ່ດາວໂຫຼດໄຟລ໌ໂມເດວ.',
addInstanceHelper: 'ສ້າງອິນສະແຕນ vLLM ເພື່ອໃຫ້ບໍລິການໂມເດວທີ່ດາວໂຫຼດແລ້ວ.',
addService: 'ເພີ່ມ',
onlineModel: 'ໂມເດວອອນລາຍ',
instanceDeployment: 'ນຳໃຊ້ຕາມອິນສະແຕນ',
engines: 'ເຄື່ອງຈັກອະນຸມານພາຍໃນ',
@@ -1068,11 +1095,10 @@ const message = {
recipeArguments: 'ພາລາມິເຕີເລີ່ມຕົ້ນ',
recipeImportCommand: 'ນຳເຂົ້າຄຳສັ່ງ',
recipeImportPlaceholder:
'ວາງຄຳສັ່ງເລີ່ມຕົ້ນໃນຮູບແບບ pip/uv ຫຼື Docker ທີ່ນີ້. 1Panel ຈະວິເຄາະແລະຕື່ມ Recipe ອັດຕະໂນມັດ.',
'ວາງຄຳສັ່ງເລີ່ມຕົ້ນໃນຮູບແບບ pip/uv ຫຼື docker ທີ່ນີ້. 1Panel ຈະວິເຄາະ ແລະ ຕື່ມແບບຟອມອັດຕະໂນມັດ.',
recipeVariablesNotSupported:
'ຄຳສັ່ງບໍ່ຮອງຮັບການອ້າງອີງຕົວແປ. ກະລຸນາປ້ອນຄ່າໂດຍກົງ ແລະຕັ້ງຄ່າຕົວແປສະພາບແວດລ້ອມໃນຊ່ອງທີ່ກ່ຽວຂ້ອງ.',
recipeImportError:
'ບໍ່ສາມາດແປງໄດ້. ກະລຸນາໃສ່ຄຳສັ່ງເລີ່ມຕົ້ນ Docker ຫຼື vllm serve ທີ່ມີໂມເດວ; ວາງຄຳສັ່ງຕິດຕັ້ງ pip/uv ພ້ອມກັບຄຳສັ່ງເລີ່ມຕົ້ນ.',
recipeImportError: 'ບໍ່ພົບຄຳສັ່ງເລີ່ມຕົ້ນທີ່ຖືກຕ້ອງ. ກະລຸນາວາງຄຳສັ່ງ pip/uv ຫຼື docker ທີ່ມີໂມເດວ.',
engineProvider: 'ເຄື່ອງຈັກ / ຜູ້ໃຫ້ບໍລິການ',
endpoint: 'ຈຸດເຊື່ອມຕໍ່',
cloudAccount: 'ບັນຊີຄລາວ',
@@ -1083,7 +1109,8 @@ const message = {
model: 'ໂມເດວ',
localModel: 'ໂມເດວໃນເຄື່ອງ',
create_helper: 'ດຶງ (Pull) "{0}"',
ollama_doc: 'ທ່ານສາມາດຢ້ຽມຊົມເວັບໄຊທ໌ທາງການຂອງ Ollama ເພື່ອຄົ້ນຫາໂມເດວເພີ່ມເຕີມ.',
ollama_doc:
'ຄົ້ນຫາໂມເດວທີ່ {link}. ລະບົບຈະດາວໂຫຼດໂມເດວອັດຕະໂນມັດຫຼັງຈາກເພີ່ມ. ກະລຸນາກວດສອບວ່າ Ollama ເຮັດວຽກປົກກະຕິ ແລະ ມີພື້ນທີ່ດິສກ໌ພຽງພໍ.',
container_conn_helper: 'ໃຊ້ທີ່ຢູ່ນີ້ສຳລັບການເຂົ້າເຖິງ ຫຼື ເຊື່ອມຕໍ່ລະຫວ່າງຄອນເທນເນີ',
from_remote: 'ໂມເດວນີ້ບໍ່ໄດ້ດາວໂຫຼດຜ່ານ 1Panel, ບໍ່ມີລັອກການດຶງຂໍ້ມູນທີ່ກ່ຽວຂ້ອງ.',
no_logs: 'ລັອກການດຶງຂໍ້ມູນຂອງໂມເດວນີ້ຖືກລຶບແລ້ວ ແລະ ບໍ່ສາມາດເບິ່ງໄດ້.',
@@ -1103,7 +1130,7 @@ const message = {
'ທີ່ຢູ່ຄອນເທນເນີແມ່ນສຳລັບຄອນເທນເນີຕົວແທນ; 127.0.0.1, IP ລະບົບ, ຫຼື ທີ່ຢູ່ກຳນົດເອງແມ່ນສຳລັບ AI Gateway ຫຼື ບໍລິການພາຍນອກ.',
containerAddress: 'ທີ່ຢູ່ຄອນເທນເນີ',
customAddress: 'ທີ່ຢູ່ກຳນົດເອງ',
downloader: 'ຈັດການການດາວໂຫຼດ',
downloader: 'ດາວໂຫຼດໂມເດວ',
modelDirectoryHelper:
'ໂດຍຄ່າເລີ່ມຕົ້ນ ລາຍຊື່ໂມເດວຈະສະແດງໂມເດວທີ່ດາວໂຫຼດໄວ້ໃນໄດເຣັກທໍຣີທີ່ກຳນົດໃນ “ການກະກຽມໂມເດວ > ການຕັ້ງຄ່າ”.',
modelDirectoryPlaceholder: 'ຄົ້ນຫາໂມເດວ ຫຼື ປ້ອນເສັ້ນທາງເຕັມ',
@@ -1114,8 +1141,7 @@ const message = {
endpointLabel: 'ຈຸດເຊື່ອມຕໍ່ (Endpoint) {0}',
acceleratedEndpointLabel: 'ຈຸດເຊື່ອມຕໍ່ເລັ່ງຄວາມໄວ {0}',
tokenLabel: '{0} Token',
hfEndpointHelper:
'ຕັ້ງຄ່າຈຸດເຊື່ອມຕໍ່ເລັ່ງຄວາມໄວເມື່ອການເຂົ້າເຖິງ HuggingFace ບໍ່ຄົງທີ່. ການຄົ້ນຫາ, ລາຍລະອຽດ ແລະ ການດາວໂຫຼດຈະໃຊ້ທີ່ຢູ່ນີ້.',
hfEndpointHelper: 'URL ມິເຣີທາງເລືອກສຳລັບຄົ້ນຫາ, ເບິ່ງລາຍລະອຽດ ແລະ ດາວໂຫຼດໂມເດວ HuggingFace.',
sortDefault: 'ການຈັດລຽງເລີ່ມຕົ້ນ',
sortMostParameters: 'ພາລາມິເຕີຫຼາຍທີ່ສຸດ',
sortLeastParameters: 'ພາລາມິເຕີໜ້ອຍທີ່ສຸດ',
@@ -4895,7 +4921,6 @@ const message = {
customScriptHelper:
'ປ້ອນຄຳສັ່ງເລີ່ມຕົ້ນທີ່ສົມບູນ ຕົວຢ່າງ: npm run start. ສຳລັບຄຳສັ່ງ PM2, ໃຫ້ປ່ຽນເປັນ pm2-runtime.',
portError: 'ຫ້າມໃຊ້ພອດຊ້ຳກັນ.',
systemRestartHelper: 'ລາຍລະອຽດ: ຖືກຂັດຈັງຫວະ - ບໍ່ສາມາດດຶງສະຖານະໄດ້ເນື່ອງຈາກລະບົບເລີ່ມຕົ້ນໃໝ່',
javaScriptHelper: 'ປ້ອນຄຳສັ່ງເລີ່ມຕົ້ນທີ່ສົມບູນ ຕົວຢ່າງ: "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'ໂຟນເດີຕ້ອງມີໄຟລ໌ jar, ໂຟນເດີ່ຍ່ອຍກໍສາມາດໃຊ້ໄດ້',
goHelper: 'ປ້ອນຄຳສັ່ງເລີ່ມຕົ້ນທີ່ສົມບູນ ຕົວຢ່າງ: "go run main.go" ຫຼື "./main".',
+38 -8
View File
@@ -1052,6 +1052,29 @@ const message = {
validateImageAvailabilityHelper: 'Menjana satu imej minimum sebelum menyimpan dan mungkin dikenakan caj',
},
model: {
searchTitle: 'Cari dan muat turun model',
searchHelper:
'Cari model di ModelScope atau Hugging Face, kemudian gunakan model atau cipta Recipe dalam Persediaan Model.',
modelScopeSearchHelper: 'Akses stabil di tanah besar China',
huggingFaceSearchHelper: 'Koleksi model yang luas',
searchPlaceholder: 'Masukkan nama model atau ID repositori, cth. Qwen/Qwen3-8B',
popularSearches: 'Carian popular',
searchSort: 'Susun mengikut',
onlyTokenizer: 'Pentoken sahaja',
downloadStatus: 'Status muat turun',
downloaded: 'Telah dimuat turun',
alreadyExists: 'Sudah wujud',
downloadCompleted: 'Muat turun selesai',
localFilesMissing: 'Fail setempat tidak ditemui',
ollamaNameHelper:
'Masukkan nama model penuh daripada pustaka Ollama. Jika tag tidak dinyatakan, latest akan digunakan.',
downloadHelper: 'Klik “Cari” untuk mencari dan memuat turun model daripada ModelScope dan Hugging Face.',
serviceHelper:
'Sambungkan perkhidmatan model daripada awan awam, enjin inferens setempat dan gerbang AI untuk digunakan oleh ejen terbina dalam 1Panel serta ejen luaran seperti WorkBuddy.',
gpuType: 'Jenis GPU',
vllmVersion: 'Versi vLLM',
vllmImage: 'Imej vLLM',
servicePort: 'Port perkhidmatan',
gpuAcceleration: 'Pecutan GPU',
gpuMode: 'Pemilihan pemecut',
gpuAll: 'Semua pemecut',
@@ -1082,7 +1105,15 @@ const message = {
approxWeightSize: 'Kira-kira {0} GB',
services: 'Perkhidmatan model',
addInstance: 'Tambah instans',
addService: 'Tambah perkhidmatan model',
modelScopeEndpointHelper:
'Untuk mencari dan memuat turun model ModelScope. Menggunakan URL rasmi secara lalai.',
modelTokenHelper: 'Pilihan. Gunakan token dengan kebenaran akses untuk model peribadi atau terhad.',
modelDirHelper: 'Direktori muat turun model dan sumber senarai model setempat.',
featuredModelsHelper:
'Katalog model pilihan rasmi 1Panel. Muat semula secara manual atau aktifkan penyegerakan automatik setiap 24 jam. Hanya katalog dikemas kini, tanpa memuat turun fail model.',
addInstanceHelper:
'Cipta instans vLLM untuk menyediakan model yang dimuat turun sebagai perkhidmatan model.',
addService: 'Tambah',
onlineModel: 'Model dalam talian',
instanceDeployment: 'Pengerahan mengikut instans',
engines: 'Enjin inferens setempat',
@@ -1104,11 +1135,11 @@ const message = {
recipeArguments: 'Argumen pelancaran',
recipeImportCommand: 'Import arahan',
recipeImportPlaceholder:
'Tampal arahan pelancaran dalam format pip/uv atau Docker di sini. 1Panel akan menghuraikan dan mengisi Recipe secara automatik.',
'Tampal arahan pelancaran dalam format pip/uv atau docker di sini. 1Panel akan menghuraikan dan mengisi borang secara automatik.',
recipeVariablesNotSupported:
'Rujukan pemboleh ubah tidak disokong dalam arahan. Masukkan nilai khusus; tetapkan pemboleh ubah persekitaran dalam medan yang berkenaan.',
recipeImportError:
'Tidak dapat menukar. Sertakan arahan pelancaran Docker atau vllm serve dengan model; tampal arahan pemasangan pip/uv bersama arahan pelancaran.',
'Tiada arahan pelancaran yang sah dikesan. Tampal arahan pip/uv atau docker yang mengandungi model.',
engineProvider: 'Enjin / Pembekal',
endpoint: 'Titik akhir',
cloudAccount: 'Akaun awan',
@@ -1119,7 +1150,8 @@ const message = {
model: 'Model',
localModel: 'Model Tempatan',
create_helper: 'Tarik "{0}"',
ollama_doc: 'Anda boleh melawat laman web rasmi Ollama untuk mencari dan menemui lebih banyak model.',
ollama_doc:
'Cari model di {link}. Model akan dimuat turun secara automatik selepas ditambah. Pastikan perkhidmatan Ollama berjalan dan ruang cakera mencukupi.',
container_conn_helper: 'Gunakan alamat ini untuk akses atau sambungan antara kontena',
from_remote: 'Model ini tidak dimuat turun melalui 1Panel; tiada log muat turun berkaitan.',
no_logs: 'Log muat turun model ini telah dipadam dan tidak boleh dilihat.',
@@ -1139,7 +1171,7 @@ const message = {
'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',
customAddress: 'Alamat tersuai',
downloader: 'Pengurusan muat turun',
downloader: 'Muat turun model',
modelDirectoryHelper:
'Secara lalai, senarai model memaparkan model yang dimuat turun dalam direktori yang dikonfigurasi di Persediaan Model > Tetapan.',
modelDirectoryPlaceholder: 'Cari model atau masukkan laluan penuh',
@@ -1150,8 +1182,7 @@ const message = {
endpointLabel: 'Endpoint {0}',
acceleratedEndpointLabel: 'Titik akhir pecutan {0}',
tokenLabel: 'Token {0}',
hfEndpointHelper:
'Konfigurasikan titik akhir pecutan apabila akses HuggingFace tidak stabil. Carian, butiran dan muat turun akan menggunakannya.',
hfEndpointHelper: 'URL cermin pilihan untuk carian, butiran dan muat turun model HuggingFace.',
sortDefault: 'Isihan lalai',
sortMostParameters: 'Parameter terbanyak',
sortLeastParameters: 'Parameter paling sedikit',
@@ -5120,7 +5151,6 @@ const message = {
customScriptHelper:
'Sila masukkan arahan permulaan penuh, contoh: npm run start. Untuk arahan permulaan PM2, sila gantikan dengan pm2-runtime, jika tidak ia akan gagal bermula.',
portError: 'Jangan ulangi port yang sama.',
systemRestartHelper: 'Huraian status: Gangguan - status gagal diperoleh kerana sistem dimulakan semula',
javaScriptHelper: 'Sediakan arahan permulaan penuh. Contohnya, "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'Direktori mesti mengandungi fail jar, subdirektori juga diterima',
goHelper: 'Sediakan arahan permulaan penuh. Contohnya, "go run main.go" atau "./main".',
+36 -9
View File
@@ -1047,6 +1047,29 @@ const message = {
validateImageAvailabilityHelper: 'Gera uma imagem mínima antes de salvar e pode gerar custos',
},
model: {
searchTitle: 'Pesquisar e baixar modelos',
searchHelper:
'Encontre modelos no ModelScope ou Hugging Face e depois implante-os ou crie uma Recipe em Preparação de modelos.',
modelScopeSearchHelper: 'Acesso estável na China continental',
huggingFaceSearchHelper: 'Ampla coleção de modelos',
searchPlaceholder: 'Digite o nome ou ID do repositório, ex.: Qwen/Qwen3-8B',
popularSearches: 'Buscas populares',
searchSort: 'Ordenar por',
onlyTokenizer: 'Somente tokenizador',
downloadStatus: 'Status do download',
downloaded: 'Baixado',
alreadyExists: 'Já existe',
downloadCompleted: 'Download concluído',
localFilesMissing: 'Arquivos locais não encontrados',
ollamaNameHelper:
'Insira o nome completo do modelo da biblioteca do Ollama. Se nenhuma tag for especificada, será usada latest.',
downloadHelper: 'Clique em “Pesquisar” para encontrar e baixar modelos do ModelScope e do Hugging Face.',
serviceHelper:
'Conecte serviços de modelos de nuvens públicas, mecanismos de inferência locais e gateways de IA para uso pelos agentes integrados do 1Panel e agentes externos, como o WorkBuddy.',
gpuType: 'Tipo de GPU',
vllmVersion: 'Versão do vLLM',
vllmImage: 'Imagem do vLLM',
servicePort: 'Porta do serviço',
gpuAcceleration: 'Aceleração de GPU',
gpuMode: 'Seleção de aceleradores',
gpuAll: 'Todos os aceleradores',
@@ -1078,7 +1101,13 @@ const message = {
approxWeightSize: 'Aprox. {0} GB',
services: 'Serviços de modelos',
addInstance: 'Adicionar instância',
addService: 'Adicionar serviço de modelo',
modelScopeEndpointHelper: 'Para buscar e baixar modelos do ModelScope. Usa a URL oficial por padrão.',
modelTokenHelper: 'Opcional. Use um token com permissão para acessar modelos privados ou restritos.',
modelDirHelper: 'Diretório de download e listagem dos modelos locais.',
featuredModelsHelper:
'Catálogo oficial de modelos em destaque do 1Panel. Atualize manualmente ou ative a sincronização automática a cada 24 horas. Apenas o catálogo é atualizado, sem baixar modelos.',
addInstanceHelper: 'Crie uma instância do vLLM para servir os modelos baixados.',
addService: 'Adicionar',
onlineModel: 'Modelos online',
instanceDeployment: 'Implantação por instância',
engines: 'Mecanismos de inferência locais',
@@ -1100,11 +1129,11 @@ const message = {
recipeArguments: 'Argumentos de inicialização',
recipeImportCommand: 'Importar comando',
recipeImportPlaceholder:
'Cole um comando de inicialização no formato pip/uv ou Docker aqui. O 1Panel irá analisar e preencher a Recipe automaticamente.',
'Cole um comando de inicialização no formato pip/uv ou docker aqui. O 1Panel irá analisar e preencher o formulário automaticamente.',
recipeVariablesNotSupported:
'Referências a variáveis não são aceitas nos comandos. Use valores explícitos; configure as variáveis de ambiente no campo correspondente.',
recipeImportError:
'Não foi possível converter. Inclua um comando de inicialização Docker ou vllm serve com um modelo; cole os comandos de instalação pip/uv junto com o comando de inicialização.',
'Nenhum comando de inicialização válido foi detectado. Cole um comando pip/uv ou docker que inclua um modelo.',
engineProvider: 'Mecanismo / Provedor',
endpoint: 'Endpoint',
cloudAccount: 'Conta na nuvem',
@@ -1115,7 +1144,8 @@ const message = {
model: 'Modelo',
localModel: 'Modelos locais',
create_helper: 'Puxar "{0}"',
ollama_doc: 'Você pode visitar o site oficial da Ollama para pesquisar e encontrar mais modelos.',
ollama_doc:
'Busque modelos em {link}. O modelo será baixado automaticamente após ser adicionado. Verifique se o Ollama está em execução e se há espaço suficiente em disco.',
container_conn_helper: 'Use este endereço para acesso ou conexão entre contêineres',
from_remote: 'Este modelo não foi baixado pelo 1Panel; não há logs de download relacionados.',
no_logs: 'Os logs de download deste modelo foram excluídos e não podem ser visualizados.',
@@ -1135,7 +1165,7 @@ const message = {
'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',
customAddress: 'Endereço personalizado',
downloader: 'Gerenciamento de downloads',
downloader: 'Download de modelos',
modelDirectoryHelper:
'Por padrão, a lista exibe os modelos baixados no diretório configurado em Preparação de modelos > Configurações.',
modelDirectoryPlaceholder: 'Buscar modelos ou inserir um caminho completo',
@@ -1146,8 +1176,7 @@ const message = {
endpointLabel: 'Endpoint do {0}',
acceleratedEndpointLabel: 'Endpoint de aceleração do {0}',
tokenLabel: 'Token do {0}',
hfEndpointHelper:
'Configure um endpoint de aceleração quando o acesso ao HuggingFace estiver instável. A pesquisa, os detalhes e os downloads usarão esse endereço.',
hfEndpointHelper: 'URL de espelho opcional para buscas, detalhes e downloads de modelos do HuggingFace.',
sortDefault: 'Ordenação padrão',
sortMostParameters: 'Mais parâmetros',
sortLeastParameters: 'Menos parâmetros',
@@ -5145,8 +5174,6 @@ const message = {
customScriptHelper:
'Por favor, insira o comando de inicialização completo, por exemplo: npm run start. Para comandos de inicialização do PM2, substitua por pm2-runtime, caso contrário irá falhar ao iniciar.',
portError: 'Evite repetir a mesma porta.',
systemRestartHelper:
'Descrição do status: Interrupção - falha ao adquirir status devido à reinicialização do sistema.',
javaScriptHelper:
'Forneça um comando completo de inicialização. Por exemplo, "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'O diretório deve conter arquivos jar, subdiretórios também são aceitos.',
+37 -7
View File
@@ -1040,6 +1040,29 @@ const message = {
'Перед сохранением создаётся одно минимальное изображение; возможна оплата',
},
model: {
searchTitle: 'Поиск и загрузка моделей',
searchHelper:
'Найдите модели в ModelScope или Hugging Face, затем разверните их или создайте Recipe в разделе подготовки моделей.',
modelScopeSearchHelper: 'Стабильный доступ в материковом Китае',
huggingFaceSearchHelper: 'Большой выбор моделей',
searchPlaceholder: 'Введите имя модели или ID репозитория, например Qwen/Qwen3-8B',
popularSearches: 'Популярные запросы',
searchSort: 'Сортировка',
onlyTokenizer: 'Только токенизатор',
downloadStatus: 'Статус загрузки',
downloaded: 'Загружено',
alreadyExists: 'Уже существует',
downloadCompleted: 'Загрузка завершена',
localFilesMissing: 'Локальные файлы не найдены',
ollamaNameHelper:
'Введите полное имя модели из библиотеки Ollama. Если тег не указан, используется latest.',
downloadHelper: 'Нажмите «Поиск», чтобы найти и загрузить модели из ModelScope и Hugging Face.',
serviceHelper:
'Подключайте сервисы моделей из публичных облаков, локальных движков инференса и шлюзов ИИ для встроенных агентов 1Panel и внешних агентов, таких как WorkBuddy.',
gpuType: 'Тип GPU',
vllmVersion: 'Версия vLLM',
vllmImage: 'Образ vLLM',
servicePort: 'Порт сервиса',
gpuAcceleration: 'Ускорение GPU',
gpuMode: 'Выбор ускорителей',
gpuAll: 'Все ускорители',
@@ -1071,7 +1094,14 @@ const message = {
approxWeightSize: 'Около {0} ГБ',
services: 'Сервисы моделей',
addInstance: 'Добавить экземпляр',
addService: 'Добавить сервис модели',
modelScopeEndpointHelper:
'Для поиска и загрузки моделей ModelScope. По умолчанию используется официальный URL.',
modelTokenHelper: 'Необязательно. Для закрытых моделей нужен токен с правами доступа.',
modelDirHelper: 'Каталог загрузки моделей и источник списка локальных моделей.',
featuredModelsHelper:
'Официальный каталог рекомендуемых моделей 1Panel. Обновляйте вручную или включите автоматическую синхронизацию каждые 24 часа. Обновляется только каталог, без загрузки файлов моделей.',
addInstanceHelper: 'Создайте экземпляр vLLM для обслуживания загруженных моделей.',
addService: 'Добавить',
onlineModel: 'Онлайн-модели',
instanceDeployment: 'Развертывание по экземплярам',
engines: 'Локальные движки инференса',
@@ -1093,11 +1123,11 @@ const message = {
recipeArguments: 'Параметры запуска',
recipeImportCommand: 'Импорт команды',
recipeImportPlaceholder:
'Вставьте сюда команду запуска в формате pip/uv или Docker. 1Panel автоматически разберёт её и заполнит Recipe.',
'Вставьте сюда команду запуска в формате pip/uv или docker. 1Panel автоматически разберёт её и заполнит форму.',
recipeVariablesNotSupported:
'Ссылки на переменные в командах не поддерживаются. Укажите конкретные значения; переменные окружения настройте в соответствующем поле.',
recipeImportError:
'Не удалось преобразовать. Добавьте команду запуска Docker или vllm serve с моделью; вставляйте команды установки pip/uv вместе с командой запуска.',
'Допустимая команда запуска не найдена. Вставьте команду pip/uv или docker, содержащую модель.',
engineProvider: 'Движок / Поставщик',
endpoint: 'Конечная точка',
cloudAccount: 'Облачная учетная запись',
@@ -1108,7 +1138,8 @@ const message = {
model: 'Модель',
localModel: 'Локальные модели',
create_helper: 'Загрузить "{0}"',
ollama_doc: 'Вы можете посетить официальный сайт Ollama, чтобы искать и находить больше моделей.',
ollama_doc:
'Найдите модели на {link}. После добавления модель будет загружена автоматически. Убедитесь, что Ollama работает и на диске достаточно места.',
container_conn_helper: 'Используйте этот адрес для доступа или подключения между контейнерами',
from_remote: 'Эта модель не была загружена через 1Panel, нет связанных журналов извлечения.',
no_logs: 'Журналы извлечения для этой модели были удалены и не могут быть просмотрены.',
@@ -1129,7 +1160,7 @@ const message = {
'Адрес контейнера подходит для контейнеров агентов; 127.0.0.1, системный IP или пользовательский адрес подходит для AI Gateway или внешних сервисов.',
containerAddress: 'Адрес контейнера',
customAddress: 'Пользовательский адрес',
downloader: 'Управление загрузками',
downloader: 'Загрузка моделей',
modelDirectoryHelper:
'По умолчанию список показывает модели, загруженные в каталог, указанный в разделе «Подготовка моделей > Настройки».',
modelDirectoryPlaceholder: 'Найти модель или ввести полный путь',
@@ -1141,7 +1172,7 @@ const message = {
acceleratedEndpointLabel: 'Endpoint ускорения {0}',
tokenLabel: '{0} Token',
hfEndpointHelper:
'Настройте endpoint ускорения, если доступ к HuggingFace нестабилен. Он будет использоваться для поиска, деталей и загрузок.',
'Необязательный URL зеркала для поиска, просмотра сведений и загрузки моделей HuggingFace.',
sortDefault: 'Сортировка по умолчанию',
sortMostParameters: 'Больше всего параметров',
sortLeastParameters: 'Меньше всего параметров',
@@ -5115,7 +5146,6 @@ const message = {
customScriptHelper:
'Пожалуйста, введите полную команду запуска, например: npm run start. Для команд запуска PM2 замените на pm2-runtime, иначе запуск завершится ошибкой.',
portError: 'Не повторяйте один и тот же порт.',
systemRestartHelper: 'Описание статуса: Прерывание - получение статуса не удалось из-за перезагрузки системы',
javaScriptHelper: 'Укажите полную команду запуска. Например, "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'Директория должна содержать jar файлы, поддиректории также допустимы',
goHelper: 'Укажите полную команду запуска. Например, "go run main.go" или "./main".',
+37 -8
View File
@@ -1050,6 +1050,29 @@ const message = {
validateImageAvailabilityHelper: 'Kaydetmeden önce bir küçük görsel üretir ve ücret doğurabilir',
},
model: {
searchTitle: 'Model ara ve indir',
searchHelper:
'ModelScope veya Hugging Face üzerinde model bulun, ardından Model Hazırlığı bölümünde dağıtın veya bir Recipe oluşturun.',
modelScopeSearchHelper: 'Çin ana karasında kararlı erişim',
huggingFaceSearchHelper: 'Geniş model koleksiyonu',
searchPlaceholder: 'Model adı veya depo kimliği girin, ör. Qwen/Qwen3-8B',
popularSearches: 'Popüler aramalar',
searchSort: 'Sırala',
onlyTokenizer: 'Yalnızca belirteç ayırıcı',
downloadStatus: 'İndirme durumu',
downloaded: 'İndirildi',
alreadyExists: 'Zaten mevcut',
downloadCompleted: 'İndirme tamamlandı',
localFilesMissing: 'Yerel dosyalar bulunamadı',
ollamaNameHelper: 'Ollama kütüphanesindeki tam model adını girin. Etiket belirtilmezse latest kullanılır.',
downloadHelper:
'ModelScope ve Hugging Face üzerindeki modelleri bulup indirmek için “Ara” düğmesine tıklayın.',
serviceHelper:
'Genel bulutlardan, yerel çıkarım motorlarından ve AI ağ geçitlerinden model hizmetlerini bağlayarak yerleşik 1Panel ajanları ve WorkBuddy gibi harici ajanlar için kullanıma sunun.',
gpuType: 'GPU türü',
vllmVersion: 'vLLM sürümü',
vllmImage: 'vLLM imajı',
servicePort: 'Hizmet portu',
gpuAcceleration: 'GPU hızlandırma',
gpuMode: 'Hızlandırıcı seçimi',
gpuAll: 'Tüm hızlandırıcılar',
@@ -1080,7 +1103,14 @@ const message = {
approxWeightSize: 'Yaklaşık {0} GB',
services: 'Model hizmetleri',
addInstance: 'Örnek ekle',
addService: 'Model hizmeti ekle',
modelScopeEndpointHelper:
'ModelScope modellerini aramak ve indirmek için kullanılır. Varsayılan, resmî URL adresidir.',
modelTokenHelper: 'İsteğe bağlı. Özel veya kısıtlı modeller için erişim yetkili bir token kullanın.',
modelDirHelper: 'Modellerin indirildiği ve yerel model listesinin okunduğu dizin.',
featuredModelsHelper:
'1Panel resmî öne çıkan model kataloğu. Elle yenileyin veya 24 saatte bir otomatik eşitlemeyi etkinleştirin. Yalnızca katalog güncellenir; model dosyaları indirilmez.',
addInstanceHelper: 'İndirilen modelleri sunmak için bir vLLM örneği oluşturun.',
addService: 'Ekle',
onlineModel: 'Çevrimiçi modeller',
instanceDeployment: 'Örnek bazında dağıtım',
engines: 'Yerel çıkarım motorları',
@@ -1102,11 +1132,11 @@ const message = {
recipeArguments: 'Başlatma parametreleri',
recipeImportCommand: 'Komut içe aktar',
recipeImportPlaceholder:
'pip/uv veya Docker biçimindeki başlatma komutunu buraya yapıştırın. 1Panel komutu otomatik olarak ayrıştırıp Recipe alanlarını doldurur.',
'pip/uv veya docker biçimindeki başlatma komutunu buraya yapıştırın. 1Panel komutu otomatik olarak ayrıştırıp form alanlarını doldurur.',
recipeVariablesNotSupported:
'Komutlarda değişken başvuruları desteklenmez. Açık değerler girin; ortam değişkenlerini ilgili alanda yapılandırın.',
recipeImportError:
'Dönüştürülemedi. Model içeren bir Docker veya vllm serve başlatma komutu ekleyin; pip/uv kurulum komutlarını başlatma komutuyla birlikte yapıştırın.',
'Geçerli bir başlatma komutu algılanmadı. Model içeren bir pip/uv veya docker komutu yapıştırın.',
engineProvider: 'Motor / Sağlayıcı',
endpoint: 'Uç nokta',
cloudAccount: 'Bulut hesabı',
@@ -1117,7 +1147,8 @@ const message = {
model: 'Model',
localModel: 'Yerel Modeller',
create_helper: '"{0}" çek',
ollama_doc: 'Daha fazla model aramak ve bulmak için Ollama resmi web sitesini ziyaret edebilirsiniz.',
ollama_doc:
'Modelleri {link} adresinde bulun. Model eklendikten sonra otomatik olarak indirilir. Ollama hizmetinin çalıştığından ve yeterli disk alanı olduğundan emin olun.',
container_conn_helper: 'Konteynerler arası erişim veya bağlantı için bu adresi kullanın',
from_remote: 'Bu model 1Panel aracılığıyla indirilmedi, ilgili çekme logları yok.',
no_logs: 'Bu modelin çekme logları silindi ve görüntülenemiyor.',
@@ -1137,7 +1168,7 @@ const message = {
'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',
customAddress: 'Özel adres',
downloader: 'İndirme yönetimi',
downloader: 'Model indirme',
modelDirectoryHelper:
'Model listesi varsayılan olarak Model Hazırlığı > Ayarlar bölümünde yapılandırılan dizine indirilen modelleri gösterir.',
modelDirectoryPlaceholder: 'Model arayın veya tam yol girin',
@@ -1149,7 +1180,7 @@ const message = {
acceleratedEndpointLabel: '{0} hızlandırma endpointi',
tokenLabel: '{0} Token',
hfEndpointHelper:
'HuggingFace erişimi kararsız olduğunda bir hızlandırma endpointi yapılandırın. Arama, ayrıntılar ve indirmeler bunu kullanır.',
'HuggingFace model aramaları, ayrıntıları ve indirmeleri için isteğe bağlı ayna URL adresi.',
sortDefault: 'Varsayılan sıralama',
sortMostParameters: 'En çok parametre',
sortLeastParameters: 'En az parametre',
@@ -5127,8 +5158,6 @@ const message = {
customScriptHelper:
'Lütfen tam başlatma komutunu girin, örneğin: npm run start. PM2 başlatma komutları için lütfen pm2-runtime ile değiştirin, aksi takdirde başlatma başarısız olacaktır.',
portError: 'Aynı portu tekrarlamayın.',
systemRestartHelper:
'Durum açıklaması: Kesinti - sistem yeniden başlatılması nedeniyle durum alımı başarısız oldu',
javaScriptHelper: 'Tam bir başlatma komutu sağlayın. Örneğin, "java -jar halo.jar -Xmx1024M -Xms256M".',
javaDirHelper: 'Dizin, jar dosyalarını içermeli, alt dizinler de kabul edilir',
goHelper: 'Tam bir başlatma komutu sağlayın. Örneğin, "go run main.go" veya "./main".',
+33 -8
View File
@@ -980,6 +980,27 @@ const message = {
validateImageAvailabilityHelper: '儲存前會實際產生一張最小圖片,可能產生費用',
},
model: {
searchTitle: '搜尋並下載模型',
searchHelper: '從 ModelScope 或 Hugging Face 尋找模型,下載後可在模型準備中部署或建立 Recipe。',
modelScopeSearchHelper: '中國大陸存取穩定',
huggingFaceSearchHelper: '模型資源豐富',
searchPlaceholder: '輸入模型名稱或儲存庫 ID,例如 Qwen/Qwen3-8B',
popularSearches: '熱門搜尋',
searchSort: '排序',
onlyTokenizer: '僅下載分詞器',
downloadStatus: '下載狀態',
downloaded: '已下載',
alreadyExists: '已存在',
downloadCompleted: '下載完成',
localFilesMissing: '找不到本機檔案',
ollamaNameHelper: '請填寫 Ollama 模型庫中的完整模型名稱,未指定標籤時預設使用 latest。',
downloadHelper: '點擊「搜尋」按鈕,即可查找並下載 ModelScope、Hugging Face 上的模型。',
serviceHelper:
'統一接入公有雲、本機推論引擎和 AI 閘道等模型服務,供 1Panel 內建智慧體及 WorkBuddy 等外部智慧體呼叫。',
gpuType: 'GPU 類型',
vllmVersion: 'vLLM 版本',
vllmImage: 'vLLM 映像檔',
servicePort: '服務連接埠',
gpuAcceleration: 'GPU 加速',
gpuMode: '加速卡選擇',
gpuAll: '全部加速卡',
@@ -1010,7 +1031,13 @@ const message = {
approxWeightSize: '約 {0} GB',
services: '模型服務',
addInstance: '新增實例',
addService: '新增模型服務',
modelScopeEndpointHelper: '用於搜尋和下載 ModelScope 模型,預設使用官方位址。',
modelTokenHelper: '選填,存取私人或受限模型時需填寫具備權限的 Token。',
modelDirHelper: '模型下載儲存目錄,也用於讀取本機模型清單。',
featuredModelsHelper:
'1Panel 官方精選模型目錄,可手動重新整理或開啟每 24 小時自動同步,僅更新目錄,不下載模型檔案。',
addInstanceHelper: '建立 vLLM 執行個體,將已下載的模型部署為模型服務。',
addService: '新增',
onlineModel: '線上模型',
instanceDeployment: '按執行個體部署',
engines: '本機推理引擎',
@@ -1031,10 +1058,9 @@ const message = {
'前往 {link},依序選擇模型提供商和目標模型,再根據硬體、量化版本及部署策略等選項產生啟動命令。',
recipeArguments: '啟動參數',
recipeImportCommand: '匯入命令',
recipeImportPlaceholder: '貼上 pip/uv 或 Docker 格式的啟動命令,1Panel 將自動解析並填入 Recipe。',
recipeImportPlaceholder: '貼上 pip/uv 或 docker 格式的啟動命令,1Panel 將自動解析並填入。',
recipeVariablesNotSupported: '命令中不支援變數引用,請填寫具體值;環境變數請在環境變數欄設定。',
recipeImportError:
'無法轉換,請提供包含模型的 Docker 或 vllm serve 啟動命令;pip/uv 安裝命令需要與啟動命令一起貼上。',
recipeImportError: '未識別到有效的啟動命令,請貼上包含模型的 pip/uv 或 docker 命令。',
engineProvider: '引擎 / 供應商',
endpoint: '端點',
cloudAccount: '雲端帳號',
@@ -1045,7 +1071,7 @@ const message = {
model: '模型',
localModel: '本地模型',
create_helper: '拉取 "{0}"',
ollama_doc: '您可以瀏覽 Ollama 官方網站,搜尋並尋找更多模型。',
ollama_doc: '前往 {link} 查找模型,新增後會自動拉取模型,請確保 Ollama 服務正常運作且磁碟空間充足。',
container_conn_helper: '容器間瀏覽或連接使用此地址',
from_remote: '該模型並非透過 1Panel 下載,無相關拉取日誌。',
no_logs: '該模型的拉取日誌已被刪除,無法檢視相關日誌。',
@@ -1065,7 +1091,7 @@ const message = {
'容器地址適合智能體容器呼叫;127.0.0.1、本機 IP 或自訂地址適合 AI 閘道或外部服務呼叫。',
containerAddress: '容器地址',
customAddress: '自訂地址',
downloader: '下載管理',
downloader: '模型下載',
modelDirectoryHelper: '模型列表預設來自「模型準備 > 設定」中配置的模型目錄,顯示該目錄下已下載的模型。',
modelDirectoryPlaceholder: '搜尋模型或輸入完整路徑',
selectModelDirectory: '選擇目錄',
@@ -1075,7 +1101,7 @@ const message = {
endpointLabel: '{0} 地址',
acceleratedEndpointLabel: '{0} 加速地址',
tokenLabel: '{0} Token',
hfEndpointHelper: '國內存取 HuggingFace 不穩定時可設定加速地址,搜尋、詳情和下載都會使用該地址。',
hfEndpointHelper: '選填,用於加速 HuggingFace 模型的搜尋、詳細資訊查詢和下載。',
sortDefault: '綜合排序',
sortMostParameters: '參數最多',
sortLeastParameters: '參數最少',
@@ -4695,7 +4721,6 @@ const message = {
customScript: '自訂啟動指令',
customScriptHelper: '請填寫完整的啟動指令,例:npm run start,pm2 啟動指令請換為 pm2-runtime,否則會啟動失敗',
portError: '不能填寫相同連接埠',
systemRestartHelper: '狀態說明:中斷-系統重新啟動導致狀態取得失敗',
javaScriptHelper: '請填寫完整啟動指令,例:java -jar halo.jar -Xmx1024M -Xms256M',
javaDirHelper: '目錄中要包含 jar 包,子目錄中包含也可',
goHelper: '請填寫完整啟動指令,例:go run main.go 或 ./main',
+33 -8
View File
@@ -993,6 +993,27 @@ const message = {
validateImageAvailabilityHelper: '保存前会真实生成一张最小图片,可能产生费用',
},
model: {
searchTitle: '搜索并下载模型',
searchHelper: '从 ModelScope 或 Hugging Face 查找模型,下载后可在模型准备中部署或创建 Recipe。',
modelScopeSearchHelper: '国内访问稳定',
huggingFaceSearchHelper: '模型资源丰富',
searchPlaceholder: '输入模型名称或仓库 ID,例如 Qwen/Qwen3-8B',
popularSearches: '热门搜索',
searchSort: '排序',
onlyTokenizer: '仅下载分词器',
downloadStatus: '下载状态',
downloaded: '已下载',
alreadyExists: '已存在',
downloadCompleted: '下载完成',
localFilesMissing: '本地文件未找到',
ollamaNameHelper: '请填写 Ollama 模型库中的完整模型名称,未指定标签时默认使用 latest。',
downloadHelper: '点击“搜索”按钮,即可查找并下载 ModelScope、Hugging Face 上的模型。',
serviceHelper:
'统一接入公有云、本地推理引擎和 AI 网关等模型服务,供 1Panel 内置智能体及 WorkBuddy 等外部智能体调用。',
gpuType: 'GPU 类型',
vllmVersion: 'vLLM 版本',
vllmImage: 'vLLM 镜像',
servicePort: '服务端口',
gpuAcceleration: 'GPU 加速',
gpuMode: '加速卡选择',
gpuAll: '全部加速卡',
@@ -1023,7 +1044,13 @@ const message = {
approxWeightSize: '约 {0} GB',
services: '模型服务',
addInstance: '新增实例',
addService: '添加模型服务',
modelScopeEndpointHelper: '用于搜索和下载 ModelScope 模型,默认使用官方地址。',
modelTokenHelper: '选填,访问私有或受限模型时需填写有权限的 Token。',
modelDirHelper: '模型下载保存目录,也用于读取本地模型列表。',
featuredModelsHelper:
'1Panel 官方精选模型目录,可手动刷新或开启每 24 小时自动同步,仅更新目录,不下载模型文件。',
addInstanceHelper: '创建 vLLM 实例,将已下载的模型部署为模型服务。',
addService: '添加',
onlineModel: '在线模型',
instanceDeployment: '按实例部署',
engines: '本地推理引擎',
@@ -1044,10 +1071,9 @@ const message = {
'前往 {link},依次选择模型提供商和目标模型,再根据硬件、量化版本及部署策略等选项生成启动命令。',
recipeArguments: '启动参数',
recipeImportCommand: '导入命令',
recipeImportPlaceholder: '粘贴 pip/uv 或 Docker 格式的启动命令,1Panel 将自动解析并填充 Recipe。',
recipeImportPlaceholder: '粘贴 pip/uv 或 docker 格式的启动命令,1Panel 将自动解析并填充。',
recipeVariablesNotSupported: '命令中不支持变量引用,请填写具体值;环境变量请在环境变量栏配置。',
recipeImportError:
'无法转换,请提供包含模型的 Docker 或 vllm serve 启动命令;pip/uv 安装命令需要与启动命令一起粘贴。',
recipeImportError: '未识别到有效的启动命令,请粘贴包含模型的 pip/uv 或 docker 命令。',
engineProvider: '引擎 / 供应商',
endpoint: '端点',
cloudAccount: '云端账号',
@@ -1058,7 +1084,7 @@ const message = {
model: '模型',
localModel: '本地模型',
create_helper: '拉取 "{0}"',
ollama_doc: '您可以访问 Ollama 官网,搜索并查找更多模型。',
ollama_doc: '前往 {link} 查找模型,添加后会自动拉取模型,请确保 Ollama 服务正常运行且磁盘空间充足。',
container_conn_helper: '容器间访问或连接使用此地址',
from_remote: '该模型并非通过 1Panel 下载,无相关拉取日志。',
no_logs: '该模型的拉取日志已被删除,无法查看相关日志。',
@@ -1078,7 +1104,7 @@ const message = {
'容器地址适合智能体容器调用;127.0.0.1、本机 IP 或自定义地址适合 AI 网关或外部服务调用。',
containerAddress: '容器地址',
customAddress: '自定义地址',
downloader: '下载管理',
downloader: '模型下载',
modelDirectoryHelper: '模型列表默认来自“模型准备 > 设置”中配置的模型目录,展示该目录下已下载的模型。',
modelDirectoryPlaceholder: '搜索模型或输入完整路径',
selectModelDirectory: '选择目录',
@@ -1088,7 +1114,7 @@ const message = {
endpointLabel: '{0} 地址',
acceleratedEndpointLabel: '{0} 加速地址',
tokenLabel: '{0} Token',
hfEndpointHelper: '国内访问 HuggingFace 不稳定时可配置加速地址,搜索、详情和下载都会使用该地址。',
hfEndpointHelper: '选填,用于加速 HuggingFace 模型的搜索、详情查询和下载。',
sortDefault: '综合排序',
sortMostParameters: '参数最多',
sortLeastParameters: '参数最少',
@@ -4737,7 +4763,6 @@ const message = {
customScript: '自定义启动命令',
customScriptHelper: '请填写完整的启动命令,例如:npm run start,pm2 启动命令请换为 pm2-runtime,否则会启动失败',
portError: '不能填写相同端口',
systemRestartHelper: '状态说明:中断-系统重启导致状态获取失败',
javaScriptHelper: '请填写完整启动命令,例如:java -jar halo.jar -Xmx1024M -Xms256M',
javaDirHelper: '目录中要包含 jar 包,子目录中包含也可',
goHelper: '请填写完整启动命令,例如:go run main.go 或 ./main',
+10
View File
@@ -22,6 +22,7 @@ export interface Deployment {
}
interface VllmAPI {
listVllmCommandTemplates: () => Promise<ResultData<Array<{ model: string }>>>;
pageVllm: (req: ReqPage & { info: string }) => Promise<ResultData<ResPage<Deployment>>>;
operateVllm: (
req: { id: number; operate: string; taskID: string; forceDelete?: boolean } & Partial<AI.ModelAccountSync>,
@@ -52,3 +53,12 @@ export async function readPages<T>(search: (page: ReqPage) => Promise<ResultData
}
}
}
export function matchesModelRecipe(recipeModel: string, modelPath: string, repoID = '') {
const path = modelPath.replace(/\/+$/, '');
const name = path.split('/').pop() || '';
const model = recipeModel.trim().replace(/\/+$/, '');
return Boolean(
model && [repoID || path.split('/').slice(-2).join('/'), path, name, `/models/${name}`].includes(model),
);
}
+7
View File
@@ -52,6 +52,13 @@
:only-icon="true"
/>
</template>
<template #prompt>
<el-alert
type="info"
:closable="false"
:title="$t(isLocal ? 'aiTools.model.addInstanceHelper' : 'aiTools.model.serviceHelper')"
/>
</template>
<template #main>
<ComplexTable
v-if="!isLocal"
@@ -2,17 +2,24 @@
<DrawerPro size="normal" v-model="drawerVisible" :header="$t('commons.button.add')" @close="handleClose">
<el-alert type="info" :closable="false">
<template #title>
<span class="flx-align-center">
{{ $t('aiTools.model.ollama_doc') }}
<el-button link class="ml-5" icon="Position" @click="goSearch()" type="primary">
{{ $t('firewall.quickJump') }}
</el-button>
</span>
<i18n-t keypath="aiTools.model.ollama_doc" tag="span" class="ollama-hint-text">
<template #link>
<a
class="ollama-link"
href="https://ollama.com/search"
target="_blank"
rel="noopener noreferrer"
>
ollama.com
</a>
</template>
</i18n-t>
</template>
</el-alert>
<el-form ref="formRef" label-position="top" class="mt-5" :model="form">
<el-form-item :label="$t('commons.table.name')" :rules="Rules.requiredInput" prop="name">
<el-input v-model.trim="form.name" />
<el-input v-model.trim="form.name" placeholder="qwen3.6:35b" />
<span class="input-help">{{ $t('aiTools.model.ollamaNameHelper') }}</span>
<span class="input-help" v-if="form.name">
{{
$t('aiTools.model.create_helper', [
@@ -80,10 +87,6 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
});
};
const goSearch = () => {
window.open('https://ollama.com/search', '_blank', 'noopener,noreferrer');
};
const handleClose = () => {
drawerVisible.value = false;
};
@@ -92,3 +95,23 @@ defineExpose({
acceptParams,
});
</script>
<style scoped>
.ollama-hint-text {
font-size: 13px;
font-weight: 400;
line-height: 1.7;
}
.ollama-link {
color: var(--el-color-primary);
font: inherit;
vertical-align: baseline;
text-decoration: none;
}
.ollama-link:hover {
text-decoration: underline;
text-underline-offset: 2px;
}
</style>
@@ -10,9 +10,6 @@
@is-exist="checkExist"
/>
</template>
<template #prompt>
<el-alert type="info" :closable="false" :title="$t('runtime.systemRestartHelper')" />
</template>
<template #leftToolBar>
<el-button v-permission :disabled="modelInfo.status !== 'Running'" type="primary" @click="onCreate">
{{ $t('commons.button.add') }}
@@ -89,9 +86,14 @@
<el-tooltip v-if="row.status === 'Unknown'" :content="row.message" placement="top">
<el-tag type="warning">{{ $t('commons.status.unknown') }}</el-tag>
</el-tooltip>
<el-tag v-if="row.status === 'Canceled'" type="danger">
{{ $t('commons.status.systemrestart') }}
</el-tag>
<el-tooltip
v-if="row.status === 'Canceled'"
:content="row.message"
:disabled="!row.message"
placement="top"
>
<el-tag type="danger">{{ $t('commons.status.systemrestart') }}</el-tag>
</el-tooltip>
<el-tag v-if="row.status === 'Failed'" type="danger">
{{ $t('commons.status.failed') }}
</el-tag>
+321 -133
View File
@@ -108,10 +108,23 @@
v-if="currentTab === 'downloader'"
title="model-download-refresh"
:rate="5"
@search="loadDownloads"
@search="refreshDownloadProgress"
/>
</div>
</template>
<template v-if="currentTab === 'featured' || currentTab === 'downloader'" #prompt>
<el-alert
type="info"
:closable="false"
:title="
$t(
currentTab === 'featured'
? 'aiTools.model.featuredModelsHelper'
: 'aiTools.model.downloadHelper',
)
"
/>
</template>
<template #main>
<ComplexTable
v-if="currentTab === 'featured'"
@@ -214,18 +227,20 @@
:pagination-config="downloadPagination"
@search="loadDownloads"
>
<el-table-column prop="source" :label="$t('aiTools.model.modelSource')" width="120">
<el-table-column prop="repoID" :label="$t('aiTools.model.repoID')" min-width="280">
<template #default="{ row }">
{{ sourceLabel(row.source) }}
<div class="download-repo-id" :title="row.repoID">{{ row.repoID }}</div>
<div class="download-source">
<svg-icon
v-if="row.source === 'modelscope' || row.source === 'huggingface'"
:iconName="row.source === 'modelscope' ? 'p-modelscope' : 'p-huggingface1'"
class="download-source-icon"
/>
<span>{{ sourceLabel(row.source) }}</span>
</div>
</template>
</el-table-column>
<el-table-column
prop="repoID"
:label="$t('aiTools.model.repoID')"
min-width="240"
show-overflow-tooltip
/>
<el-table-column :label="$t('modelDownloadExtra.content')" width="140">
<el-table-column :label="$t('commons.table.type')" width="140">
<template #default="{ row }">
{{
$t(
@@ -236,59 +251,65 @@
}}
</template>
</el-table-column>
<el-table-column prop="status" :label="$t('commons.table.status')" width="120">
<template #default="{ row }">
<el-tooltip :content="row.errorMessage" :disabled="!row.errorMessage" placement="top">
<el-tag :type="statusTagType(row.status)" round effect="light" size="small">
<span class="status-tag-content">
<span>{{ statusText(row.status) }}</span>
<el-icon v-if="row.status === 'Downloading'" class="is-loading">
<Loading />
</el-icon>
</span>
</el-tag>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="$t('aiTools.model.progress')" min-width="220">
<el-table-column prop="status" :label="$t('aiTools.model.downloadStatus')" min-width="260">
<template #default="{ row }">
<div class="progress-cell">
<el-progress
class="progress-bar"
:percentage="formatProgress(row.progress)"
:stroke-width="6"
/>
<span
v-if="formatSizePair(row.downloadedSize, row.totalSize)"
class="progress-size"
:title="formatSizePair(row.downloadedSize, row.totalSize)"
>
{{ formatSizePair(row.downloadedSize, row.totalSize) }}
</span>
<div class="progress-track">
<el-progress
:percentage="formatProgress(row.progress)"
:show-text="false"
:stroke-width="4"
/>
<span class="progress-percentage">{{ formatProgress(row.progress) }}%</span>
</div>
<div class="download-size-row">
<span class="progress-size">
{{
row.status === 'Success'
? row.localModel
? row.localModel.sizeFormatted || formatBytes(row.localModel.size)
: '—'
: formatSizePair(row.downloadedSize, row.totalSize) || '—'
}}
</span>
<el-tooltip :content="statusText(row, true)" placement="top">
<span class="download-status" :aria-label="statusText(row, true)" tabindex="0">
<el-icon
class="download-status-icon"
:class="{ 'is-loading': row.status === 'Downloading' }"
aria-hidden="true"
>
<Loading v-if="row.status === 'Downloading'" />
<Warning v-else-if="row.status === 'Success' && !row.localModel" />
<Select v-else-if="row.status === 'Success'" />
<Close v-else-if="row.status === 'Failed'" />
<Minus v-else-if="row.status === 'Canceled'" />
<Clock v-else />
</el-icon>
<span class="download-status-text">{{ statusText(row) }}</span>
</span>
</el-tooltip>
</div>
</div>
</template>
</el-table-column>
<el-table-column
prop="targetDir"
:label="$t('aiTools.model.modelDir')"
min-width="260"
show-overflow-tooltip
>
<el-table-column prop="targetDir" :label="$t('aiTools.model.modelDir')" width="110" align="center">
<template #default="{ row }">
<el-button
v-permission:view="'host_file_view'"
link
type="primary"
class="model-path-link"
:title="row.targetDir"
@click="openLocalModelPath(row.targetDir)"
>
{{ row.targetDir }}
</el-button>
<el-tooltip :content="row.targetDir" placement="top">
<el-button
v-permission:view="'host_file_view'"
link
type="primary"
:aria-label="$t('aiTools.model.modelDir') + ': ' + row.targetDir"
@click="openLocalModelPath(row.targetDir)"
>
<el-icon><Folder /></el-icon>
</el-button>
</el-tooltip>
</template>
</el-table-column>
<el-table-column :label="$t('file.size')" width="120">
<template #default="{ row }">{{ row.localModel?.sizeFormatted || '-' }}</template>
<el-table-column prop="recipeCount" label="Recipes" width="90" align="center">
<template #default="{ row }">{{ row.recipeCount ?? '—' }}</template>
</el-table-column>
<el-table-column prop="createdAt" :label="$t('commons.table.date')" width="180" />
<el-table-column :label="$t('commons.table.operate')" width="240" fixed="right">
@@ -300,8 +321,9 @@
{{ $t('commons.button.retry') }}
</el-button>
<el-button
v-if="row.downloadType === 'all' && row.status === 'Success' && row.localModel"
v-if="row.status === 'Success' && row.localModel"
v-permission
:disabled="row.downloadType === 'tokenizer'"
link
type="primary"
@click="emit('deploy', row.localModel.path)"
@@ -309,14 +331,9 @@
{{ $t('aiTools.model.deploy') }}
</el-button>
<el-button
v-if="
recipesView &&
isProductPro &&
row.downloadType === 'all' &&
row.status === 'Success' &&
row.localModel
"
v-if="recipesView && isProductPro && row.status === 'Success' && row.localModel"
v-permission
:disabled="row.downloadType === 'tokenizer'"
link
type="primary"
@click="
@@ -352,6 +369,7 @@
<el-col :xs="24" :sm="20" :md="15" :lg="12" :xl="12">
<el-form-item :label="$t('aiTools.model.modelDir')" prop="modelDir">
<el-input v-model="settings.modelDir" />
<span class="input-help">{{ $t('aiTools.model.modelDirHelper') }}</span>
</el-form-item>
<el-form-item
:label="$t('aiTools.model.acceleratedEndpointLabel', ['HuggingFace'])"
@@ -362,6 +380,7 @@
</el-form-item>
<el-form-item :label="$t('aiTools.model.tokenLabel', ['HuggingFace'])" prop="hfToken">
<el-input v-model="settings.hfToken" show-password />
<span class="input-help">{{ $t('aiTools.model.modelTokenHelper') }}</span>
</el-form-item>
<el-form-item
:label="$t('aiTools.model.endpointLabel', ['ModelScope'])"
@@ -371,12 +390,14 @@
v-model="settings.modelScopeEndpoint"
placeholder="https://www.modelscope.cn"
/>
<span class="input-help">{{ $t('aiTools.model.modelScopeEndpointHelper') }}</span>
</el-form-item>
<el-form-item
:label="$t('aiTools.model.tokenLabel', ['ModelScope'])"
prop="modelScopeToken"
>
<el-input v-model="settings.modelScopeToken" show-password />
<span class="input-help">{{ $t('aiTools.model.modelTokenHelper') }}</span>
</el-form-item>
<el-form-item>
<el-button
@@ -395,23 +416,57 @@
</template>
</LayoutContent>
<DrawerPro v-model="searchOpen" :header="$t('commons.button.search')" size="50%" :full-screen="true">
<DrawerPro
v-model="searchOpen"
:header="$t('aiTools.model.searchTitle')"
:size="isMobile ? 'full' : 'min(1100px, 90vw)'"
:full-screen="true"
>
<el-alert class="search-intro" type="info" :closable="false" :title="$t('aiTools.model.searchHelper')" />
<div class="source-switch">
<SourceSelect
v-model="currentSource"
:sources="['modelscope', 'huggingface']"
show-description
@update:model-value="handleSourceChange"
/>
</div>
<form class="search-row" @submit.prevent="handleSearchSubmit">
<el-input
v-model="searchForm.query"
class="search-input"
clearable
:placeholder="$t('aiTools.model.searchPlaceholder')"
:aria-label="$t('aiTools.model.searchPlaceholder')"
/>
<el-button type="primary" native-type="submit" :loading="searchCardLoading">
{{ $t('commons.button.search') }}
</el-button>
</form>
<div class="popular-searches">
<span>{{ $t('aiTools.model.popularSearches') }}</span>
<el-button
v-for="keyword in ['Qwen3', 'DeepSeek', 'GLM', 'embedding']"
:key="keyword"
link
type="primary"
@click="
searchForm.query = keyword;
handleSearchSubmit();
"
>
{{ keyword }}
</el-button>
</div>
<div v-loading="searchCardLoading">
<div class="search-row">
<TableSearch
v-model:searchName="searchForm.query"
class="search-input"
placeholder="Qwen"
@search="handleSearchSubmit"
/>
<el-select v-model="searchForm.sort" class="sort-select" @change="handleSortChange">
<div class="search-results-toolbar">
<el-select
v-model="searchForm.sort"
class="sort-select"
:aria-label="$t('aiTools.model.searchSort')"
@change="handleSortChange"
>
<template #prefix>{{ $t('aiTools.model.searchSort') }}</template>
<el-option
v-for="item in sortOptions"
:key="item.value"
@@ -448,9 +503,18 @@
</el-button>
</template>
</el-table-column>
<el-table-column :label="$t('file.size')" width="110">
<template #default="{ row }">
{{ row.size > 0 ? row.sizeFormatted || formatBytes(row.size) : '—' }}
</template>
</el-table-column>
<el-table-column prop="downloads" :label="$t('aiTools.model.downloadsCount')" width="130" />
<el-table-column prop="likes" :label="$t('aiTools.model.likes')" width="90" />
<el-table-column :label="$t('commons.table.operate')" width="200" fixed="right">
<el-table-column
:label="$t('commons.table.operate')"
min-width="240"
:fixed="isMobile ? false : 'right'"
>
<template #default="{ row }">
<el-button
v-permission
@@ -459,7 +523,7 @@
icon="Download"
@click="downloadRef?.acceptParams(row.repoID, 'all', [currentSource])"
>
{{ $t('aiTools.model.model') }}
{{ $t('commons.button.download') }}
</el-button>
<el-button
v-permission
@@ -468,7 +532,7 @@
icon="Download"
@click="downloadRef?.acceptParams(row.repoID, 'tokenizer', [currentSource])"
>
{{ $t('aiTools.benchmark.tokenizer') }}
{{ $t('aiTools.model.onlyTokenizer') }}
</el-button>
</template>
</el-table-column>
@@ -524,6 +588,7 @@ import {
updateFeaturedModelsSync,
} from '@/api/modules/model-downloader';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { loadVllmAPI, matchesModelRecipe } from '@/views/ai/model/deployment';
const emit = defineEmits<{ deploy: [modelDir: string] }>();
const { currentNode, isMobile, isOffline, language, isProductPro } = useGlobalStore();
@@ -579,7 +644,7 @@ const featuredFields = [
] as const;
const currentSource = ref<DownloaderSource>('modelscope');
const models = ref<ModelDownloader.ModelItem[]>([]);
const downloads = ref<ModelDownloader.TaskItem[]>([]);
const downloads = ref<Array<ModelDownloader.TaskItem & { recipeCount?: number }>>([]);
const searchOpen = ref(false);
watch(
[currentSource, currentNode, searchOpen],
@@ -629,7 +694,7 @@ const searchForm = reactive<ModelDownloader.ModelSearch>({
const searchPagination = reactive({
currentPage: 1,
pageSize: 50,
pageSize: 10,
total: 0,
});
@@ -751,9 +816,58 @@ const changeDownloadType = async () => {
};
let downloadRequest = 0;
let refreshingProgress = false;
const refreshDownloadProgress = async () => {
if (refreshingProgress || currentTab.value !== 'downloader') return;
const ids = downloads.value
.filter((row) => row.id && ['Waiting', 'Downloading'].includes(row.status))
.map((row) => row.id);
if (!ids.length) return;
const request = downloadRequest;
const node = currentNode.value;
refreshingProgress = true;
try {
const { data } = await pageModelDownloadTasks({
ids,
page: 1,
pageSize: ids.length,
info: '',
status: '',
includeLocal: true,
});
if (node !== currentNode.value || request !== downloadRequest || currentTab.value !== 'downloader') return;
const tasks = new Map((data.items || []).map((item) => [item.id, item]));
for (const row of downloads.value) {
const task = tasks.get(row.id);
if (!task) continue;
row.status = task.status;
row.progress = task.progress;
row.totalSize = task.totalSize;
row.downloadedSize = task.downloadedSize;
row.errorMessage = task.errorMessage;
row.startedAt = task.startedAt;
row.completedAt = task.completedAt;
row.canCancel = task.canCancel;
row.canRetry = task.canRetry;
row.canRemoveRecord = task.canRemoveRecord;
row.localModel = task.localModel;
}
} finally {
refreshingProgress = false;
}
};
const loadDownloads = async () => {
const request = ++downloadRequest;
const node = currentNode.value;
const recipeResult = Promise.allSettled([
recipesView && isProductPro.value
? loadVllmAPI().then((api) => {
if (node !== currentNode.value || request !== downloadRequest) return;
return api.listVllmCommandTemplates();
})
: Promise.resolve(undefined),
]);
const res = await pageModelDownloadTasks({
page: downloadPagination.currentPage,
pageSize: downloadPagination.pageSize,
@@ -769,6 +883,16 @@ const loadDownloads = async () => {
if (downloadPagination.currentPage > lastPage) {
downloadPagination.currentPage = lastPage;
await loadDownloads();
return;
}
const [result] = await recipeResult;
if (node !== currentNode.value || request !== downloadRequest) return;
const recipes = result.status === 'fulfilled' ? result.value?.data : undefined;
for (const row of downloads.value) {
row.recipeCount =
row.downloadType === 'tokenizer'
? 0
: recipes?.filter((recipe) => matchesModelRecipe(recipe.model, row.targetDir, row.repoID)).length;
}
};
@@ -861,34 +985,32 @@ const refreshCurrent = async () => {
}
};
const statusTagType = (status: string) => {
switch (status) {
case 'Success':
return 'success';
const statusText = (row: ModelDownloader.TaskItem, withDetail = false) => {
let key = 'commons.status.waiting';
switch (row.status) {
case 'Downloading':
return 'primary';
key = 'aiTools.model.downloading';
break;
case 'Success':
key = !row.localModel
? 'aiTools.model.downloadCompleted'
: row.id
? 'aiTools.model.downloaded'
: 'aiTools.model.alreadyExists';
break;
case 'Failed':
key = 'commons.status.failed';
break;
case 'Canceled':
return 'danger';
default:
return 'info';
key = 'aiTools.model.canceled';
break;
}
};
const statusText = (status: string) => {
if (status === 'Downloading') {
return i18n.global.t('aiTools.model.downloading');
}
if (status === 'Success') {
return i18n.global.t('commons.status.success');
}
if (status === 'Failed') {
return i18n.global.t('commons.status.failed');
}
if (status === 'Canceled') {
return i18n.global.t('aiTools.model.canceled');
}
return i18n.global.t('commons.status.waiting');
if (!withDetail) return i18n.global.t(key);
const detail =
row.status === 'Success' && !row.localModel
? i18n.global.t('aiTools.model.localFilesMissing')
: row.errorMessage;
return [i18n.global.t(key), detail].filter(Boolean).join(':');
};
const sourceLabel = (source: string) => {
@@ -903,7 +1025,7 @@ const sourceLabel = (source: string) => {
const formatBytes = (value: number) => {
if (!value) {
return '-';
return '0 B';
}
if (value < 1024 * 1024) {
return `${(value / 1024).toFixed(1)} KB`;
@@ -945,6 +1067,8 @@ watch(currentTab, async (value) => {
});
watch(currentNode, async () => {
downloadRequest++;
downloads.value = [];
recipeModelPath.value = '';
featuredRequest++;
featuredLoading.value = false;
@@ -1062,6 +1186,10 @@ onMounted(() => {
overflow-wrap: anywhere;
}
.search-intro {
margin-bottom: 20px;
}
.source-switch {
margin-bottom: 16px;
}
@@ -1075,63 +1203,123 @@ onMounted(() => {
.search-input {
flex: 1;
min-width: 0;
}
:deep(.search-button) {
width: 100%;
.popular-searches {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px 16px;
margin-top: 12px;
color: var(--el-text-color-secondary);
font-size: 12px;
.el-button {
margin-left: 0;
font-size: 12px;
}
}
.search-results-toolbar {
display: flex;
align-items: center;
justify-content: flex-end;
margin-top: 16px;
}
.sort-select {
flex: 0 0 160px;
width: 160px;
width: 220px;
}
.download-repo-id {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 20px;
}
.download-source {
display: flex;
align-items: center;
gap: 4px;
margin-top: 6px;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 16px;
}
.download-source-icon {
width: 14px;
height: 14px;
padding: 0;
flex-shrink: 0;
}
.progress-cell {
display: flex;
flex-direction: column;
align-items: stretch;
display: grid;
grid-template-rows: 16px 16px;
gap: 2px;
width: 100%;
}
.status-tag-content {
.progress-track {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
:deep(.el-progress) {
flex: 1;
min-width: 0;
}
}
.progress-percentage {
flex-shrink: 0;
width: 42px;
text-align: right;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 16px;
}
.download-size-row {
display: flex;
align-items: center;
gap: 6px;
min-width: 0;
}
.download-status {
display: inline-flex;
align-items: center;
gap: 4px;
margin-left: auto;
min-width: 0;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 16px;
}
.progress-bar {
flex: 1;
min-width: 110px;
.download-status-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
:deep(.el-progress__text) {
min-width: 36px;
margin-left: 6px;
font-size: 12px !important;
}
.download-status-icon {
flex-shrink: 0;
color: var(--el-text-color-secondary);
font-size: 14px;
}
.progress-size {
min-width: 0;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 14px;
line-height: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.model-path-link {
max-width: 100%;
justify-content: flex-start;
:deep(> span) {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
text-align: left;
}
}
</style>
@@ -10,7 +10,22 @@
@click="modelValue = source"
>
<svg-icon :iconName="source === 'modelscope' ? 'p-modelscope' : 'p-huggingface1'" class="source-icon" />
<span class="source-name">{{ source === 'modelscope' ? 'ModelScope' : 'HuggingFace' }}</span>
<span class="source-content">
<span class="source-heading">
<span class="source-name">{{ source === 'modelscope' ? 'ModelScope' : 'Hugging Face' }}</span>
<el-tag v-if="showDescription && source === 'modelscope'" size="small" effect="plain">
{{ $t('home.recommend') }}
</el-tag>
</span>
<span v-if="showDescription" class="source-description">
{{
$t(
'aiTools.model.' +
(source === 'modelscope' ? 'modelScopeSearchHelper' : 'huggingFaceSearchHelper'),
)
}}
</span>
</span>
</el-button>
</div>
</template>
@@ -18,7 +33,7 @@
<script setup lang="ts">
import type { ModelDownloader } from '@/api/interface/model-downloader';
defineProps<{ sources: ModelDownloader.Source[]; disabled?: boolean }>();
defineProps<{ sources: ModelDownloader.Source[]; disabled?: boolean; showDescription?: boolean }>();
const modelValue = defineModel<ModelDownloader.Source>({ required: true });
</script>
@@ -68,4 +83,23 @@ const modelValue = defineModel<ModelDownloader.Source>({ required: true });
text-overflow: ellipsis;
white-space: nowrap;
}
.source-content {
min-width: 0;
}
.source-heading {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.source-description {
display: block;
margin-top: 6px;
color: var(--el-text-color-secondary);
font-size: 12px;
line-height: 1.5;
}
</style>