From 11771b2b5381c5a8b6b8b9f68ff17fa2bab40a76 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Fri, 8 May 2026 16:31:15 +0800 Subject: [PATCH] fix: improve ai benchmark i18n (#12686) --- agent/app/api/v2/file.go | 10 ---- agent/app/api/v2/setting.go | 10 ++++ agent/app/service/file.go | 12 ---- agent/app/service/setting.go | 11 ++++ agent/i18n/lang/zh-Hant.yaml | 1 + agent/router/ro_file.go | 1 - agent/router/ro_setting.go | 1 + core/i18n/lang/zh-Hant.yaml | 1 + frontend/src/api/modules/files.ts | 4 -- frontend/src/api/modules/setting.ts | 3 + frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/es-es.ts | 56 ++++++++++++++++++ frontend/src/lang/modules/ja.ts | 54 ++++++++++++++++++ frontend/src/lang/modules/ko.ts | 54 ++++++++++++++++++ frontend/src/lang/modules/ms.ts | 56 ++++++++++++++++++ frontend/src/lang/modules/pt-br.ts | 56 ++++++++++++++++++ frontend/src/lang/modules/ru.ts | 57 +++++++++++++++++++ frontend/src/lang/modules/tr.ts | 56 ++++++++++++++++++ frontend/src/lang/modules/zh-Hant.ts | 53 +++++++++++++++++ frontend/src/lang/modules/zh.ts | 3 + .../views/app-store/detail/params/index.vue | 4 +- frontend/src/views/home/index.vue | 4 +- .../views/website/website/create/index.vue | 4 +- 23 files changed, 481 insertions(+), 33 deletions(-) diff --git a/agent/app/api/v2/file.go b/agent/app/api/v2/file.go index 1a678d74c..24db39c03 100644 --- a/agent/app/api/v2/file.go +++ b/agent/app/api/v2/file.go @@ -997,16 +997,6 @@ func (b *BaseApi) BatchChangeModeAndOwner(c *gin.Context) { helper.Success(c) } -func (b *BaseApi) GetPathByType(c *gin.Context) { - pathType, ok := c.Params.Get("type") - if !ok { - helper.BadRequest(c, errors.New("error pathType id in path")) - return - } - resPath := fileService.GetPathByType(pathType) - helper.SuccessWithData(c, resPath) -} - // @Tags File // @Summary system mount // @Accept json diff --git a/agent/app/api/v2/setting.go b/agent/app/api/v2/setting.go index bfda59429..8fe516e2f 100644 --- a/agent/app/api/v2/setting.go +++ b/agent/app/api/v2/setting.go @@ -134,6 +134,16 @@ func (b *BaseApi) UpdateFileHistorySetting(c *gin.Context) { helper.Success(c) } +// @Tags System Setting +// @Summary Load website dir +// @Success 200 {string} path +// @Security ApiKeyAuth +// @Security Timestamp +// @Router /settings/website/dir [get] +func (b *BaseApi) LoadWebsiteDir(c *gin.Context) { + helper.SuccessWithData(c, settingService.GetWebsiteDir()) +} + // @Tags System Setting // @Summary Load local backup dir // @Success 200 {string} path diff --git a/agent/app/service/file.go b/agent/app/service/file.go index 2d68ac0bd..38f58e9e4 100644 --- a/agent/app/service/file.go +++ b/agent/app/service/file.go @@ -76,7 +76,6 @@ type IFileService interface { BatchChangeModeAndOwner(op request.FileRoleReq) error ReadLogByLine(req request.FileReadByLineReq) (*response.FileLineContent, error) - GetPathByType(pathType string) string BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo GetHostMount() []dto.DiskInfo GetUsersAndGroups() (*response.UserGroupResponse, error) @@ -1128,17 +1127,6 @@ func (f *FileService) ReadLogByLine(req request.FileReadByLineReq) (*response.Fi return res, nil } -func (f *FileService) GetPathByType(pathType string) string { - if pathType == "websiteDir" { - value, _ := settingRepo.GetValueByKey("WEBSITE_DIR") - if value == "" { - return path.Join(global.Dir.BaseDir, "1panel", "www") - } - return value - } - return "" -} - func (f *FileService) BatchCheckFiles(req request.FilePathsCheck) []response.ExistFileInfo { fileList := make([]response.ExistFileInfo, 0, len(req.Paths)) for _, filePath := range req.Paths { diff --git a/agent/app/service/setting.go b/agent/app/service/setting.go index 0b8f6b893..5c66ea4cc 100644 --- a/agent/app/service/setting.go +++ b/agent/app/service/setting.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "encoding/json" "errors" + "path" "strconv" "strings" "time" @@ -15,6 +16,7 @@ import ( "github.com/1Panel-dev/1Panel/agent/app/repo" "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/constant" + "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/encrypt" "github.com/1Panel-dev/1Panel/agent/utils/ssh" terminalai "github.com/1Panel-dev/1Panel/agent/utils/terminal/ai" @@ -28,6 +30,7 @@ type ISettingService interface { GetTerminalAIInfo() (*dto.TerminalAIInfo, error) GetFileManageAIInfo() (*dto.FileManageAIInfo, error) GetFileHistorySettingInfo() (*response.FileHistorySettingInfo, error) + GetWebsiteDir() string Update(key, value string) error UpdateTerminalAI(req dto.TerminalAIInfo) error UpdateFileManageAI(req dto.FileManageAIInfo) error @@ -112,6 +115,14 @@ func (u *SettingService) GetFileHistorySettingInfo() (*response.FileHistorySetti return historyService.GetSettingInfo() } +func (u *SettingService) GetWebsiteDir() string { + value, _ := settingRepo.GetValueByKey("WEBSITE_DIR") + if value == "" { + return path.Join(global.Dir.BaseDir, "1panel", "www") + } + return value +} + func (u *SettingService) Update(key, value string) error { return settingRepo.UpdateOrCreate(key, value) } diff --git a/agent/i18n/lang/zh-Hant.yaml b/agent/i18n/lang/zh-Hant.yaml index d305d643e..955af078c 100644 --- a/agent/i18n/lang/zh-Hant.yaml +++ b/agent/i18n/lang/zh-Hant.yaml @@ -438,6 +438,7 @@ Clamscan: '掃描 {{ .name }}' TaskScan: '掃描' OllamaModelPull: '拉取 Ollama 模型{{ .name }}' OllamaModelSize: '取得 Ollama 模型{{ .name }} 大小' +AIBenchmarkRun: '執行 AI 基準測試' Snapshot: '快照' SnapDBInfo: '寫入1Panel 資料庫資訊' SnapCopy: '複製檔案&目錄{{ .name }}' diff --git a/agent/router/ro_file.go b/agent/router/ro_file.go index 7d8c92881..3b4a701e4 100644 --- a/agent/router/ro_file.go +++ b/agent/router/ro_file.go @@ -66,7 +66,6 @@ func (f *FileRouter) InitRouter(Router *gin.RouterGroup) { fileRouter.POST("/favorite", baseApi.CreateFavorite) fileRouter.POST("/favorite/del", baseApi.DeleteFavorite) - fileRouter.GET("/path/:type", baseApi.GetPathByType) fileRouter.POST("/mount", baseApi.GetHostMount) fileRouter.POST("/user/group", baseApi.GetUsersAndGroups) fileRouter.POST("/convert", baseApi.ConvertFile) diff --git a/agent/router/ro_setting.go b/agent/router/ro_setting.go index 7aa32df1e..95cafb35e 100644 --- a/agent/router/ro_setting.go +++ b/agent/router/ro_setting.go @@ -15,6 +15,7 @@ func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) { settingRouter.POST("/terminal/ai/search", baseApi.GetTerminalAISettingInfo) settingRouter.POST("/files/ai/search", baseApi.GetFileManageAISettingInfo) settingRouter.POST("/file-history/search", baseApi.GetFileHistorySettingInfo) + settingRouter.GET("/website/dir", baseApi.LoadWebsiteDir) settingRouter.GET("/search/available", baseApi.GetSystemAvailable) settingRouter.POST("/update", baseApi.UpdateSetting) settingRouter.POST("/terminal/ai/update", baseApi.UpdateTerminalAISetting) diff --git a/core/i18n/lang/zh-Hant.yaml b/core/i18n/lang/zh-Hant.yaml index fef23add5..74f07f629 100644 --- a/core/i18n/lang/zh-Hant.yaml +++ b/core/i18n/lang/zh-Hant.yaml @@ -125,6 +125,7 @@ TaskUpgrade: "升級" TaskSync: "同步" TaskSyncForNode: "同步節點資料" TaskBackup: "備份" +AIBenchmarkRun: "執行 AI 基準測試" SuccessStatus: "{{ .name }} 成功" FailedStatus: "{{ .name }} 失敗 {{ .err }}" Start: "開始" diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index 7f37e1704..48ed89a6f 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -221,10 +221,6 @@ export const getRecycleStatusByNode = (node: string) => { return http.get('files/recycle/status?operateNode=' + node); }; -export const getPathByType = (pathType: string) => { - return http.get(`files/path/${pathType}`); -}; - export const searchHostMount = () => { return http.post(`/files/mount`); }; diff --git a/frontend/src/api/modules/setting.ts b/frontend/src/api/modules/setting.ts index 63271ce33..7f01829e0 100644 --- a/frontend/src/api/modules/setting.ts +++ b/frontend/src/api/modules/setting.ts @@ -72,6 +72,9 @@ export const loadBaseDir = (node?: string) => { const query = node ? `?operateNode=${node}` : ''; return http.get(`/settings/basedir${query}`); }; +export const loadWebsiteDir = () => { + return http.get(`/settings/website/dir`); +}; export const loadDaemonJsonPath = () => { return http.get(`/settings/daemonjson`, {}); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index b97dd275a..dcc77d6ac 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -29,6 +29,7 @@ const message = { conn: 'Connect', disConn: 'Disconnect', clean: 'Clear', + cleanAll: 'Clear all', selectAll: 'Select all', login: 'Sign in', close: 'Close', @@ -3835,6 +3836,8 @@ const message = { ai_mcp_view: 'MCP View', ai_mcp_manage: 'MCP Manage', ai_gpu_view: 'GPU View', + ai_benchmark_view: 'AI Benchmark View', + ai_benchmark_manage: 'AI Benchmark Manage', website_view: 'Website View', website_manage: 'Website Manage', website_cert_view: 'Certificate View', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 4d80d4305..5e85b33a2 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -29,6 +29,7 @@ const message = { conn: 'Conectar', disconn: 'Desconectar', clean: 'Limpiar', + cleanAll: 'Limpiar todo', selectAll: 'Seleccionar todo', login: 'Iniciar sesión', close: 'Cerrar', @@ -1001,6 +1002,59 @@ const message = { validationModelMapEmpty: 'Los nombres del mapeo de modelos no pueden estar vacíos', validationModelMapDuplicate: 'El modelo solicitado {0} está duplicado', }, + benchmark: { + title: 'Benchmark', + create: 'Crear', + launchCommand: 'Comando de inicio', + retest: 'Volver a probar', + statusRunning: 'En ejecución', + statusWaiting: 'En espera', + base: 'Información básica', + backend: 'Backend', + baseUrl: 'URL base', + endpoint: 'Endpoint', + tokenizer: 'Tokenizador', + tokenizerPlaceholder: + 'Seleccione o introduzca un directorio local de tokenizador, p. ej. /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: 'Configuración de ejecución', + rawResult: 'Resultado bruto', + resultMetrics: 'Métricas de resultado', + contextTokens: 'Longitud de contexto', + contextTokensHelper: 'Suma del límite de tokens de entrada y salida de este benchmark.', + outputThroughput: 'Rendimiento de salida', + outputThroughputHelper: 'Tokens de salida generados por segundo. Un valor mayor indica más velocidad.', + totalThroughput: 'Rendimiento total', + totalThroughputHelper: + 'Tokens de entrada y salida procesados por segundo. Se usa para medir la capacidad general.', + firstTokenLatency: 'Latencia del primer token', + firstTokenLatencyHelper: + 'Tiempo desde el envío de la solicitud hasta recibir el primer token. Un valor menor indica respuesta más rápida.', + inputTokens: 'Tokens de entrada', + outputTokens: 'Tokens de salida', + tokenValueHelper: 'Introduzca un entero positivo o valor con k, p. ej. 512, 1k, 32k', + numPrompts: 'Prompts', + concurrency: 'Concurrencia', + requestRate: 'Tasa de solicitudes', + requestRateUnlimited: 'Ilimitado (máximo rendimiento)', + requestRateCustom: 'QPS personalizado', + requestRateCustomPlaceholder: 'Solicitudes por segundo, p. ej. 2.5', + successfulRequests: 'Solicitudes correctas', + failedRequests: 'Solicitudes fallidas', + requestThroughput: 'Rendimiento de solicitudes', + ttftMean: 'TTFT promedio', + ttftMedian: 'TTFT mediana', + ttftP99: 'TTFT P99', + tpotMean: 'TPOT promedio', + tpotMedian: 'TPOT mediana', + tpotP99: 'TPOT P99', + itlMean: 'ITL promedio', + itlMedian: 'ITL mediana', + itlP99: 'ITL P99', + timeout: 'Tiempo de espera (segundos)', + image: 'Imagen vLLM', + ignoreEos: 'Ignorar EOS', + extraHeaders: 'Encabezados adicionales', + }, gpu: { gpu: 'Monitoreo de GPU', gpuHelper: 'El sistema no detectó comandos NVIDIA-SMI o XPU-SMI. ¡Compruebe e inténtelo de nuevo!', @@ -3822,6 +3876,8 @@ const message = { ai_mcp_view: 'Vista de MCP', ai_mcp_manage: 'Gestión de MCP', ai_gpu_view: 'Vista de GPU', + ai_benchmark_view: 'Vista de benchmark de IA', + ai_benchmark_manage: 'Gestión de benchmark de IA', website_view: 'Vista del sitio web', website_manage: 'Gestión del sitio web', website_cert_view: 'Vista de certificados', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 872460717..3e5f64f09 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -26,6 +26,7 @@ const message = { conn: '接続', disConn: '切断', clean: 'クリア', + cleanAll: 'すべてクリア', selectAll: 'すべて選択', login: 'サインイン', close: '閉じる', @@ -991,6 +992,57 @@ const message = { validationModelMapEmpty: 'モデルマッピングのモデル名は空にできません', validationModelMapDuplicate: 'リクエストモデル {0} が重複しています', }, + benchmark: { + title: 'ベンチマーク', + create: '作成', + launchCommand: '起動コマンド', + retest: '再テスト', + statusRunning: '実行中', + statusWaiting: '待機中', + base: '基本情報', + backend: 'バックエンド', + baseUrl: 'Base URL', + endpoint: 'エンドポイント', + tokenizer: 'トークナイザー', + tokenizerPlaceholder: + 'ローカルトークナイザーディレクトリを選択または入力してください。例: /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: '実行設定', + rawResult: '生データ', + resultMetrics: '結果指標', + contextTokens: 'コンテキスト長', + contextTokensHelper: 'このベンチマークの入力 Token 上限と出力 Token 上限の合計です。', + outputThroughput: '出力スループット', + outputThroughputHelper: '1 秒あたりに生成される出力 Token 数です。高いほど生成が速くなります。', + totalThroughput: '合計スループット', + totalThroughputHelper: '1 秒あたりに処理される入力と出力 Token の合計で、全体性能の測定に使います。', + firstTokenLatency: '初回 Token レイテンシ', + firstTokenLatencyHelper: 'リクエスト送信から最初の Token 受信までの時間です。低いほど応答が速くなります。', + inputTokens: '入力 Token', + outputTokens: '出力 Token', + tokenValueHelper: '正の整数または k 単位を入力してください。例: 512、1k、32k', + numPrompts: 'プロンプト数', + concurrency: '同時実行数', + requestRate: 'リクエストレート', + requestRateUnlimited: '無制限(最大スループット)', + requestRateCustom: 'カスタム QPS', + requestRateCustomPlaceholder: '1 秒あたりのリクエスト数。例: 2.5', + successfulRequests: '成功リクエスト', + failedRequests: '失敗リクエスト', + requestThroughput: 'リクエストスループット', + ttftMean: '平均 TTFT', + ttftMedian: '中央値 TTFT', + ttftP99: 'P99 TTFT', + tpotMean: '平均 TPOT', + tpotMedian: '中央値 TPOT', + tpotP99: 'P99 TPOT', + itlMean: '平均 ITL', + itlMedian: '中央値 ITL', + itlP99: 'P99 ITL', + timeout: 'タイムアウト(秒)', + image: 'vLLM イメージ', + ignoreEos: 'EOS を無視', + extraHeaders: '追加ヘッダー', + }, gpu: { gpu: 'GPU 監視', gpuHelper: @@ -3806,6 +3858,8 @@ const message = { ai_mcp_view: 'MCP 表示', ai_mcp_manage: 'MCP 管理', ai_gpu_view: 'GPU 表示', + ai_benchmark_view: 'AI ベンチマーク表示', + ai_benchmark_manage: 'AI ベンチマーク管理', website_view: 'サイト表示', website_manage: 'サイト管理', website_cert_view: '証明書表示', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 7a02eae51..e627ede15 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -26,6 +26,7 @@ const message = { conn: '연결', disConn: '연결 해제', clean: '지우기', + cleanAll: '모두 지우기', selectAll: '전체 선택', login: '로그인', close: '닫기', @@ -975,6 +976,57 @@ const message = { validationModelMapEmpty: '모델 매핑의 모델 이름은 비워 둘 수 없습니다', validationModelMapDuplicate: '요청 모델 {0}이(가) 중복되었습니다', }, + benchmark: { + title: '벤치마크', + create: '생성', + launchCommand: '시작 명령', + retest: '다시 테스트', + statusRunning: '실행 중', + statusWaiting: '대기 중', + base: '기본 정보', + backend: '백엔드', + baseUrl: 'Base URL', + endpoint: '엔드포인트', + tokenizer: '토크나이저', + tokenizerPlaceholder: + '로컬 토크나이저 디렉터리를 선택하거나 입력하세요. 예: /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: '실행 구성', + rawResult: '원시 결과', + resultMetrics: '결과 지표', + contextTokens: '컨텍스트 길이', + contextTokensHelper: '이 벤치마크의 입력 Token 제한과 출력 Token 제한의 합계입니다.', + outputThroughput: '출력 처리량', + outputThroughputHelper: '초당 생성된 출력 Token 수입니다. 높을수록 생성 속도가 빠릅니다.', + totalThroughput: '총 처리량', + totalThroughputHelper: '초당 처리된 입력 및 출력 Token 수로 전체 처리 능력을 측정합니다.', + firstTokenLatency: '첫 Token 지연 시간', + firstTokenLatencyHelper: '요청 전송부터 첫 Token 수신까지의 시간입니다. 낮을수록 응답이 빠릅니다.', + inputTokens: '입력 Token', + outputTokens: '출력 Token', + tokenValueHelper: '양의 정수 또는 k 값을 입력하세요. 예: 512, 1k, 32k', + numPrompts: '프롬프트 수', + concurrency: '동시성', + requestRate: '요청 속도', + requestRateUnlimited: '무제한(최대 처리량)', + requestRateCustom: '사용자 지정 QPS', + requestRateCustomPlaceholder: '초당 요청 수, 예: 2.5', + successfulRequests: '성공한 요청', + failedRequests: '실패한 요청', + requestThroughput: '요청 처리량', + ttftMean: '평균 TTFT', + ttftMedian: '중앙값 TTFT', + ttftP99: 'P99 TTFT', + tpotMean: '평균 TPOT', + tpotMedian: '중앙값 TPOT', + tpotP99: 'P99 TPOT', + itlMean: '평균 ITL', + itlMedian: '중앙값 ITL', + itlP99: 'P99 ITL', + timeout: '시간 초과(초)', + image: 'vLLM 이미지', + ignoreEos: 'EOS 무시', + extraHeaders: '추가 헤더', + }, gpu: { gpu: 'GPU 모니터링', gpuHelper: '시스템에서 NVIDIA-SMI 또는 XPU-SMI 명령을 감지하지 못했습니다. 확인하고 다시 시도하세요!', @@ -3722,6 +3774,8 @@ const message = { ai_mcp_view: 'MCP 보기', ai_mcp_manage: 'MCP 관리', ai_gpu_view: 'GPU 보기', + ai_benchmark_view: 'AI 벤치마크 보기', + ai_benchmark_manage: 'AI 벤치마크 관리', website_view: '웹사이트 보기', website_manage: '웹사이트 관리', website_cert_view: '인증서 보기', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index fb7509757..1c587fbbd 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -26,6 +26,7 @@ const message = { conn: 'Sambung', disConn: 'Putus sambungan', clean: 'Kosongkan', + cleanAll: 'Kosongkan semua', selectAll: 'Pilih semua', login: 'Log masuk', close: 'Tutup', @@ -1000,6 +1001,59 @@ const message = { validationModelMapEmpty: 'Nama model dalam pemetaan model tidak boleh kosong', validationModelMapDuplicate: 'Model permintaan {0} berulang', }, + benchmark: { + title: 'Penanda Aras', + create: 'Cipta', + launchCommand: 'Arahan Pelancaran', + retest: 'Uji Semula', + statusRunning: 'Sedang berjalan', + statusWaiting: 'Menunggu', + base: 'Maklumat Asas', + backend: 'Backend', + baseUrl: 'URL Asas', + endpoint: 'Endpoint', + tokenizer: 'Tokenizer', + tokenizerPlaceholder: + 'Pilih atau masukkan direktori tokenizer tempatan, cth. /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: 'Konfigurasi Jalan', + rawResult: 'Keputusan Mentah', + resultMetrics: 'Metrik Keputusan', + contextTokens: 'Panjang Konteks', + contextTokensHelper: 'Had token input ditambah had token output untuk penanda aras ini.', + outputThroughput: 'Throughput Output', + outputThroughputHelper: 'Token output dijana setiap saat. Lebih tinggi bermaksud penjanaan lebih pantas.', + totalThroughput: 'Jumlah Throughput', + totalThroughputHelper: + 'Token input dan output diproses setiap saat. Digunakan untuk mengukur kapasiti keseluruhan.', + firstTokenLatency: 'Latensi Token Pertama', + firstTokenLatencyHelper: + 'Masa dari menghantar permintaan hingga menerima token pertama. Lebih rendah bermaksud respons lebih pantas.', + inputTokens: 'Token Input', + outputTokens: 'Token Output', + tokenValueHelper: 'Masukkan integer positif atau nilai k, cth. 512, 1k, 32k', + numPrompts: 'Prompt', + concurrency: 'Keserentakan', + requestRate: 'Kadar Permintaan', + requestRateUnlimited: 'Tanpa had (throughput maksimum)', + requestRateCustom: 'QPS tersuai', + requestRateCustomPlaceholder: 'Permintaan sesaat, cth. 2.5', + successfulRequests: 'Permintaan berjaya', + failedRequests: 'Permintaan gagal', + requestThroughput: 'Throughput Permintaan', + ttftMean: 'Purata TTFT', + ttftMedian: 'Median TTFT', + ttftP99: 'P99 TTFT', + tpotMean: 'Purata TPOT', + tpotMedian: 'Median TPOT', + tpotP99: 'P99 TPOT', + itlMean: 'Purata ITL', + itlMedian: 'Median ITL', + itlP99: 'P99 ITL', + timeout: 'Tamat Masa (saat)', + image: 'Imej vLLM', + ignoreEos: 'Abaikan EOS', + extraHeaders: 'Pengepala Tambahan', + }, gpu: { gpu: 'Pemantauan GPU', gpuHelper: 'Sistem tidak mengesan arahan NVIDIA-SMI atau XPU-SMI. Sila periksa dan cuba lagi!', @@ -3861,6 +3915,8 @@ const message = { ai_mcp_view: 'Paparan MCP', ai_mcp_manage: 'Pengurusan MCP', ai_gpu_view: 'Paparan GPU', + ai_benchmark_view: 'Paparan Penanda Aras AI', + ai_benchmark_manage: 'Pengurusan Penanda Aras AI', website_view: 'Paparan Laman Web', website_manage: 'Pengurusan Laman Web', website_cert_view: 'Paparan Sijil', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index b85d443bb..c2846defc 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -26,6 +26,7 @@ const message = { conn: 'Conectar', disConn: 'Desconectar', clean: 'Limpar', + cleanAll: 'Limpar tudo', selectAll: 'Selecionar tudo', login: 'Entrar', close: 'Fechar', @@ -996,6 +997,59 @@ const message = { validationModelMapEmpty: 'Os nomes no mapeamento de modelos não podem ficar vazios', validationModelMapDuplicate: 'O modelo solicitado {0} está duplicado', }, + benchmark: { + title: 'Benchmark', + create: 'Criar', + launchCommand: 'Comando de inicialização', + retest: 'Testar novamente', + statusRunning: 'Executando', + statusWaiting: 'Aguardando', + base: 'Informações básicas', + backend: 'Backend', + baseUrl: 'URL base', + endpoint: 'Endpoint', + tokenizer: 'Tokenizer', + tokenizerPlaceholder: + 'Selecione ou informe um diretório local de tokenizer, ex.: /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: 'Configuração de execução', + rawResult: 'Resultado bruto', + resultMetrics: 'Métricas de resultado', + contextTokens: 'Comprimento de contexto', + contextTokensHelper: 'Limite de tokens de entrada mais limite de tokens de saída para este benchmark.', + outputThroughput: 'Throughput de saída', + outputThroughputHelper: 'Tokens de saída gerados por segundo. Quanto maior, mais rápida a geração.', + totalThroughput: 'Throughput total', + totalThroughputHelper: + 'Tokens de entrada e saída processados por segundo. Usado para medir a capacidade geral.', + firstTokenLatency: 'Latência do primeiro token', + firstTokenLatencyHelper: + 'Tempo entre enviar a requisição e receber o primeiro token. Quanto menor, mais rápida a resposta.', + inputTokens: 'Tokens de entrada', + outputTokens: 'Tokens de saída', + tokenValueHelper: 'Informe um inteiro positivo ou valor com k, ex.: 512, 1k, 32k', + numPrompts: 'Prompts', + concurrency: 'Concorrência', + requestRate: 'Taxa de requisições', + requestRateUnlimited: 'Ilimitado (throughput máximo)', + requestRateCustom: 'QPS personalizado', + requestRateCustomPlaceholder: 'Requisições por segundo, ex.: 2.5', + successfulRequests: 'Requisições bem-sucedidas', + failedRequests: 'Requisições com falha', + requestThroughput: 'Throughput de requisições', + ttftMean: 'TTFT médio', + ttftMedian: 'TTFT mediano', + ttftP99: 'TTFT P99', + tpotMean: 'TPOT médio', + tpotMedian: 'TPOT mediano', + tpotP99: 'TPOT P99', + itlMean: 'ITL médio', + itlMedian: 'ITL mediano', + itlP99: 'ITL P99', + timeout: 'Timeout (segundos)', + image: 'Imagem vLLM', + ignoreEos: 'Ignorar EOS', + extraHeaders: 'Cabeçalhos extras', + }, gpu: { gpu: 'Monitoramento de GPU', gpuHelper: 'O sistema não detectou comandos NVIDIA-SMI ou XPU-SMI. Verifique e tente novamente!', @@ -4000,6 +4054,8 @@ const message = { ai_mcp_view: 'Visualização do MCP', ai_mcp_manage: 'Gerenciamento do MCP', ai_gpu_view: 'Visualização da GPU', + ai_benchmark_view: 'Visualização do Benchmark de IA', + ai_benchmark_manage: 'Gerenciamento do Benchmark de IA', website_view: 'Visualização do Site', website_manage: 'Gerenciamento do Site', website_cert_view: 'Visualização do Certificado', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index c7862a13a..dc914a21a 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -26,6 +26,7 @@ const message = { conn: 'Подключить', disConn: 'Отключить', clean: 'Очистить', + cleanAll: 'Очистить все', selectAll: 'Выбрать все', login: 'Войти', close: 'Закрыть', @@ -990,6 +991,60 @@ const message = { validationModelMapEmpty: 'Имена моделей в сопоставлении не могут быть пустыми', validationModelMapDuplicate: 'Запрошенная модель {0} дублируется', }, + benchmark: { + title: 'Бенчмарк', + create: 'Создать', + launchCommand: 'Команда запуска', + retest: 'Повторить тест', + statusRunning: 'Выполняется', + statusWaiting: 'Ожидание', + base: 'Основная информация', + backend: 'Backend', + baseUrl: 'Base URL', + endpoint: 'Endpoint', + tokenizer: 'Токенизатор', + tokenizerPlaceholder: + 'Выберите или введите локальный каталог токенизатора, например /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: 'Конфигурация запуска', + rawResult: 'Исходный результат', + resultMetrics: 'Метрики результата', + contextTokens: 'Длина контекста', + contextTokensHelper: 'Лимит входных токенов плюс лимит выходных токенов для этого бенчмарка.', + outputThroughput: 'Выходная пропускная способность', + outputThroughputHelper: + 'Выходные токены, генерируемые в секунду. Чем выше значение, тем быстрее генерация.', + totalThroughput: 'Общая пропускная способность', + totalThroughputHelper: + 'Входные и выходные токены, обработанные в секунду. Используется для оценки общей емкости.', + firstTokenLatency: 'Задержка первого токена', + firstTokenLatencyHelper: + 'Время от отправки запроса до получения первого токена. Чем ниже значение, тем быстрее ответ.', + inputTokens: 'Входные токены', + outputTokens: 'Выходные токены', + tokenValueHelper: 'Введите положительное целое число или значение с k, например 512, 1k, 32k', + numPrompts: 'Промпты', + concurrency: 'Параллелизм', + requestRate: 'Частота запросов', + requestRateUnlimited: 'Без ограничений (макс. пропускная способность)', + requestRateCustom: 'Пользовательский QPS', + requestRateCustomPlaceholder: 'Запросов в секунду, например 2.5', + successfulRequests: 'Успешные запросы', + failedRequests: 'Неуспешные запросы', + requestThroughput: 'Пропускная способность запросов', + ttftMean: 'Средний TTFT', + ttftMedian: 'Медианный TTFT', + ttftP99: 'P99 TTFT', + tpotMean: 'Средний TPOT', + tpotMedian: 'Медианный TPOT', + tpotP99: 'P99 TPOT', + itlMean: 'Средний ITL', + itlMedian: 'Медианный ITL', + itlP99: 'P99 ITL', + timeout: 'Тайм-аут (секунды)', + image: 'Образ vLLM', + ignoreEos: 'Игнорировать EOS', + extraHeaders: 'Дополнительные заголовки', + }, gpu: { gpu: 'Мониторинг GPU', gpuHelper: 'Система не обнаружила команды NVIDIA-SMI или XPU-SMI. Проверьте и повторите попытку!', @@ -3854,6 +3909,8 @@ const message = { ai_mcp_view: 'Просмотр MCP', ai_mcp_manage: 'Управление MCP', ai_gpu_view: 'Просмотр GPU', + ai_benchmark_view: 'Просмотр AI-бенчмарка', + ai_benchmark_manage: 'Управление AI-бенчмарком', website_view: 'Просмотр сайта', website_manage: 'Управление сайтом', website_cert_view: 'Просмотр сертификата', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index c988276c3..a24ffa420 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -29,6 +29,7 @@ const message = { conn: 'Bağlan', disconn: 'Bağlantıyı Kes', clean: 'Temizle', + cleanAll: 'Tümünü temizle', selectAll: 'Tümünü seç', login: 'Oturum Aç', close: 'Kapat', @@ -998,6 +999,59 @@ const message = { validationModelMapEmpty: 'Model eşlemesindeki model adları boş olamaz', validationModelMapDuplicate: 'İstek modeli {0} yineleniyor', }, + benchmark: { + title: 'Benchmark', + create: 'Oluştur', + launchCommand: 'Başlatma Komutu', + retest: 'Yeniden test et', + statusRunning: 'Çalışıyor', + statusWaiting: 'Bekliyor', + base: 'Temel Bilgiler', + backend: 'Backend', + baseUrl: 'Base URL', + endpoint: 'Endpoint', + tokenizer: 'Tokenizer', + tokenizerPlaceholder: 'Yerel tokenizer dizini seçin veya girin, örn. /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: 'Çalıştırma Yapılandırması', + rawResult: 'Ham Sonuç', + resultMetrics: 'Sonuç Metrikleri', + contextTokens: 'Bağlam Uzunluğu', + contextTokensHelper: 'Bu benchmark için giriş token sınırı ile çıkış token sınırının toplamı.', + outputThroughput: 'Çıkış Throughput', + outputThroughputHelper: + 'Saniye başına üretilen çıkış token sayısı. Daha yüksek değer daha hızlı üretimdir.', + totalThroughput: 'Toplam Throughput', + totalThroughputHelper: + 'Saniye başına işlenen giriş ve çıkış token sayısı. Genel kapasiteyi ölçmek için kullanılır.', + firstTokenLatency: 'İlk Token Gecikmesi', + firstTokenLatencyHelper: + 'İsteğin gönderilmesinden ilk token alınana kadar geçen süre. Daha düşük değer daha hızlı yanıttır.', + inputTokens: 'Giriş Token', + outputTokens: 'Çıkış Token', + tokenValueHelper: 'Pozitif tam sayı veya k değeri girin, örn. 512, 1k, 32k', + numPrompts: 'Prompt', + concurrency: 'Eşzamanlılık', + requestRate: 'İstek Hızı', + requestRateUnlimited: 'Sınırsız (maksimum throughput)', + requestRateCustom: 'Özel QPS', + requestRateCustomPlaceholder: 'Saniye başına istek, örn. 2.5', + successfulRequests: 'Başarılı istekler', + failedRequests: 'Başarısız istekler', + requestThroughput: 'İstek Throughput', + ttftMean: 'Ortalama TTFT', + ttftMedian: 'Medyan TTFT', + ttftP99: 'P99 TTFT', + tpotMean: 'Ortalama TPOT', + tpotMedian: 'Medyan TPOT', + tpotP99: 'P99 TPOT', + itlMean: 'Ortalama ITL', + itlMedian: 'Medyan ITL', + itlP99: 'P99 ITL', + timeout: 'Zaman aşımı (saniye)', + image: 'vLLM İmajı', + ignoreEos: "EOS'u yok say", + extraHeaders: 'Ek Başlıklar', + }, gpu: { gpu: 'GPU İzleme', gpuHelper: 'Sistem NVIDIA-SMI veya XPU-SMI komutlarını algılamadı. Lütfen kontrol edip tekrar deneyin!', @@ -3854,6 +3908,8 @@ const message = { ai_mcp_view: 'MCP Görünümü', ai_mcp_manage: 'MCP Yönetimi', ai_gpu_view: 'GPU Görünümü', + ai_benchmark_view: 'AI Benchmark Görünümü', + ai_benchmark_manage: 'AI Benchmark Yönetimi', website_view: 'Web Sitesi Görünümü', website_manage: 'Web Sitesi Yönetimi', website_cert_view: 'Sertifika Görünümü', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 0bd5f87c0..8b78adc07 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -29,6 +29,7 @@ const message = { conn: '連接', disConn: '斷開', clean: '清除', + cleanAll: '清空所有', selectAll: '全選', login: '登入', close: '關閉', @@ -935,6 +936,56 @@ const message = { validationModelMapEmpty: '模型映射的模型名稱不能為空', validationModelMapDuplicate: '請求模型 {0} 重複', }, + benchmark: { + title: '基準測試', + create: '建立', + launchCommand: '啟動命令', + retest: '重新測試', + statusRunning: '執行中', + statusWaiting: '等待中', + base: '基礎資訊', + backend: '後端', + baseUrl: '服務地址', + endpoint: '介面路徑', + tokenizer: '分詞器', + tokenizerPlaceholder: '請選擇或輸入本機分詞器目錄,例如 /opt/1panel/tokenizers/DeepSeek-V3', + runConfig: '執行設定', + rawResult: '原始結果', + resultMetrics: '結果指標', + contextTokens: '上下文長度', + contextTokensHelper: '本次測試的輸入 Token 與輸出 Token 上限之和。', + outputThroughput: '輸出吞吐', + outputThroughputHelper: '模型每秒產生的輸出 Token 數,越高表示生成速度越快。', + totalThroughput: '總吞吐', + totalThroughputHelper: '每秒處理的輸入與輸出 Token 總數,用於衡量整體處理能力。', + firstTokenLatency: '首 Token 延遲', + firstTokenLatencyHelper: '從請求送出到收到第一個 Token 的時間,越低表示回應越快。', + inputTokens: '輸入 Token', + outputTokens: '輸出 Token', + tokenValueHelper: '請輸入正整數或 k 單位,例如 512、1k、32k', + numPrompts: '請求數量', + concurrency: '併發數', + requestRate: '請求速率', + requestRateUnlimited: '不限速(最大吞吐)', + requestRateCustom: '自訂 QPS', + requestRateCustomPlaceholder: '請輸入每秒請求數,如 2.5', + successfulRequests: '成功請求', + failedRequests: '失敗請求', + requestThroughput: '請求吞吐', + ttftMean: 'TTFT 平均', + ttftMedian: 'TTFT 中位數', + ttftP99: 'TTFT P99', + tpotMean: 'TPOT 平均', + tpotMedian: 'TPOT 中位數', + tpotP99: 'TPOT P99', + itlMean: 'ITL 平均', + itlMedian: 'ITL 中位數', + itlP99: 'ITL P99', + timeout: '逾時時間(秒)', + image: 'vLLM 映像', + ignoreEos: '忽略 EOS', + extraHeaders: '額外請求標頭', + }, gpu: { gpu: 'GPU 監控', gpuHelper: '目前系統未偵測到 NVIDIA-SMI 或 XPU-SMI 指令,請檢查後重試', @@ -3503,6 +3554,8 @@ const message = { ai_mcp_view: 'MCP 檢視', ai_mcp_manage: 'MCP 管理', ai_gpu_view: 'GPU 檢視', + ai_benchmark_view: 'AI 基準測試檢視', + ai_benchmark_manage: 'AI 基準測試管理', website_view: '網站檢視', website_manage: '網站管理', website_cert_view: '憑證檢視', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 23becd2c9..bd73836b5 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -29,6 +29,7 @@ const message = { conn: '连接', disConn: '断开', clean: '清空', + cleanAll: '清空所有', selectAll: '全选', login: '登录', close: '关闭', @@ -4148,6 +4149,8 @@ const message = { ai_mcp_view: 'MCP 查看', ai_mcp_manage: 'MCP 管理', ai_gpu_view: 'GPU 查看', + ai_benchmark_view: 'AI 基准测试查看', + ai_benchmark_manage: 'AI 基准测试管理', website_view: '网站查看', website_manage: '网站管理', website_cert_view: '证书查看', diff --git a/frontend/src/views/app-store/detail/params/index.vue b/frontend/src/views/app-store/detail/params/index.vue index 1ac8fc432..f2ef11013 100644 --- a/frontend/src/views/app-store/detail/params/index.vue +++ b/frontend/src/views/app-store/detail/params/index.vue @@ -144,7 +144,7 @@ import { getAppService } from '@/api/modules/app'; import { Rules } from '@/global/form-rules'; import { App } from '@/api/interface/app'; import { getDBName, getLabel, getDescription } from '@/utils/app-store'; -import { getPathByType } from '@/api/modules/files'; +import { loadWebsiteDir } from '@/api/modules/setting'; import { loadFormatCollations } from '@/api/modules/database'; interface ParamObj extends App.FromField { @@ -226,7 +226,7 @@ const handleParams = () => { form[p.envKey] = p.default; } if (p.type == 'text' && p.envKey == 'WEBSITE_DIR') { - getPathByType('websiteDir').then((res) => { + loadWebsiteDir().then((res) => { form[p.envKey] = res.data; }); } diff --git a/frontend/src/views/home/index.vue b/frontend/src/views/home/index.vue index 2fac6e3ed..17417a27f 100644 --- a/frontend/src/views/home/index.vue +++ b/frontend/src/views/home/index.vue @@ -10,7 +10,7 @@ >