mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-13 16:00:38 +00:00
fix(ai-gateway): support backup logic during app upgrades (#14072)
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||
"github.com/1Panel-dev/1Panel/agent/global"
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/files"
|
||||
)
|
||||
|
||||
func prepareAIGatewayAppRecover(install *model.AppInstall, recoverFile, secret string) (string, func(), error) {
|
||||
noop := func() {}
|
||||
if !isAIGatewayApp(install.App.Key) {
|
||||
return "", noop, nil
|
||||
}
|
||||
tmpDir, err := os.MkdirTemp(global.Dir.TmpDir, "ai-gateway-recover-")
|
||||
if err != nil {
|
||||
return "", noop, err
|
||||
}
|
||||
cleanup := func() { _ = os.RemoveAll(tmpDir) }
|
||||
fail := func(err error) (string, func(), error) {
|
||||
cleanup()
|
||||
return "", noop, err
|
||||
}
|
||||
if err := files.NewFileOp().TarGzExtractPro(recoverFile, tmpDir, secret); err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
backupDir := filepath.Join(tmpDir, strings.ReplaceAll(filepath.Base(recoverFile), ".tar.gz", ""))
|
||||
for _, name := range []string{"app.json", "app.tar.gz"} {
|
||||
info, err := os.Lstat(filepath.Join(backupDir, name))
|
||||
if err != nil || !info.Mode().IsRegular() {
|
||||
return fail(buserr.New("AppBackupFileIncomplete"))
|
||||
}
|
||||
}
|
||||
metadata, err := os.ReadFile(filepath.Join(backupDir, "app.json"))
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
var backup model.AppInstall
|
||||
if err := json.Unmarshal(metadata, &backup); err != nil {
|
||||
return fail(fmt.Errorf("unmarshal app.json failed: %w", err))
|
||||
}
|
||||
if backup.App.Key != install.App.Key || backup.Name != install.Name {
|
||||
return fail(buserr.New("AppAttributesNotMatch"))
|
||||
}
|
||||
// Historical backups already include Version. Unsuffixed releases are
|
||||
// SQLite; no new metadata field is required. Missing versions are invalid,
|
||||
// not evidence that an archive contains SQLite data.
|
||||
if strings.TrimSpace(backup.Version) == "" || strings.TrimSpace(install.Version) == "" {
|
||||
return fail(buserr.New("AppBackupFileIncomplete"))
|
||||
}
|
||||
// Deliberately do not compare version order: restoring an older version of
|
||||
// the same database type is required for failed-upgrade rollbacks.
|
||||
if !isAIGatewayUpgradeVersionAllowed(install.App.Key, install.Version, backup.Version) {
|
||||
return fail(buserr.New("ErrAIGatewayRecoverDatabaseTypeMismatch"))
|
||||
}
|
||||
return backupDir, cleanup, nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
||||
)
|
||||
|
||||
const aiGatewayAppKey = "ai-gateway"
|
||||
|
||||
func isAIGatewayApp(appKey string) bool {
|
||||
return appKey == aiGatewayAppKey || appKey == "local"+aiGatewayAppKey
|
||||
}
|
||||
|
||||
func isAIGatewayPostgresVersion(version string) bool {
|
||||
return strings.HasSuffix(version, "-pg") || strings.HasSuffix(version, "-postgres")
|
||||
}
|
||||
|
||||
// Database variants are deployment choices, not interchangeable upgrades.
|
||||
func isAIGatewayUpgradeVersionAllowed(appKey, currentVersion, targetVersion string) bool {
|
||||
return !isAIGatewayApp(appKey) ||
|
||||
isAIGatewayPostgresVersion(currentVersion) == isAIGatewayPostgresVersion(targetVersion)
|
||||
}
|
||||
|
||||
func sortAIGatewayVersions(versions []string) {
|
||||
sort.SliceStable(versions, func(i, j int) bool {
|
||||
if common.CompareVersion(versions[i], versions[j]) {
|
||||
return true
|
||||
}
|
||||
if common.CompareVersion(versions[j], versions[i]) {
|
||||
return false
|
||||
}
|
||||
// Prefer SQLite only when the numeric versions are equal.
|
||||
return !isAIGatewayPostgresVersion(versions[i]) && isAIGatewayPostgresVersion(versions[j])
|
||||
})
|
||||
}
|
||||
@@ -687,6 +687,9 @@ func (a *AppInstallService) GetUpdateVersions(req request.AppUpdateVersion) ([]d
|
||||
if !canAccessVllmVersion(app.Key, detail.Version) {
|
||||
continue
|
||||
}
|
||||
if !isAIGatewayUpgradeVersionAllowed(app.Key, install.Version, detail.Version) {
|
||||
continue
|
||||
}
|
||||
ignores, _ := appIgnoreUpgradeRepo.List(runtimeRepo.WithDetailId(detail.ID), appIgnoreUpgradeRepo.WithScope("version"))
|
||||
if len(ignores) > 0 {
|
||||
continue
|
||||
|
||||
@@ -106,6 +106,9 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isAIGatewayUpgradeVersionAllowed(install.App.Key, install.Version, detail.Version) {
|
||||
return buserr.New("ErrAIGatewayDatabaseTypeMismatch")
|
||||
}
|
||||
if err = checkVllmVersionAccess(install.App.Key, detail.Version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1571,6 +1571,9 @@ func handleInstalled(appInstallList []model.AppInstall, updated, sync, checkUpda
|
||||
|
||||
var versions []string
|
||||
for _, appDetail := range details {
|
||||
if !isAIGatewayUpgradeVersionAllowed(installed.App.Key, installed.Version, appDetail.Version) {
|
||||
continue
|
||||
}
|
||||
ignores, _ := appIgnoreUpgradeRepo.List(runtimeRepo.WithDetailId(appDetail.ID), appIgnoreUpgradeRepo.WithScope("version"))
|
||||
if len(ignores) > 0 {
|
||||
continue
|
||||
@@ -2279,7 +2282,12 @@ func getAppVersions(key string, details []model.AppDetail) []string {
|
||||
}
|
||||
versionsRaw = append(versionsRaw, detail.Version)
|
||||
}
|
||||
versions = common.GetSortedVersions(versionsRaw)
|
||||
if isAIGatewayApp(key) {
|
||||
sortAIGatewayVersions(versionsRaw)
|
||||
versions = versionsRaw
|
||||
} else {
|
||||
versions = common.GetSortedVersions(versionsRaw)
|
||||
}
|
||||
if hasLatest {
|
||||
versions = append([]string{latestVersion}, versions...)
|
||||
}
|
||||
|
||||
@@ -132,11 +132,9 @@ func (u *BackupService) AppRecover(req dto.CommonRecover) error {
|
||||
if !fileOp.Stat(req.File) {
|
||||
return buserr.WithName("ErrFileNotFound", req.File)
|
||||
}
|
||||
if _, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&install, nil, req.File, false, req.Secret, req.TaskID); err != nil {
|
||||
global.LOG.Errorf("recover app %s failed, err: %v", req.DetailName, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -200,8 +198,20 @@ func handleAppBackup(install *model.AppInstall, parentTask *task.Task, recordID
|
||||
}
|
||||
|
||||
func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverFile string, isRollback bool, secret, taskID string) error {
|
||||
// Validate AI Gateway backups before stopping the app, creating rollback
|
||||
// backups, or touching its files/database. Keep the validated extraction for
|
||||
// the restore so uploaded/encrypted archives are not unpacked twice.
|
||||
preparedPath, cleanup, err := prepareAIGatewayAppRecover(install, recoverFile, secret)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if parentTask == nil && !isRollback {
|
||||
if _, err := compose.Down(install.GetComposePath()); err != nil {
|
||||
cleanup()
|
||||
return err
|
||||
}
|
||||
}
|
||||
var (
|
||||
err error
|
||||
recoverTask *task.Task
|
||||
isOk = false
|
||||
rollbackFile string
|
||||
@@ -210,11 +220,13 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
if parentTask == nil {
|
||||
recoverTask, err = task.NewTaskWithOps(install.Name, task.TaskRecover, task.TaskScopeBackup, taskID, install.ID)
|
||||
if err != nil {
|
||||
cleanup()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
recoverApp := func(t *task.Task) error {
|
||||
defer cleanup()
|
||||
fileOp := files.NewFileOp()
|
||||
if !isRollback {
|
||||
rollbackFile = path.Join(global.Dir.TmpDir, fmt.Sprintf("app/%s_%s.tar.gz", install.Name, time.Now().Format(constant.DateTimeSlimLayout)))
|
||||
@@ -223,10 +235,13 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
}
|
||||
}
|
||||
|
||||
if err := fileOp.TarGzExtractPro(recoverFile, path.Dir(recoverFile), secret); err != nil {
|
||||
return err
|
||||
tmpPath := preparedPath
|
||||
if tmpPath == "" {
|
||||
if err := fileOp.TarGzExtractPro(recoverFile, path.Dir(recoverFile), secret); err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath = strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
}
|
||||
tmpPath := strings.ReplaceAll(recoverFile, ".tar.gz", "")
|
||||
if err := fileOp.TarGzExtractPro(tmpPath+"/app.tar.gz", tmpPath, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -236,7 +251,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
} else {
|
||||
_, _ = compose.Up(install.GetComposePath())
|
||||
}
|
||||
_ = os.RemoveAll(strings.ReplaceAll(recoverFile, ".tar.gz", ""))
|
||||
_ = os.RemoveAll(tmpPath)
|
||||
}()
|
||||
|
||||
if !fileOp.Stat(tmpPath+"/app.json") || !fileOp.Stat(tmpPath+"/app.tar.gz") {
|
||||
@@ -397,6 +412,7 @@ func handleAppRecover(install *model.AppInstall, parentTask *task.Task, recoverF
|
||||
}
|
||||
recoverTask.AddSubTask(task.GetTaskName(install.Name, task.TaskRecover, task.TaskScopeBackup), recoverApp, rollBackApp)
|
||||
go func() {
|
||||
defer cleanup()
|
||||
_ = recoverTask.Execute()
|
||||
}()
|
||||
return nil
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Unable to derive a project name from Docker Compose
|
||||
ErrComposeNameInvalid: 'Invalid Compose project name: it must start with a lowercase letter or number, contain only lowercase letters, numbers, hyphens, and underscores, and be 1-256 characters long.'
|
||||
ErrAppVersionUnavailable: 'This application version has been removed from the remote service. Please select another version and try again.'
|
||||
ErrVllmGB10ProOnly: 'This vLLM version is available only in 1Panel Professional Edition.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway can only upgrade within the same database type (SQLite or PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'The AI Gateway backup and target application must use the same database type (SQLite or PostgreSQL).'
|
||||
ErrAppWarn: 'App status abnormal; check logs'
|
||||
ErrAppParamKey: 'Invalid app parameter: {{ .name }}'
|
||||
ErrAppUpgrade: 'App upgrade failed: {{ .name }} {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'No se pudo derivar un nombre de proyecto desde la c
|
||||
ErrComposeNameInvalid: 'Nombre de proyecto Compose no válido: debe comenzar con una letra minúscula o un número, contener solo letras minúsculas, números, guiones y guiones bajos, y tener entre 1 y 256 caracteres.'
|
||||
ErrAppVersionUnavailable: 'Esta versión de la aplicación se ha eliminado del servicio remoto. Seleccione otra versión e inténtelo de nuevo.'
|
||||
ErrVllmGB10ProOnly: 'Esta versión de vLLM solo está disponible en 1Panel Professional Edition.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway solo puede actualizarse dentro del mismo tipo de base de datos (SQLite o PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'La copia de seguridad de AI Gateway y la aplicación de destino deben usar el mismo tipo de base de datos (SQLite o PostgreSQL).'
|
||||
ErrAppWarn: 'Estado anómalo, revise el log'
|
||||
ErrAppParamKey: 'El campo de parámetro {{ .name }} es anómalo'
|
||||
ErrAppUpgrade: 'La actualización de la aplicación {{ .name }} falló {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'نام پروژه از پیکربندی Docker Comp
|
||||
ErrComposeNameInvalid: 'نام پروژه Compose نامعتبر است: باید با حرف کوچک یا عدد شروع شود، فقط شامل حروف کوچک، اعداد، خط تیره و زیرخط باشد و ۱ تا ۲۵۶ نویسه داشته باشد.'
|
||||
ErrAppVersionUnavailable: 'این نسخه برنامه از سرویس راه دور حذف شده است. لطفاً نسخه دیگری را انتخاب کرده و دوباره تلاش کنید.'
|
||||
ErrVllmGB10ProOnly: 'این نسخه vLLM فقط در نسخه حرفهای 1Panel در دسترس است.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway فقط در همان نوع پایگاه داده (SQLite یا PostgreSQL) قابل ارتقا است.'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'نسخه پشتیبان AI Gateway و برنامه مقصد باید از یک نوع پایگاه داده (SQLite یا PostgreSQL) استفاده کنند.'
|
||||
ErrAppWarn: 'وضعیت برنامه غیرعادی است؛ لاگها را بررسی کنید'
|
||||
ErrAppParamKey: 'پارامتر برنامه نامعتبر است: {{ .name }}'
|
||||
ErrAppUpgrade: 'ارتقاء برنامه ناموفق بود: {{ .name }} {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose 設定またはファイルの親デ
|
||||
ErrComposeNameInvalid: 'Compose プロジェクト名の形式が正しくありません。小文字または数字で始まり、小文字、数字、ハイフン、アンダースコアのみを使用した 1~256 文字にしてください。'
|
||||
ErrAppVersionUnavailable: '現在のアプリケーションバージョンはリモートサービスから削除されています。別のバージョンを選択して再試行してください。'
|
||||
ErrVllmGB10ProOnly: 'この vLLM バージョンは 1Panel プロフェッショナル版でのみ利用できます。'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway は同じデータベース種別(SQLite または PostgreSQL)間でのみアップグレードできます。'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway のバックアップと復元先アプリのデータベース種別(SQLite または PostgreSQL)は一致している必要があります。'
|
||||
ErrAppWarn: '異常な状態です。ログを確認してください'
|
||||
ErrAppParamKey: 'パラメータ {{ .name }} フィールドが異常です'
|
||||
ErrAppUpgrade: 'アプリケーション {{ .name }} のアップグレードに失敗しました {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose 구성 또는 파일의 상위 디
|
||||
ErrComposeNameInvalid: 'Compose 프로젝트 이름 형식이 잘못되었습니다. 소문자 또는 숫자로 시작하고 소문자, 숫자, 하이픈, 밑줄만 사용하여 1~256자로 입력하세요.'
|
||||
ErrAppVersionUnavailable: '현재 애플리케이션 버전이 원격 서비스에서 제거되었습니다. 다른 버전을 선택한 후 다시 시도해 주세요.'
|
||||
ErrVllmGB10ProOnly: '이 vLLM 버전은 1Panel 프로페셔널 에디션에서만 사용할 수 있습니다.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway는 동일한 데이터베이스 유형(SQLite 또는 PostgreSQL) 내에서만 업그레이드할 수 있습니다.'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway 백업과 대상 애플리케이션의 데이터베이스 유형(SQLite 또는 PostgreSQL)이 같아야 합니다.'
|
||||
ErrAppWarn: '비정상적인 상태입니다. 로그를 확인해 주세요.'
|
||||
ErrAppParamKey: '매개변수 {{ .name }} 필드가 비정상입니다.'
|
||||
ErrAppUpgrade: '애플리케이션 {{ .name }} 업그레이드에 실패했습니다 {{ .err }}'
|
||||
|
||||
@@ -130,6 +130,8 @@ ErrComposeProjectNameEmpty: 'ບໍ່ສາມາດກຳນົດຊື່ໂ
|
||||
ErrComposeNameInvalid: 'ຊື່ໂຄງການ Compose ບໍ່ຖືກຕ້ອງ: ຕ້ອງເລີ່ມດ້ວຍຕົວພິມນ້ອຍ ຫຼື ຕົວເລກ, ໃຊ້ໄດ້ສະເພາະຕົວພິມນ້ອຍ, ຕົວເລກ, ຂີດກາງ ແລະ ຂີດລຸ່ມ, ຄວາມຍາວ 1-256 ຕົວອັກສອນ.'
|
||||
ErrAppVersionUnavailable: 'ເວີຊັນແອັບນີ້ຖືກລຶບອອກຈາກບໍລິການທາງໄກແລ້ວ ກະລຸນາເລືອກເວີຊັນອື່ນແລ້ວລອງໃໝ່'
|
||||
ErrVllmGB10ProOnly: 'ເວີຊັນ vLLM ນີ້ມີໃຫ້ໃຊ້ສະເພາະໃນ 1Panel Professional Edition ເທົ່ານັ້ນ.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway ສາມາດອັບເກຣດໄດ້ພາຍໃນປະເພດຖານຂໍ້ມູນດຽວກັນເທົ່ານັ້ນ (SQLite ຫຼື PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'ຂໍ້ມູນສຳຮອງ AI Gateway ແລະ ແອັບເປົ້າໝາຍຕ້ອງໃຊ້ປະເພດຖານຂໍ້ມູນດຽວກັນ (SQLite ຫຼື PostgreSQL).'
|
||||
ErrAppWarn: 'ສະຖານະແອັບຜິດປົກກະຕິ; ກະລຸນາກວດສອບບັນທຶກ'
|
||||
ErrAppParamKey: 'ພາຣາມິເຕີຂອງແອັບບໍ່ຖືກຕ້ອງ: {{ .name }}'
|
||||
ErrAppUpgrade: 'ອັບເກຣດແອັບລົ້ມເຫຼວ: {{ .name }} {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Nama projek tidak dapat diperoleh daripada konfigur
|
||||
ErrComposeNameInvalid: 'Nama projek Compose tidak sah: mesti bermula dengan huruf kecil atau nombor, hanya mengandungi huruf kecil, nombor, tanda sempang dan garis bawah, serta sepanjang 1-256 aksara.'
|
||||
ErrAppVersionUnavailable: 'Versi aplikasi ini telah dialih keluar daripada perkhidmatan jauh. Sila pilih versi lain dan cuba lagi.'
|
||||
ErrVllmGB10ProOnly: 'Versi vLLM ini hanya tersedia dalam 1Panel Edisi Profesional.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway hanya boleh dinaik taraf dalam jenis pangkalan data yang sama (SQLite atau PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'Sandaran AI Gateway dan aplikasi sasaran mesti menggunakan jenis pangkalan data yang sama (SQLite atau PostgreSQL).'
|
||||
ErrAppWarn: 'Status tidak normal, sila semak log'
|
||||
ErrAppParamKey: 'Parameter {{ .name }} medan tidak normal'
|
||||
ErrAppUpgrade: 'Peningkatan {{ .name }} aplikasi gagal {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Não foi possível derivar um nome de projeto da co
|
||||
ErrComposeNameInvalid: 'Nome de projeto Compose inválido: deve começar com uma letra minúscula ou número, conter apenas letras minúsculas, números, hífens e sublinhados e ter de 1 a 256 caracteres.'
|
||||
ErrAppVersionUnavailable: 'Esta versão do aplicativo foi removida do serviço remoto. Selecione outra versão e tente novamente.'
|
||||
ErrVllmGB10ProOnly: 'Esta versão do vLLM está disponível apenas no 1Panel Professional Edition.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'O AI Gateway só pode ser atualizado dentro do mesmo tipo de banco de dados (SQLite ou PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'O backup do AI Gateway e o aplicativo de destino devem usar o mesmo tipo de banco de dados (SQLite ou PostgreSQL).'
|
||||
ErrAppWarn: 'Status anormal, verifique o log'
|
||||
ErrAppParamKey: 'O campo de parâmetro {{ .name }} está anormal'
|
||||
ErrAppUpgrade: 'Falha na atualização do aplicativo {{ .name }} {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Не удалось получить имя про
|
||||
ErrComposeNameInvalid: 'Недопустимое имя проекта Compose: оно должно начинаться со строчной буквы или цифры, содержать только строчные буквы, цифры, дефисы и подчёркивания и иметь длину от 1 до 256 символов.'
|
||||
ErrAppVersionUnavailable: 'Эта версия приложения удалена из удаленного сервиса. Выберите другую версию и повторите попытку.'
|
||||
ErrVllmGB10ProOnly: 'Эта версия vLLM доступна только в профессиональной редакции 1Panel.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway можно обновлять только в пределах одного типа базы данных (SQLite или PostgreSQL).'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'Резервная копия AI Gateway и целевое приложение должны использовать один и тот же тип базы данных (SQLite или PostgreSQL).'
|
||||
ErrAppWarn: 'Ненормальное состояние, проверьте журнал'
|
||||
ErrAppParamKey: 'Поле параметра {{ .name }} ненормально'
|
||||
ErrAppUpgrade: 'Обновление приложения {{ .name }} не удалось {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: 'Docker Compose yapılandırmasından veya dosyanın
|
||||
ErrComposeNameInvalid: 'Geçersiz Compose proje adı: küçük harf veya rakamla başlamalı, yalnızca küçük harf, rakam, kısa çizgi ve alt çizgi içermeli ve 1-256 karakter uzunluğunda olmalıdır.'
|
||||
ErrAppVersionUnavailable: 'Bu uygulama sürümü uzak hizmetten kaldırıldı. Lütfen başka bir sürüm seçip tekrar deneyin.'
|
||||
ErrVllmGB10ProOnly: 'Bu vLLM sürümü yalnızca 1Panel Professional Edition sürümünde kullanılabilir.'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI Gateway yalnızca aynı veritabanı türü (SQLite veya PostgreSQL) içinde yükseltilebilir.'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI Gateway yedeği ve hedef uygulama aynı veritabanı türünü (SQLite veya PostgreSQL) kullanmalıdır.'
|
||||
ErrAppWarn: 'Anormal durum, lütfen günlüğü kontrol edin'
|
||||
ErrAppParamKey: 'Parametre {{ .name }} alanı anormal'
|
||||
ErrAppUpgrade: 'Uygulama {{ .name }} yükseltmesi başarısız {{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: '無法從 Docker Compose 設定或檔案父目錄
|
||||
ErrComposeNameInvalid: 'Compose 專案名稱格式錯誤:必須以小寫字母或數字開頭,僅支援小寫字母、數字、- 和 _,長度為 1-256 個字元'
|
||||
ErrAppVersionUnavailable: '目前應用程式版本已從遠端服務下架,請選擇其他版本後重試'
|
||||
ErrVllmGB10ProOnly: '此 vLLM 版本僅支援 1Panel 專業版'
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI 閘道只能在相同資料庫類型(SQLite 或 PostgreSQL)之間升級。'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI 閘道備份與目標應用程式的資料庫類型(SQLite 或 PostgreSQL)必須一致,無法跨資料庫類型還原。'
|
||||
ErrAppWarn: '狀態異常,請檢視日誌'
|
||||
ErrAppParamKey: '參數{{ .name }} 欄位異常'
|
||||
ErrAppUpgrade: '應用程式{{ .name }} 升級失敗{{ .err }}'
|
||||
|
||||
@@ -140,6 +140,8 @@ ErrComposeProjectNameEmpty: "无法从 Docker Compose 配置或文件父目录
|
||||
ErrComposeNameInvalid: "Compose 项目名称格式错误:必须以小写字母或数字开头,仅支持小写字母、数字、- 和 _,长度为 1-256 个字符"
|
||||
ErrAppVersionUnavailable: "当前应用版本已从远程服务下架,请选择其他版本后重试"
|
||||
ErrVllmGB10ProOnly: "该 vLLM 版本仅支持 1Panel 专业版"
|
||||
ErrAIGatewayDatabaseTypeMismatch: 'AI 网关只能在相同数据库类型(SQLite 或 PostgreSQL)之间升级。'
|
||||
ErrAIGatewayRecoverDatabaseTypeMismatch: 'AI 网关备份与目标应用的数据库类型(SQLite 或 PostgreSQL)必须一致,无法跨数据库类型恢复。'
|
||||
ErrAppWarn: "状态异常,请查看日志"
|
||||
ErrAppParamKey: "参数 {{ .name }} 字段异常"
|
||||
ErrAppUpgrade: "应用 {{ .name }} 升级失败 {{ .err }}"
|
||||
|
||||
@@ -102,5 +102,9 @@
|
||||
"monaco-editor": {
|
||||
"dompurify": "3.4.16"
|
||||
}
|
||||
},
|
||||
"allowScripts": {
|
||||
"@vue-office/docx@1.6.3": true,
|
||||
"@vue-office/excel@1.7.14": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user