diff --git a/agent/app/api/v2/ai_benchmark.go b/agent/app/api/v2/ai_benchmark.go new file mode 100644 index 000000000..726b9a090 --- /dev/null +++ b/agent/app/api/v2/ai_benchmark.go @@ -0,0 +1,16 @@ +package v2 + +import ( + "github.com/1Panel-dev/1Panel/agent/app/api/v2/helper" + "github.com/1Panel-dev/1Panel/agent/app/service" + "github.com/gin-gonic/gin" +) + +func (b *BaseApi) AIBenchmarkSources(c *gin.Context) { + sources, err := service.AIBenchmarkSources(c.Query("kind"), c.Query("selected")) + if err != nil { + helper.BadRequest(c, err) + return + } + helper.SuccessWithData(c, sources) +} diff --git a/agent/app/dto/ai_benchmark.go b/agent/app/dto/ai_benchmark.go new file mode 100644 index 000000000..7aa5cfdfd --- /dev/null +++ b/agent/app/dto/ai_benchmark.go @@ -0,0 +1,13 @@ +package dto + +type AIBenchmarkSource struct { + ID string `json:"id"` + Kind string `json:"kind"` + Name string `json:"name"` + Status string `json:"status"` + BaseURL string `json:"baseUrl"` + Endpoint string `json:"endpoint"` + Models []string `json:"models"` + Tokenizer string `json:"tokenizer"` + Message string `json:"message"` +} diff --git a/agent/app/service/ai_benchmark.go b/agent/app/service/ai_benchmark.go new file mode 100644 index 000000000..49897a4dd --- /dev/null +++ b/agent/app/service/ai_benchmark.go @@ -0,0 +1,209 @@ +package service + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net" + "net/http" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "time" + + "github.com/1Panel-dev/1Panel/agent/app/dto" + "github.com/1Panel-dev/1Panel/agent/utils/docker" + "github.com/mattn/go-shellwords" +) + +func AIBenchmarkSources(kind, selected string) ([]dto.AIBenchmarkSource, error) { + if kind != "vllm" && kind != "ollama" { + return nil, errors.New("unsupported benchmark source") + } + selectedID := strings.SplitN(selected, ":", 2)[0] + type instance struct { + id uint + name, container string + port int + } + instances := []instance{} + apps, err := appRepo.GetBy(appRepo.WithKey(kind)) + if err != nil { + return nil, err + } + for _, app := range apps { + installs, err := appInstallRepo.ListBy(context.Background(), appInstallRepo.WithAppId(app.ID)) + if err != nil { + return nil, err + } + for _, install := range installs { + if selected != "" && strconv.FormatUint(uint64(install.ID), 10) != selectedID { + continue + } + instances = append(instances, instance{id: install.ID, name: install.Name, container: install.ContainerName, port: install.HttpPort}) + } + } + results := []dto.AIBenchmarkSource{} + if len(instances) == 0 { + return results, nil + } + client, err := docker.NewDockerClient() + if err != nil { + return nil, err + } + defer client.Close() + if !strings.HasPrefix(client.DaemonHost(), "unix://") { + return nil, errors.New("benchmark shortcuts require a Docker daemon on the main node; enter the remote service address manually") + } + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + for _, instance := range instances { + base := dto.AIBenchmarkSource{Kind: kind, Name: instance.name, Endpoint: "/v1/chat/completions", Models: []string{}, Status: "unknown"} + inspected, err := client.ContainerInspect(ctx, instance.container) + if err != nil { + base.ID = strconv.FormatUint(uint64(instance.id), 10) + base.Message = "container inspection unavailable" + results = append(results, base) + continue + } + if inspected.State != nil { + base.Status = inspected.State.Status + } + args := []string{} + if inspected.Config != nil { + args = append(args, inspected.Config.Entrypoint...) + args = append(args, inspected.Config.Cmd...) + } + if len(args) >= 3 && (args[0] == "sh" || args[0] == "bash" || strings.HasSuffix(args[0], "/sh") || strings.HasSuffix(args[0], "/bash")) && args[1] == "-c" { + parser := shellwords.NewParser() + parser.ParseEnv = false + parser.ParseBacktick = false + if parsed, err := parser.Parse(args[2]); err == nil { + args = parsed + } + } + flags := map[string]string{} + for i, arg := range args { + if key, value, ok := strings.Cut(arg, "="); ok && strings.HasPrefix(key, "--") { + flags[key] = value + } else if strings.HasPrefix(arg, "--") && i+1 < len(args) && !strings.HasPrefix(args[i+1], "--") { + flags[arg] = args[i+1] + } + } + if name := flags["--served-model-name"]; name != "" { + base.Models = []string{name} + } + tokenizer := flags["--tokenizer"] + if tokenizer == "" { + tokenizer = flags["--model"] + for i, arg := range args { + if tokenizer == "" && arg == "serve" && i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") { + tokenizer = args[i+1] + } + } + } + if kind != "ollama" && tokenizer != "" { + if !filepath.IsAbs(tokenizer) { + base.Tokenizer = tokenizer + } else { + longest := 0 + for _, mount := range inspected.Mounts { + relative, err := filepath.Rel(mount.Destination, tokenizer) + if err == nil && relative != ".." && !strings.HasPrefix(relative, ".."+string(filepath.Separator)) && len(mount.Destination) > longest { + candidate := filepath.Join(mount.Source, relative) + if info, err := os.Stat(candidate); err == nil && info.IsDir() { + base.Tokenizer = candidate + longest = len(mount.Destination) + } + } + } + } + } + ports := map[int]string{} + if instance.port > 0 { + ports[instance.port] = "127.0.0.1" + } + if inspected.NetworkSettings != nil { + for _, bindings := range inspected.NetworkSettings.Ports { + for _, binding := range bindings { + port, _ := strconv.Atoi(binding.HostPort) + if port > 0 { + host := binding.HostIP + if host == "" || host == "0.0.0.0" || host == "::" { + host = "127.0.0.1" + } + ports[port] = host + } + } + } + } + if len(ports) == 0 && inspected.HostConfig != nil && inspected.HostConfig.NetworkMode == "host" { + port, _ := strconv.Atoi(flags["--port"]) + if port > 0 { + ports[port] = "127.0.0.1" + } + } + ordered := []int{} + for port := range ports { + ordered = append(ordered, port) + } + sort.Ints(ordered) + if len(ordered) == 0 { + ordered = append(ordered, 0) + } + for _, port := range ordered { + source := base + source.ID = fmt.Sprintf("%d:%d", instance.id, port) + if selected != "" && source.ID != selected { + continue + } + if port > 0 { + source.BaseURL = "http://" + net.JoinHostPort(ports[port], strconv.Itoa(port)) + } + if selected == source.ID && source.BaseURL != "" && source.Status == "running" { + endpoint := "/v1/models" + if kind == "ollama" { + endpoint = "/api/tags" + } + request, err := http.NewRequestWithContext(ctx, http.MethodGet, source.BaseURL+endpoint, nil) + if err != nil { + return nil, err + } + response, err := (&http.Client{Timeout: 3 * time.Second, CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}).Do(request) + if err != nil { + source.Message = "model list unavailable; enter the served model name" + } else { + raw, readErr := io.ReadAll(io.LimitReader(response.Body, 2*1024*1024)) + response.Body.Close() + if response.StatusCode == http.StatusOK && readErr == nil { + var data struct { + Data []struct { + ID string `json:"id"` + } `json:"data"` + Models []struct { + Name string `json:"name"` + } `json:"models"` + } + if err := json.Unmarshal(raw, &data); err == nil { + source.Models = []string{} + for _, model := range data.Data { + source.Models = append(source.Models, model.ID) + } + for _, model := range data.Models { + source.Models = append(source.Models, model.Name) + } + } + } else { + source.Message = fmt.Sprintf("model list HTTP %d; provide model name and credentials if required", response.StatusCode) + } + } + } + results = append(results, source) + } + } + return results, nil +} diff --git a/agent/router/ro_ai.go b/agent/router/ro_ai.go index 1c68336ea..99a057e8d 100644 --- a/agent/router/ro_ai.go +++ b/agent/router/ro_ai.go @@ -13,6 +13,7 @@ func (a *AIToolsRouter) InitRouter(Router *gin.RouterGroup) { baseApi := v1.ApiGroupApp.BaseApi { + aiToolsRouter.GET("/benchmark/sources", baseApi.AIBenchmarkSources) aiToolsRouter.POST("/ollama/close", baseApi.CloseOllamaModel) aiToolsRouter.POST("/ollama/model", baseApi.CreateOllamaModel) aiToolsRouter.POST("/ollama/model/recreate", baseApi.RecreateOllamaModel) diff --git a/frontend/build/benchmark-report.ts b/frontend/build/benchmark-report.ts new file mode 100644 index 000000000..7b648a068 --- /dev/null +++ b/frontend/build/benchmark-report.ts @@ -0,0 +1,73 @@ +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { build, type Plugin } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +export function benchmarkReportPlugin(root: string): Plugin | undefined { + const entry = resolve(root, 'src/enterprise/views/ai-benchmark/report/main.ts'); + if (!existsSync(entry)) return; + const id = 'virtual:benchmark-report'; + const resolvedID = `\0${id}`; + const dependencies = new Set(); + return { + name: 'benchmark-report', + resolveId(source) { + if (source === id) return resolvedID; + }, + async load(source) { + if (source !== resolvedID) return; + const result = await build({ + root, + configFile: false, + publicDir: false, + logLevel: 'warn', + resolve: { preserveSymlinks: true }, + plugins: [ + vue(), + { + name: 'benchmark-report-dependencies', + buildEnd() { + for (const file of this.getModuleIds()) { + if (!file.includes('node_modules') && !file.startsWith('\0')) { + dependencies.add(file.split('?')[0]); + } + } + }, + }, + ], + define: { + 'process.env.NODE_ENV': JSON.stringify('production'), + __VUE_OPTIONS_API__: true, + __VUE_PROD_DEVTOOLS__: false, + __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, + }, + build: { + write: false, + minify: 'oxc', + cssCodeSplit: false, + lib: { entry, name: 'BenchmarkReport', formats: ['iife'] }, + }, + }); + const outputs = (Array.isArray(result) ? result : [result]).flatMap((bundle) => + 'output' in bundle ? bundle.output : [], + ); + const script = outputs + .filter((output) => output.type === 'chunk') + .map((output) => output.code) + .join('\n'); + const styles = outputs + .filter((output) => output.type === 'asset' && output.fileName.endsWith('.css')) + .map((output) => (output.type === 'asset' ? String(output.source) : '')) + .join('\n'); + if (!script || !styles) throw new Error('Benchmark report bundle is incomplete'); + for (const file of dependencies) this.addWatchFile(file); + return `export const script = ${JSON.stringify(script)}; export const styles = ${JSON.stringify(styles)};`; + }, + handleHotUpdate(context) { + if (!dependencies.has(context.file)) return; + const module = context.server.moduleGraph.getModuleById(resolvedID); + if (module) context.server.moduleGraph.invalidateModule(module); + context.server.ws.send({ type: 'full-reload' }); + }, + }; +} diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index f08c7d4f0..edf586993 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -10,8 +10,13 @@ export type FileUploadRequestConfig = AxiosRequestConfig & { skipErrorMessage?: boolean; }; -export const getFilesList = (params: File.ReqFile) => { - return http.post('files/search', params, TimeoutEnum.T_5M); +export const getFilesList = (params: File.ReqFile, currentNode?: string) => { + return http.post( + 'files/search', + params, + TimeoutEnum.T_5M, + currentNode ? { CurrentNode: currentNode } : undefined, + ); }; export const fileAiSearch = (params: File.FileAISearchReq) => { @@ -217,8 +222,13 @@ export const checkFileShare = (params: File.FileShareCheck, headers?: AxiosReque return http.get('files/share/check', params, { headers }); }; -export const computeDirSize = (params: File.DirSizeReq) => { - return http.post('files/size', params, TimeoutEnum.T_5M); +export const computeDirSize = (params: File.DirSizeReq, currentNode?: string) => { + return http.post( + 'files/size', + params, + TimeoutEnum.T_5M, + currentNode ? { CurrentNode: currentNode } : undefined, + ); }; export const computeDepthDirSize = (params: File.DirSizeReq) => { @@ -241,8 +251,13 @@ export const clearRecycle = () => { return http.post('files/recycle/clear'); }; -export const searchFavorite = (params: ReqPage) => { - return http.post>('files/favorite/search', params); +export const searchFavorite = (params: ReqPage, currentNode?: string) => { + return http.post>( + 'files/favorite/search', + params, + undefined, + currentNode ? { CurrentNode: currentNode } : undefined, + ); }; export const addFavorite = (path: string) => { diff --git a/frontend/src/components/file-list/index.vue b/frontend/src/components/file-list/index.vue index 1a1e32832..d71a53482 100644 --- a/frontend/src/components/file-list/index.vue +++ b/frontend/src/components/file-list/index.vue @@ -201,6 +201,7 @@ import { MsgSuccess, MsgWarning } from '@/utils/message'; import { useSearchableForSelect } from '@/views/host/file-management/hooks/searchable'; import { computeSize } from '@/utils/size'; import { debounce } from '@/utils/misc'; +const props = defineProps<{ currentNode?: string }>(); const data = ref([]); const loading = ref(false); const paths = ref([]); @@ -367,7 +368,7 @@ const getFileSize = async (path: string) => { }; updateByPath(path, { btnLoading: true }); try { - const res = await getFileContent(params); + const res = await getFileContent(params, props.currentNode); updateByPath(path, { dirSize: res.data.size }); } finally { updateByPath(path, { btnLoading: false }); @@ -380,7 +381,7 @@ const getDirSize = async (path: string) => { }; updateByPath(path, { btnLoading: true }); try { - const res = await computeDirSize(req); + const res = await computeDirSize(req, props.currentNode); updateByPath(path, { dirSize: res.data.size }); } finally { updateByPath(path, { btnLoading: false }); @@ -410,7 +411,7 @@ const getPaths = (reqPath: string) => { const search = async (req: File.ReqFile) => { req.dir = form.dir; loading.value = true; - await getFilesList(req) + await getFilesList(req, props.currentNode) .then((res) => { if (!res.data.path) { req.path = oldUrl.value; @@ -497,7 +498,7 @@ const createFolder = async (row: any) => { let addItem = {}; Object.assign(addItem, addForm); loading.value = true; - createFile(addItem as File.FileCreate) + createFile(addItem as File.FileCreate, props.currentNode) .then(async () => { row.isCreate = false; disBtn.value = false; @@ -524,7 +525,7 @@ const removeSelected = (index: number) => { const loadFavorites = async () => { try { - const res = await searchFavorite({ page: 1, pageSize: 100 }); + const res = await searchFavorite({ page: 1, pageSize: 100 }, props.currentNode); favorites.value = res.data.items || []; } catch {} }; diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts index a699b8a2d..36db6e1f4 100644 --- a/frontend/src/env.d.ts +++ b/frontend/src/env.d.ts @@ -5,3 +5,8 @@ declare module '*.vue' { const component: DefineComponent<{}, {}, any>; export default component; } + +declare module 'virtual:benchmark-report' { + export const script: string; + export const styles: string; +} diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index a91c94107..e9ed70a25 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1493,16 +1493,13 @@ const message = { statusWaiting: 'Waiting', base: 'Basic Information', backend: 'Backend', - baseUrl: 'Base URL', endpoint: 'Endpoint', tokenizer: 'Tokenizer', - tokenizerPlaceholder: - 'Select or enter a local tokenizer directory, e.g. /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: 'Enter an absolute directory on the main node or a Hugging Face repository ID', runConfig: 'Run Config', rawResult: 'Raw Result', resultMetrics: 'Result Metrics', contextTokens: 'Context Length', - contextTokensHelper: 'Input token limit plus output token limit for this benchmark.', outputThroughput: 'Output Throughput', outputThroughputHelper: 'Generated output tokens per second. Higher means faster generation.', totalThroughput: 'Total Throughput', @@ -1510,20 +1507,19 @@ const message = { firstTokenLatency: 'First Token Latency', firstTokenLatencyHelper: 'Time from sending the request to receiving the first token. Lower means faster response.', - tokenValueHelper: 'Enter a positive integer or k value, e.g. 512, 1k, 32k', numPrompts: 'Prompts', concurrency: 'Concurrency', requestRate: 'Request Rate', requestRateUnlimited: 'Unlimited (max throughput)', - requestRateCustom: 'Custom QPS', requestRateCustomPlaceholder: 'Requests per second, e.g. 2.5', successfulRequests: 'Successful Requests', requestThroughput: 'Request Throughput', mean: 'Mean', median: 'Median', - timeout: 'Timeout (seconds)', image: 'vLLM Image', - ignoreEos: 'Ignore EOS', + ignoreEos: 'Ignore end-of-sequence token (EOS)', + ignoreEosHelp: + 'Prevents early stopping at EOS to help test the configured output length. Other stop conditions still apply; server support is required.', extraHeaders: 'Extra Headers', }, vllmMonitor: { @@ -1737,6 +1733,155 @@ const message = { modelType: 'Model type', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Preparation time limit, excluded from the overall timeout.', + pointTimeoutHelp: + 'Separate timer per point, including startup, warmups and all requests; capped by the remaining overall time.', + totalTimeoutHelp: 'Starts after preparation, covers all points and intervals, and stops the test on timeout.', + concurrencyLevels: 'Concurrency levels', + concurrencyHelp: + 'Levels run sequentially. Each value limits the number of requests in progress at the same time.', + requestCountMode: 'Request count', + fixedRequestMode: 'Fixed requests per level', + scaledRequestMode: 'Calculate from concurrency', + requestsPerPoint: 'Requests per level', + requestCountFormula: + 'Per level: fixed value, or max(concurrency × multiplier, minimum requests). Scenario total: sum across levels × trials, excluding warmups.', + controlLog: 'Preparation and control log', + executionLog: 'Execution log', + pointLog: 'Point #{0} · {1} · Execution log', + archivedLog: '{0} (archive {1})', + tokenLengths: 'Input / output tokens', + kind: 'Result category', + kindServe: 'serve (regular tests)', + kindPD: 'pd (Prefill/Decode probes)', + saveDetailed: 'Save request details', + saveDetailedHelp: + 'Save per-request lengths, latencies, generated text and errors. Summary metrics remain available when disabled, reducing result file size.', + parameters: 'Parameters', + temperatureHelp: + 'Controls output randomness. Zero usually gives more stable output; higher values increase randomness.', + pointTimeout: 'Per-point timeout (seconds)', + temperature: 'Sampling temperature', + requestUrl: 'API URL', + invalidRequestUrl: + 'Enter a full HTTP(S) URL ending in /chat/completions or /completions, without credentials, query parameters, or fragments.', + requestRateHelp: + 'Applies only to this scenario. Unlimited rate still respects concurrency limits; fractional QPS is supported.', + tokenizerModeHelp: + 'Available modes depend on the vLLM version in the benchmark image. Tokenizer loading is checked during task preparation.', + invalidBaseUrl: 'Enter a valid HTTP(S) URL without credentials, query parameters or fragments.', + invalidEndpoint: + 'Enter an endpoint path matching the selected protocol and ending in {0}, without query parameters or fragments.', + invalidTokenizer: + 'Use an absolute directory or repository ID; relative paths, commas and line breaks are not supported.', + invalidRequestRate: 'Select unlimited or enter a finite number greater than 0; decimals are supported.', + invalidCaCert: 'Enter an absolute CA certificate file path on the primary node, without commas or line breaks.', + bodyOverride: 'Extra body cannot override {0}.', + invalidBody: 'Enter a valid JSON object.', + invalidConcurrencies: 'Provide 1–100 concurrency values, each an integer between 1 and 100000.', + emptyRequestCount: 'When calculating from concurrency, multiplier and minimum requests cannot both be 0.', + requestCountLimit: 'Calculated requests per point must not exceed 1000000.', + contextExceeded: 'Input tokens, output tokens and template reserve exceed the context limit.', + planLimit: 'Provide 1–100 scenarios with no more than 2000 expanded points.', + + caCertHelp: + 'Select a CA certificate file on the primary server to verify HTTPS services. Leave empty to use system certificates.', + extraBody: 'Extra request body', + entryKey: 'Parameter name', + entryValue: 'Parameter value', + tokenizerMode: 'Tokenizer mode', + requireIdle: 'Check service idle before starting', + requireIdleHelp: + 'Checks /metrics once before warmup and load testing. Stops if the service is busy or its idle state cannot be verified. This does not prevent other traffic during the test.', + trustRemoteCode: 'Trust remote code', + trustRemoteCodeHelp: + 'Allows custom tokenizer code from the model repository to run inside the benchmark container. Enable only when required and the source is trusted.', + tokenizerModes: { auto: 'Auto (recommended)', slow: 'Slow tokenizer', mistral: 'Mistral tokenizer' }, + quickDescription: 'Verify connectivity and measurement with a single request.', + regularDescription: 'Short, medium and long workloads for routine performance testing.', + fullDescription: + 'Multiple scenarios, concurrency levels and repeated runs, including long inputs and shared prefixes.', + customDescription: 'Start with one scenario, set its parameters and add more as needed.', + scenarios: 'Scenarios', + builtIn: 'Built-in', + builtInHelp: 'Built-in schemes cannot be edited or deleted. Adjust a copy when creating a test.', + modified: 'Modified', + + imageExists: 'Available locally', + imageNeedsPull: 'Pull required', + remark: 'Remarks', + source: 'Local service', + mode: 'Test plan', + quick: 'Quick check', + regular: 'Regular', + full: 'Full', + custom: 'Custom', + addScenario: 'Add scenario', + advanced: 'Advanced settings', + points: 'Points', + warmups: 'Warmup requests', + fixedRequests: 'Fixed requests', + multiplier: 'Requests per concurrency', + minRequests: 'Minimum requests', + trials: 'Trials', + prefixRatio: 'Shared prefix ratio', + totalTimeout: 'Round timeout (s)', + prepareTimeout: 'Preparation timeout (s)', + interval: 'Point interval (s)', + context: 'Context limit (0: unknown)', + reserve: 'Template token reserve', + storage: 'Storage limit (MiB)', + stopOnError: 'Stop subsequent points on error', + caCert: 'CA certificate path', + validTrials: 'Valid / total trials', + retry: 'Retry selected points', + environment: 'Environment', + plan: 'Frozen configuration', + clientHelp: + 'The client container runs on the main node and sends requests to an existing service. It does not start inference or require a GPU.', + retryHelp: 'Only selected abnormal points are retried, with the same parameters and new seeds.', + secretHelp: 'API keys and headers are excluded from copies. Enter them again if needed.', + resultHelp: + 'Only successful runs without request anomalies enter the median and min/max summaries. P99 is the median of per-run P99 values. Cache and external traffic are uncontrolled.', + }, + benchmarkOverview: { + noResults: 'No valid test results. Check the failure reason and logs.', + noGroupResults: 'No valid results for this combination. Select another scenario or concurrency.', + partial: 'Partial results: the test did not fully succeed. Metrics cover valid points only.', + highlights: 'Key metrics', + aggregate: 'Median across valid runs in this combination. Click a metric for details.', + trend: 'Concurrency trend', + std: 'Std. deviation', + min: 'Minimum', + max: 'Maximum', + tpot: 'Time per output token', + tpotHelp: 'Average generation time per output token after the first token.', + itl: 'Inter-token latency', + itlHelp: 'Time between consecutive tokens in a streaming response.', + e2el: 'End-to-end latency', + e2elHelp: 'Time from sending the request to receiving the complete response.', + requestHelp: 'Number of requests completed per second.', + usageHelp: + 'Medians of valid runs in this combination, not request totals for the entire test. See the Points tab for abnormal runs.', + duration: 'Run duration', + throughput: 'Throughput', + latency: 'Latency', + usage: 'Requests and usage (valid runs)', + }, + benchmarkTokenizer: { + title: 'Tokenizer management', + local: 'Register local directory', + upload: 'Upload tokenizer package', + uploadHelp: + 'Upload a ZIP / tar.gz containing tokenizer files without model weights. Maximum: 128 MiB compressed, 256 MiB extracted.', + source: 'Import method', + deleteLocal: 'Remove the registration for tokenizer “{0}”? The original directory and files will be kept.', + deleteUpload: 'Delete tokenizer “{0}” and its uploaded files? Historical test reports will be kept.', + select: 'Select a tokenizer', + selectHelp: + 'For offline testing, select a managed tokenizer. Custom input still accepts a local directory or repository name.', + }, container: { createByCommand: 'Create by command', importContainerBackupTip: 'Import container backup file, only .tar.gz is supported', diff --git a/frontend/src/lang/modules/es-es.ts b/frontend/src/lang/modules/es-es.ts index 88505b330..94f2b5293 100644 --- a/frontend/src/lang/modules/es-es.ts +++ b/frontend/src/lang/modules/es-es.ts @@ -1501,16 +1501,14 @@ const message = { 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', + 'Introduzca un directorio absoluto del nodo principal o un ID de repositorio de Hugging Face', 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', @@ -1519,20 +1517,19 @@ const message = { 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.', - tokenValueHelper: 'Introduzca un entero positivo o valor con k, p. ej. 512, 1k, 32k', numPrompts: 'Prompts', concurrency: 'Concurrencia', mean: 'Media', median: 'Mediana', requestRate: 'Tasa de solicitudes', requestRateUnlimited: 'Ilimitado (máximo rendimiento)', - requestRateCustom: 'QPS personalizado', requestRateCustomPlaceholder: 'Solicitudes por segundo, p. ej. 2.5', successfulRequests: 'Solicitudes correctas', requestThroughput: 'Rendimiento de solicitudes', - timeout: 'Tiempo de espera (segundos)', image: 'Imagen vLLM', - ignoreEos: 'Ignorar EOS', + ignoreEos: 'Ignorar el token de fin de secuencia (EOS)', + ignoreEosHelp: + 'Evita detenerse antes por EOS para probar la longitud de salida configurada. Las demás condiciones de parada siguen vigentes; requiere soporte del servidor.', extraHeaders: 'Encabezados adicionales', }, vllmMonitor: { @@ -1750,6 +1747,156 @@ const message = { modelType: 'Tipo de modelo', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Límite de preparación, excluido del tiempo límite total.', + pointTimeoutHelp: + 'Tiempo independiente por punto, con inicio, calentamiento y solicitudes; limitado por el tiempo total restante.', + totalTimeoutHelp: 'Empieza tras la preparación, incluye puntos e intervalos y detiene la prueba al agotarse.', + concurrencyLevels: 'Niveles de concurrencia', + concurrencyHelp: 'Los niveles se ejecutan en secuencia. Cada valor limita las solicitudes simultáneas.', + requestCountMode: 'Cantidad de solicitudes', + fixedRequestMode: 'Solicitudes fijas por nivel', + scaledRequestMode: 'Calcular según la concurrencia', + requestsPerPoint: 'Solicitudes por nivel', + requestCountFormula: + 'Por nivel: valor fijo o max(concurrencia × multiplicador, mínimo de solicitudes). Total del escenario: suma de los niveles × repeticiones, sin calentamiento.', + controlLog: 'Registro de preparación y control', + executionLog: 'Registro de ejecución', + pointLog: 'Punto n.º {0} · {1} · Registro de ejecución', + archivedLog: '{0} (archivo histórico {1})', + tokenLengths: 'Tokens de entrada / salida', + kind: 'Categoría de resultados', + kindServe: 'serve (pruebas normales)', + kindPD: 'pd (mediciones de Prefill/Decode)', + saveDetailed: 'Guardar detalles de solicitudes', + saveDetailedHelp: + 'Guarda longitudes, latencias, texto generado y errores de cada solicitud. Al desactivarlo se conservan las métricas resumidas y se reduce el tamaño de los archivos.', + parameters: 'Parámetros', + temperatureHelp: + 'Controla la aleatoriedad de la respuesta. Cero suele producir resultados más estables; los valores altos aumentan la aleatoriedad.', + pointTimeout: 'Tiempo límite por punto (segundos)', + temperature: 'Temperatura de muestreo', + requestUrl: 'URL de API', + invalidRequestUrl: + 'Introduzca una URL HTTP(S) completa terminada en /chat/completions o /completions, sin credenciales, parámetros de consulta ni fragmentos.', + requestRateHelp: + 'Se aplica solo a este escenario. La tasa ilimitada respeta los límites de concurrencia; se admite QPS fraccionario.', + tokenizerModeHelp: + 'Los modos disponibles dependen de la versión de vLLM de la imagen de prueba. La carga del tokenizador se comprueba al preparar la tarea.', + invalidBaseUrl: 'Introduzca una URL HTTP(S) válida sin credenciales, consultas ni fragmentos.', + invalidEndpoint: + 'Introduzca una ruta compatible con el protocolo seleccionado que termine en {0}, sin parámetros de consulta ni fragmentos.', + invalidTokenizer: + 'Use un directorio absoluto o un ID de repositorio; no se admiten rutas relativas, comas ni saltos de línea.', + invalidRequestRate: 'Seleccione sin límite o introduzca un número finito mayor que 0; se admiten decimales.', + invalidCaCert: + 'Introduzca la ruta absoluta del certificado CA en el nodo principal, sin comas ni saltos de línea.', + bodyOverride: 'El cuerpo adicional no puede sobrescribir {0}.', + invalidBody: 'Introduzca un objeto JSON válido.', + invalidConcurrencies: 'Indique entre 1 y 100 valores de concurrencia, cada uno un entero entre 1 y 100000.', + emptyRequestCount: + 'Al calcular según la concurrencia, el multiplicador y el mínimo de solicitudes no pueden ser ambos 0.', + requestCountLimit: 'Las solicitudes calculadas por punto no pueden superar 1000000.', + contextExceeded: 'Los tokens de entrada, salida y reserva de plantilla superan el límite de contexto.', + planLimit: 'Indique entre 1 y 100 escenarios con un máximo de 2000 puntos.', + + caCertHelp: + 'Seleccione un certificado CA del servidor principal para verificar servicios HTTPS. Déjelo vacío para usar los certificados del sistema.', + extraBody: 'Cuerpo adicional de la solicitud', + entryKey: 'Nombre del parámetro', + entryValue: 'Valor del parámetro', + tokenizerMode: 'Modo del tokenizador', + requireIdle: 'Comprobar que el servicio esté inactivo antes de comenzar', + requireIdleHelp: + 'Consulta /metrics una vez antes del calentamiento y la prueba de carga. Se detiene si el servicio está ocupado o no se puede verificar su estado. No impide otro tráfico durante la prueba.', + trustRemoteCode: 'Confiar en código remoto', + trustRemoteCodeHelp: + 'Permite ejecutar código de tokenización del repositorio del modelo dentro del contenedor de pruebas. Actívelo solo si es necesario y confía en la fuente.', + tokenizerModes: { auto: 'Automático (recomendado)', slow: 'Tokenizador lento', mistral: 'Tokenizador Mistral' }, + quickDescription: 'Verifica la conectividad y la medición con una sola solicitud.', + regularDescription: 'Cargas cortas, medias y largas para pruebas habituales de rendimiento.', + fullDescription: + 'Varios escenarios, niveles de concurrencia y repeticiones, con entradas largas y prefijos compartidos.', + customDescription: 'Empiece con un escenario, configure sus parámetros y añada más según necesite.', + scenarios: 'Escenarios', + builtIn: 'Integrado', + builtInHelp: 'Los esquemas integrados no se pueden editar ni eliminar. Ajuste una copia al crear una prueba.', + modified: 'Modificado', + + imageExists: 'Disponible localmente', + imageNeedsPull: 'Requiere descarga', + remark: 'Observaciones', + source: 'Servicio local', + mode: 'Plan de prueba', + quick: 'Comprobación rápida', + regular: 'Normal', + full: 'Completa', + custom: 'Personalizada', + addScenario: 'Añadir escenario', + advanced: 'Configuración avanzada', + points: 'Puntos', + warmups: 'Solicitudes de calentamiento', + fixedRequests: 'Solicitudes fijas', + multiplier: 'Solicitudes por concurrencia', + minRequests: 'Solicitudes mínimas', + trials: 'Repeticiones', + prefixRatio: 'Proporción de prefijo compartido', + totalTimeout: 'Tiempo límite de ronda (s)', + prepareTimeout: 'Tiempo límite de preparación (s)', + interval: 'Intervalo entre puntos (s)', + context: 'Límite de contexto (0: desconocido)', + reserve: 'Tokens reservados para plantilla', + storage: 'Límite de almacenamiento (MiB)', + stopOnError: 'Detener los siguientes puntos si hay errores', + caCert: 'Ruta del certificado CA', + validTrials: 'Válidas / total', + retry: 'Repetir puntos seleccionados', + environment: 'Entorno', + plan: 'Configuración fijada', + clientHelp: + 'El contenedor cliente se ejecuta en el nodo principal y envía solicitudes a un servicio existente. No inicia inferencia ni requiere GPU.', + retryHelp: 'Solo se repiten los puntos anómalos seleccionados, con los mismos parámetros y nuevas semillas.', + secretHelp: 'Las copias no incluyen claves API ni cabeceras. Vuelva a introducirlas si es necesario.', + resultHelp: + 'La mediana y los mínimos/máximos solo incluyen ejecuciones correctas sin anomalías. P99 es la mediana de los P99 de cada ejecución. La caché y el tráfico externo no están controlados.', + }, + benchmarkOverview: { + noResults: 'No hay resultados válidos. Consulte la causa del fallo y los registros.', + noGroupResults: 'Esta combinación no tiene resultados válidos. Seleccione otro escenario o concurrencia.', + partial: 'Resultados parciales: la prueba no se completó con éxito. Solo se incluyen puntos válidos.', + highlights: 'Métricas principales', + aggregate: 'Mediana de las ejecuciones válidas de esta combinación. Pulse una métrica para ver los detalles.', + trend: 'Tendencia por concurrencia', + std: 'Desviación estándar', + min: 'Mínimo', + max: 'Máximo', + tpot: 'Tiempo por token de salida', + tpotHelp: 'Tiempo medio de generación por token de salida después del primero.', + itl: 'Latencia entre tokens', + itlHelp: 'Tiempo entre tokens consecutivos de una respuesta en streaming.', + e2el: 'Latencia de extremo a extremo', + e2elHelp: 'Tiempo desde el envío de la solicitud hasta la recepción de la respuesta completa.', + requestHelp: 'Número de solicitudes completadas por segundo.', + usageHelp: + 'Medianas de las ejecuciones válidas de esta combinación, no totales de solicitudes de toda la prueba. Consulte las ejecuciones anómalas en la pestaña de puntos.', + duration: 'Duración de la ejecución', + throughput: 'Rendimiento', + latency: 'Latencia', + usage: 'Solicitudes y uso (ejecuciones válidas)', + }, + benchmarkTokenizer: { + title: 'Gestión de tokenizadores', + local: 'Registrar directorio local', + upload: 'Subir paquete de tokenizador', + uploadHelp: 'Suba un ZIP / tar.gz sin pesos del modelo. Máximo: 128 MiB comprimido y 256 MiB extraído.', + source: 'Método de importación', + deleteLocal: + '¿Quitar el registro del tokenizador «{0}»? Se conservarán el directorio y los archivos originales.', + deleteUpload: '¿Eliminar el tokenizador «{0}» y sus archivos subidos? Se conservarán los informes anteriores.', + select: 'Seleccionar un tokenizador', + selectHelp: + 'Para pruebas sin conexión, seleccione un tokenizador gestionado. La entrada personalizada admite directorios locales o nombres de repositorios.', + }, container: { createByCommand: 'Crear por comando', importContainerBackupTip: 'Importar archivo de copia de seguridad de contenedor, solo se admite .tar.gz', diff --git a/frontend/src/lang/modules/fa.ts b/frontend/src/lang/modules/fa.ts index eb54e87c9..ceb088c94 100644 --- a/frontend/src/lang/modules/fa.ts +++ b/frontend/src/lang/modules/fa.ts @@ -1477,16 +1477,13 @@ const message = { statusWaiting: 'در انتظار', base: 'اطلاعات پایه', backend: 'بک‌اند', - baseUrl: 'URL پایه', endpoint: 'نقطه پایانی', tokenizer: 'توکن‌ساز', - tokenizerPlaceholder: - 'یک دایرکتوری توکن‌ساز محلی را انتخاب یا وارد کنید، مثلاً /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: 'مسیر مطلق پوشه در گره اصلی یا شناسه مخزن Hugging Face را وارد کنید', runConfig: 'پیکربندی اجرا', rawResult: 'نتیجه خام', resultMetrics: 'معیارهای نتیجه', contextTokens: 'طول زمینه', - contextTokensHelper: 'محدودیت توکن ورودی به اضافه محدودیت توکن خروجی برای این معیار سنجش.', outputThroughput: 'توان خروجی', outputThroughputHelper: 'توکن‌های خروجی تولید شده در ثانیه. بیشتر به معنای تولید سریع‌تر است.', totalThroughput: 'توان کل', @@ -1494,20 +1491,19 @@ const message = { 'توکن‌های ورودی و خروجی پردازش شده در ثانیه. برای اندازه‌گیری ظرفیت کلی استفاده می‌شود.', firstTokenLatency: 'تأخیر اولین توکن', firstTokenLatencyHelper: 'زمان از ارسال درخواست تا دریافت اولین توکن. کمتر به معنای پاسخ سریع‌تر است.', - tokenValueHelper: 'یک عدد صحیح مثبت یا مقدار k وارد کنید، مثلاً 512، 1k، 32k', numPrompts: 'راهنماها', concurrency: 'هم‌روندی', requestRate: 'نرخ درخواست', requestRateUnlimited: 'نامحدود (حداکثر توان)', - requestRateCustom: 'QPS سفارشی', requestRateCustomPlaceholder: 'درخواست در ثانیه، مثلاً 2.5', successfulRequests: 'درخواست‌های موفق', requestThroughput: 'توان درخواست', mean: 'میانگین', median: 'میانه', - timeout: 'مهلت (ثانیه)', image: 'تصویر vLLM', - ignoreEos: 'نادیده گرفتن EOS', + ignoreEos: 'نادیده گرفتن توکن پایان دنباله (EOS)', + ignoreEosHelp: + 'از توقف زودهنگام به دلیل EOS جلوگیری می‌کند تا طول خروجی تنظیم‌شده آزموده شود. سایر شرایط توقف همچنان اعمال می‌شوند و پشتیبانی سرور لازم است.', extraHeaders: 'هدرهای اضافی', }, vllmMonitor: { @@ -1718,6 +1714,153 @@ const message = { modelType: 'نوع مدل', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'مهلت آماده‌سازی در مهلت کلی آزمون محاسبه نمی‌شود.', + pointTimeoutHelp: + 'زمان‌سنج مستقل هر نقطه، شامل راه‌اندازی، گرم‌کردن و همه درخواست‌ها؛ محدود به زمان کلی باقی‌مانده.', + totalTimeoutHelp: + 'پس از آماده‌سازی شروع می‌شود و همه نقاط و فاصله‌ها را شامل می‌شود. با پایان مهلت، آزمون متوقف می‌شود.', + concurrencyLevels: 'سطوح هم‌زمانی', + concurrencyHelp: + 'سطوح به‌ترتیب آزمایش می‌شوند. هر مقدار سقف تعداد درخواست‌های در حال اجرا به‌صورت هم‌زمان است.', + requestCountMode: 'تنظیم تعداد درخواست‌ها', + fixedRequestMode: 'تعداد ثابت برای هر سطح', + scaledRequestMode: 'محاسبه بر اساس هم‌زمانی', + requestsPerPoint: 'درخواست در هر سطح', + requestCountFormula: + 'هر سطح: مقدار ثابت یا max(هم‌زمانی × ضریب، حداقل درخواست‌ها). مجموع سناریو: مجموع سطوح × تعداد تکرار، بدون گرم‌کردن.', + controlLog: 'گزارش آماده‌سازی و کنترل', + executionLog: 'گزارش اجرا', + pointLog: 'نقطهٔ {0} · {1} · گزارش اجرا', + archivedLog: '{0} (بایگانی {1})', + tokenLengths: 'توکن‌های ورودی / خروجی', + kind: 'دسته‌بندی نتایج', + kindServe: 'serve (آزمون‌های معمول)', + kindPD: 'pd (سنجش Prefill/Decode)', + saveDetailed: 'ذخیره جزئیات درخواست‌ها', + saveDetailedHelp: + 'طول، تأخیر، متن تولیدشده و خطاهای هر درخواست را ذخیره می‌کند. با غیرفعال کردن، شاخص‌های خلاصه حفظ و حجم فایل نتیجه کمتر می‌شود.', + parameters: 'پارامترها', + temperatureHelp: + 'میزان تصادفی بودن خروجی را کنترل می‌کند. صفر معمولاً خروجی پایدارتری می‌دهد؛ مقادیر بالاتر تصادفی بودن را افزایش می‌دهند.', + pointTimeout: 'مهلت هر نقطه (ثانیه)', + temperature: 'دمای نمونه‌برداری', + requestUrl: 'نشانی API', + invalidRequestUrl: + 'نشانی کامل HTTP(S) را با پایان /chat/completions یا /completions وارد کنید؛ بدون اطلاعات ورود، پارامترهای پرس‌وجو یا بخش پس از #.', + requestRateHelp: + 'فقط برای این سناریو اعمال می‌شود. نرخ نامحدود همچنان از سقف هم‌زمانی پیروی می‌کند؛ QPS اعشاری پشتیبانی می‌شود.', + tokenizerModeHelp: + 'حالت‌های موجود به نسخه vLLM در تصویر آزمون بستگی دارند. بارگذاری توکن‌ساز هنگام آماده‌سازی کار بررسی می‌شود.', + invalidBaseUrl: 'نشانی معتبر HTTP(S) بدون اطلاعات ورود، پارامتر پرس‌وجو یا قطعه وارد کنید.', + invalidEndpoint: + 'مسیر سازگار با پروتکل انتخاب‌شده را وارد کنید که به {0} ختم شود و پارامتر پرس‌وجو یا بخش نشانی نداشته باشد.', + invalidTokenizer: 'مسیر مطلق پوشه یا شناسه مخزن را وارد کنید؛ مسیر نسبی، ویرگول و خط جدید پشتیبانی نمی‌شوند.', + invalidRequestRate: 'نامحدود را انتخاب کنید یا عدد متناهی بزرگ‌تر از 0 وارد کنید؛ اعشار مجاز است.', + invalidCaCert: 'مسیر مطلق فایل گواهی CA در گره اصلی را بدون ویرگول یا خط جدید وارد کنید.', + bodyOverride: 'بدنه اضافی نمی‌تواند {0} را بازنویسی کند.', + invalidBody: 'یک شیء JSON معتبر وارد کنید.', + invalidConcurrencies: 'بین 1 تا 100 مقدار هم‌زمانی وارد کنید؛ هر مقدار عدد صحیح بین 1 و 100000 باشد.', + emptyRequestCount: 'هنگام محاسبه بر اساس هم‌زمانی، ضریب و حداقل درخواست‌ها نمی‌توانند هر دو 0 باشند.', + requestCountLimit: 'تعداد محاسبه‌شده درخواست‌ها در هر نقطه نباید بیشتر از 1000000 باشد.', + contextExceeded: 'مجموع توکن‌های ورودی، خروجی و ذخیره قالب از حد زمینه بیشتر است.', + planLimit: 'بین 1 تا 100 سناریو با حداکثر 2000 نقطه وارد کنید.', + + caCertHelp: + 'فایل گواهی CA را از سرور اصلی برای تأیید سرویس HTTPS انتخاب کنید. برای استفاده از گواهی‌های سیستم خالی بگذارید.', + extraBody: 'بدنه اضافی درخواست', + entryKey: 'نام پارامتر', + entryValue: 'مقدار پارامتر', + tokenizerMode: 'حالت توکن‌ساز', + requireIdle: 'بررسی بیکار بودن سرویس پیش از شروع', + requireIdleHelp: + 'پیش از گرم‌کردن و آزمون بار، /metrics یک بار بررسی می‌شود. اگر سرویس مشغول باشد یا بیکار بودن آن قابل تأیید نباشد، آزمون متوقف می‌شود. این بررسی مانع ترافیک دیگر در طول آزمون نمی‌شود.', + trustRemoteCode: 'اعتماد به کد راه‌دور', + trustRemoteCodeHelp: + 'اجرای کد سفارشی توکن‌ساز از مخزن مدل در کانتینر آزمون را مجاز می‌کند. فقط در صورت نیاز و اعتماد به منبع فعال کنید.', + tokenizerModes: { auto: 'خودکار (پیشنهادی)', slow: 'توکن‌ساز کند', mistral: 'توکن‌ساز Mistral' }, + quickDescription: 'اتصال و فرایند اندازه‌گیری را با یک درخواست بررسی می‌کند.', + regularDescription: 'بارهای کوتاه، متوسط و بلند برای آزمون روزمره عملکرد.', + fullDescription: 'چندین سناریو، سطح هم‌زمانی و اجرای تکراری، شامل ورودی‌های بلند و پیشوندهای مشترک.', + customDescription: + 'با یک سناریو شروع کنید، پارامترهای آن را تنظیم کنید و در صورت نیاز سناریوهای بیشتری اضافه کنید.', + scenarios: 'سناریوها', + builtIn: 'داخلی', + builtInHelp: 'طرح‌های داخلی قابل ویرایش یا حذف نیستند. هنگام ایجاد آزمون یک نسخه را تنظیم کنید.', + modified: 'تغییریافته', + + imageExists: 'موجود در میزبان', + imageNeedsPull: 'نیازمند دریافت', + remark: 'یادداشت', + source: 'سرویس محلی', + mode: 'برنامه آزمون', + quick: 'بررسی سریع', + regular: 'معمولی', + full: 'کامل', + custom: 'سفارشی', + addScenario: 'افزودن سناریو', + advanced: 'تنظیمات پیشرفته', + points: 'نقاط اندازه‌گیری', + warmups: 'درخواست‌های گرم‌سازی', + fixedRequests: 'درخواست ثابت', + multiplier: 'ضریب درخواست بر هم‌زمانی', + minRequests: 'حداقل درخواست', + trials: 'تکرارها', + prefixRatio: 'نسبت پیشوند مشترک', + totalTimeout: 'مهلت دور (ثانیه)', + prepareTimeout: 'مهلت آماده‌سازی (ثانیه)', + interval: 'فاصله نقاط (ثانیه)', + context: 'حد زمینه (۰: نامشخص)', + reserve: 'توکن ذخیره قالب', + storage: 'حد ذخیره‌سازی (MiB)', + stopOnError: 'توقف نقاط بعدی هنگام خطا', + caCert: 'مسیر گواهی CA', + validTrials: 'معتبر / کل تکرارها', + retry: 'تکرار نقاط انتخاب‌شده', + environment: 'محیط اجرا', + plan: 'پیکربندی ثابت', + clientHelp: + 'کانتینر کلاینت در گره اصلی به سرویس موجود درخواست می‌فرستد. سرویس استنتاج راه‌اندازی نمی‌کند و به GPU نیاز ندارد.', + retryHelp: 'فقط نقاط غیرعادی انتخاب‌شده با همان پارامترها و بذرهای جدید تکرار می‌شوند.', + secretHelp: 'کپی‌ها شامل کلید API و سرآیندها نیستند. در صورت نیاز دوباره وارد کنید.', + resultHelp: + 'میانه و کمینه/بیشینه فقط از اجراهای موفق بدون ناهنجاری درخواست محاسبه می‌شوند. P99 میانه P99 هر اجرا است. کش و ترافیک بیرونی کنترل نشده‌اند.', + }, + benchmarkOverview: { + noResults: 'نتیجه معتبر وجود ندارد. علت شکست و گزارش‌ها را بررسی کنید.', + noGroupResults: 'برای این ترکیب نتیجه معتبر وجود ندارد. سناریو یا هم‌زمانی دیگری انتخاب کنید.', + partial: 'نتایج جزئی: آزمون کاملاً موفق نبوده است. معیارها فقط نقاط معتبر را شامل می‌شوند.', + highlights: 'معیارهای اصلی', + aggregate: 'میانه اجراهای معتبر این ترکیب. برای جزئیات روی معیار کلیک کنید.', + trend: 'روند هم‌زمانی', + std: 'انحراف معیار', + min: 'کمینه', + max: 'بیشینه', + tpot: 'زمان هر توکن خروجی', + tpotHelp: 'میانگین زمان تولید هر توکن خروجی پس از توکن نخست.', + itl: 'تأخیر بین توکن‌ها', + itlHelp: 'زمان بین توکن‌های متوالی در پاسخ جریانی.', + e2el: 'تأخیر سرتاسری', + e2elHelp: 'زمان ارسال درخواست تا دریافت کامل پاسخ.', + requestHelp: 'تعداد درخواست‌های تکمیل‌شده در ثانیه.', + usageHelp: + 'میانه اجراهای معتبر این ترکیب است، نه مجموع درخواست‌های کل آزمون. اجراهای غیرعادی را در زبانه نقاط بررسی کنید.', + duration: 'مدت اجرا', + throughput: 'توان عملیاتی', + latency: 'تأخیر', + usage: 'درخواست‌ها و مصرف (اجراهای معتبر)', + }, + benchmarkTokenizer: { + title: 'مدیریت توکن‌ساز', + local: 'ثبت پوشه محلی', + upload: 'بارگذاری بسته توکن‌ساز', + uploadHelp: 'فایل ZIP / tar.gz بدون وزن‌های مدل بارگذاری کنید. حداکثر ۱۲۸ MiB فشرده و ۲۵۶ MiB پس از استخراج.', + source: 'روش ورود', + deleteLocal: 'ثبت توکن‌ساز «{0}» حذف شود؟ پوشه و فایل‌های اصلی حفظ می‌شوند.', + deleteUpload: 'توکن‌ساز «{0}» و فایل‌های بارگذاری‌شده حذف شوند؟ گزارش‌های پیشین حفظ می‌شوند.', + select: 'انتخاب توکنایزر', + selectHelp: 'برای آزمون آفلاین از فهرست مدیریت انتخاب کنید. ورودی سفارشی پوشه محلی یا نام مخزن را می‌پذیرد.', + }, container: { createByCommand: 'ایجاد با دستور', importContainerBackupTip: 'واردات فایل پشتیبان کانتینر، فقط .tar.gz پشتیبانی می‌شود', diff --git a/frontend/src/lang/modules/ja.ts b/frontend/src/lang/modules/ja.ts index 9a751f307..0727e8f98 100644 --- a/frontend/src/lang/modules/ja.ts +++ b/frontend/src/lang/modules/ja.ts @@ -1482,36 +1482,32 @@ const message = { statusWaiting: '待機中', base: '基本情報', backend: 'バックエンド', - baseUrl: 'Base URL', endpoint: 'エンドポイント', tokenizer: 'トークナイザー', - tokenizerPlaceholder: - 'ローカルトークナイザーディレクトリを選択または入力してください。例: /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: 'メインノード上の絶対ディレクトリパス、または Hugging Face リポジトリ ID を入力', runConfig: '実行設定', rawResult: '生データ', resultMetrics: '結果指標', contextTokens: 'コンテキスト長', - contextTokensHelper: 'このベンチマークの入力 Token 上限と出力 Token 上限の合計です。', outputThroughput: '出力スループット', outputThroughputHelper: '1 秒あたりに生成される出力 Token 数です。高いほど生成が速くなります。', totalThroughput: '合計スループット', totalThroughputHelper: '1 秒あたりに処理される入力と出力 Token の合計で、全体性能の測定に使います。', firstTokenLatency: '初回 Token レイテンシ', firstTokenLatencyHelper: 'リクエスト送信から最初の Token 受信までの時間です。低いほど応答が速くなります。', - tokenValueHelper: '正の整数または k 単位を入力してください。例: 512、1k、32k', numPrompts: 'プロンプト数', concurrency: '同時実行数', mean: '平均値', median: '中央値', requestRate: 'リクエストレート', requestRateUnlimited: '無制限(最大スループット)', - requestRateCustom: 'カスタム QPS', requestRateCustomPlaceholder: '1 秒あたりのリクエスト数。例: 2.5', successfulRequests: '成功リクエスト', requestThroughput: 'リクエストスループット', - timeout: 'タイムアウト(秒)', image: 'vLLM イメージ', - ignoreEos: 'EOS を無視', + ignoreEos: '終了トークン(EOS)を無視', + ignoreEosHelp: + 'EOS による早期終了を防ぎ、指定した出力長でのテストを助けます。他の停止条件は有効で、サーバー側の対応が必要です。', extraHeaders: '追加ヘッダー', }, vllmMonitor: { @@ -1721,6 +1717,153 @@ const message = { modelType: 'モデルタイプ', }, }, + benchmarkPlan: { + prepareTimeoutHelp: '準備時間の上限です。テスト全体のタイムアウトには含みません。', + pointTimeoutHelp: + '各測定点で個別に計時し、起動、ウォームアップ、全リクエストを含みます。全体の残り時間にも制限されます。', + totalTimeoutHelp: '準備完了後に開始し、全測定点と待機時間を含みます。時間切れでテストを停止します。', + concurrencyLevels: '同時実行数の段階', + concurrencyHelp: '各段階を順番にテストします。各値は同時に処理するリクエスト数の上限です。', + requestCountMode: 'リクエスト数の設定', + fixedRequestMode: '各段階のリクエスト数を固定', + scaledRequestMode: '同時実行数から計算', + requestsPerPoint: '各段階のリクエスト数', + requestCountFormula: + '各段階:固定値、または max(同時実行数 × 倍率, 最小リクエスト数)。 シナリオ合計:各段階の合計 × 繰り返し回数(ウォームアップを除く)。', + controlLog: '準備・制御ログ', + executionLog: '実行ログ', + pointLog: '測定点 #{0} · {1} · 実行ログ', + archivedLog: '{0}(履歴 {1})', + tokenLengths: '入力 / 出力トークン', + kind: '結果分類', + kindServe: 'serve(通常のテスト)', + kindPD: 'pd(Prefill/Decode 測定)', + saveDetailed: 'リクエスト詳細を保存', + saveDetailedHelp: + '各リクエストの長さ、遅延、生成テキスト、エラーを保存します。無効にしても集計指標は残り、結果ファイルを小さくできます。', + parameters: 'パラメーター', + temperatureHelp: + '生成内容のランダム性を制御します。0 は通常より安定した出力になり、値が高いほどランダム性が増します。', + pointTimeout: '測定点ごとのタイムアウト(秒)', + temperature: 'サンプリング温度', + requestUrl: 'API URL', + invalidRequestUrl: + '/chat/completions または /completions で終わる完全な HTTP(S) URL を入力してください。認証情報、クエリ、フラグメントは使用できません。', + requestRateHelp: + 'このシナリオにのみ適用します。無制限でも同時実行数の上限に従います。小数の QPS も使用できます。', + tokenizerModeHelp: + '利用可能なモードはベンチマークイメージの vLLM バージョンによって異なります。タスクの準備時にトークナイザーを読み込めるか確認します。', + invalidBaseUrl: '認証情報、クエリ、フラグメントを含まない有効な HTTP(S) URL を入力してください。', + invalidEndpoint: + '選択したプロトコルに対応し、{0} で終わるパスを入力してください。クエリパラメーターやフラグメントは含めないでください。', + invalidTokenizer: + '絶対ディレクトリパスまたはリポジトリ ID を指定してください。相対パス、カンマ、改行は使用できません。', + invalidRequestRate: '無制限を選択するか、0 より大きい有限の数値を入力してください。小数も使用できます。', + invalidCaCert: 'プライマリノード上の CA 証明書の絶対パスを入力してください。カンマや改行は使用できません。', + bodyOverride: '追加本文で {0} を上書きできません。', + invalidBody: '有効な JSON オブジェクトを入力してください。', + invalidConcurrencies: '同時実行数は 1~100 項目、各値は 1~100000 の整数にしてください。', + emptyRequestCount: '同時実行数から計算する場合、倍率と最小リクエスト数の両方を 0 にできません。', + requestCountLimit: '測定点ごとの計算済みリクエスト数は 1000000 以下にしてください。', + contextExceeded: '入力・出力トークンとテンプレート予約分の合計がコンテキスト上限を超えています。', + planLimit: 'シナリオは 1~100 件、展開後の測定点は 2000 件以下にしてください。', + + caCertHelp: + 'HTTPS サービスの検証に使う CA 証明書をプライマリサーバーから選択します。空欄の場合はシステム証明書を使用します。', + extraBody: '追加のリクエスト本文', + entryKey: 'パラメーター名', + entryValue: 'パラメーター値', + tokenizerMode: 'トークナイザーモード', + requireIdle: '開始前にサービスのアイドル状態を確認', + requireIdleHelp: + 'ウォームアップと負荷テストの前に /metrics を一度確認します。サービスが処理中、またはアイドル状態を確認できない場合は停止します。テスト中の他のトラフィックは防げません。', + trustRemoteCode: 'リモートコードを信頼', + trustRemoteCodeHelp: + 'モデルリポジトリのカスタムトークナイザーコードをベンチマークコンテナー内で実行します。必要な場合に、信頼できる提供元に対してのみ有効にしてください。', + tokenizerModes: { auto: '自動(推奨)', slow: '低速トークナイザー', mistral: 'Mistral 専用' }, + quickDescription: '単一リクエストで接続と測定処理を確認します。', + regularDescription: '短・中・長の負荷で日常的な性能テストを行います。', + fullDescription: '長い入力と共有プレフィックスを含む、複数シナリオ・同時実行数での反復測定です。', + customDescription: '1つのシナリオから始め、パラメーターを設定し、必要に応じて追加します。', + scenarios: 'シナリオ', + builtIn: '組み込み', + builtInHelp: '組み込みプランは編集・削除できません。テスト作成時にコピーを調整できます。', + modified: '変更済み', + + imageExists: 'ローカルに存在', + imageNeedsPull: '取得が必要', + remark: '備考', + source: 'ローカルサービス', + mode: 'テスト計画', + quick: '簡易確認', + regular: '通常', + full: '完全', + custom: 'カスタム', + addScenario: 'シナリオを追加', + advanced: '詳細設定', + points: '測定点', + warmups: 'ウォームアップ要求数', + fixedRequests: '固定要求数', + multiplier: '同時実行数に対する要求数倍率', + minRequests: '最小要求数', + trials: '繰り返し回数', + prefixRatio: '共通プレフィックス比率', + totalTimeout: '全体のタイムアウト(秒)', + prepareTimeout: '準備のタイムアウト(秒)', + interval: '測定間隔(秒)', + context: 'コンテキスト上限(0:不明)', + reserve: 'テンプレート用予約トークン', + storage: '保存容量上限(MiB)', + stopOnError: 'エラー時に後続の測定を停止', + caCert: 'CA 証明書のパス', + validTrials: '有効 / 総試行数', + retry: '選択した測定点を再試行', + environment: '実行環境', + plan: '固定された設定', + clientHelp: + 'クライアントコンテナはメインノードで既存サービスに要求を送信します。推論サービスの起動や GPU の割り当ては不要です。', + retryHelp: '選択した異常な測定点のみ、同じパラメータと新しいシードで再試行します。', + secretHelp: 'コピーに API キーとヘッダーは含まれません。必要に応じて再入力してください。', + resultHelp: + '要求異常のない成功した試行のみを集計し、中央値と最小・最大値を表示します。P99 は試行ごとの P99 の中央値です。キャッシュと外部トラフィックは制御されません。', + }, + benchmarkOverview: { + noResults: '有効なテスト結果がありません。失敗の原因とログを確認してください。', + noGroupResults: 'この組み合わせに有効な結果はありません。シナリオまたは同時実行数を変更してください。', + partial: '部分的な結果:テストは完全には成功していません。有効な測定点のみを表示します。', + highlights: '主要指標', + aggregate: 'この組み合わせの有効な実行の中央値です。指標をクリックすると詳細を表示します。', + trend: '同時実行数による推移', + std: '標準偏差', + min: '最小値', + max: '最大値', + tpot: '出力トークンあたりの時間', + tpotHelp: '最初のトークン以降の、出力トークンあたりの平均生成時間。', + itl: 'トークン間レイテンシ', + itlHelp: 'ストリーミング応答の連続するトークン間の時間。', + e2el: 'エンドツーエンドのレイテンシ', + e2elHelp: 'リクエスト送信から応答の受信完了までの時間。', + requestHelp: '1 秒あたりに完了したリクエスト数。', + usageHelp: + 'この組み合わせの有効な実行の中央値であり、テスト全体のリクエスト総数ではありません。異常な実行は測定点タブで確認してください。', + duration: '実行時間', + throughput: 'スループット', + latency: 'レイテンシ', + usage: 'リクエストと使用量(有効な実行)', + }, + benchmarkTokenizer: { + title: 'トークナイザー管理', + local: 'ローカルディレクトリを登録', + upload: 'トークナイザーをアップロード', + uploadHelp: + 'モデルの重みを含まない ZIP / tar.gz をアップロードしてください。圧縮時 128 MiB、展開後 256 MiB まで。', + source: 'インポート方法', + deleteLocal: '「{0}」の登録を解除しますか?元のディレクトリとファイルは保持されます。', + deleteUpload: '「{0}」とアップロード済みファイルを削除しますか?過去のテストレポートは保持されます。', + select: 'トークナイザーを選択', + selectHelp: + 'オフラインでは管理リストから選択してください。カスタム入力ではローカルパスやリポジトリ名も使えます。', + }, container: { createByCommand: 'コマンドで作成', importContainerBackupTip: 'コンテナバックアップファイルをインポートします。.tar.gz のみ対応です', diff --git a/frontend/src/lang/modules/ko.ts b/frontend/src/lang/modules/ko.ts index 8a6c336de..d75b7d6dc 100644 --- a/frontend/src/lang/modules/ko.ts +++ b/frontend/src/lang/modules/ko.ts @@ -1467,36 +1467,32 @@ const message = { statusWaiting: '대기 중', base: '기본 정보', backend: '백엔드', - baseUrl: 'Base URL', endpoint: '엔드포인트', tokenizer: '토크나이저', - tokenizerPlaceholder: - '로컬 토크나이저 디렉터리를 선택하거나 입력하세요. 예: /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: '메인 노드의 절대 디렉터리 경로 또는 Hugging Face 저장소 ID를 입력하세요', runConfig: '실행 구성', rawResult: '원시 결과', resultMetrics: '결과 지표', contextTokens: '컨텍스트 길이', - contextTokensHelper: '이 벤치마크의 입력 Token 제한과 출력 Token 제한의 합계입니다.', outputThroughput: '출력 처리량', outputThroughputHelper: '초당 생성된 출력 Token 수입니다. 높을수록 생성 속도가 빠릅니다.', totalThroughput: '총 처리량', totalThroughputHelper: '초당 처리된 입력 및 출력 Token 수로 전체 처리 능력을 측정합니다.', firstTokenLatency: '첫 Token 지연 시간', firstTokenLatencyHelper: '요청 전송부터 첫 Token 수신까지의 시간입니다. 낮을수록 응답이 빠릅니다.', - tokenValueHelper: '양의 정수 또는 k 값을 입력하세요. 예: 512, 1k, 32k', numPrompts: '프롬프트 수', concurrency: '동시성', mean: '평균값', median: '중앙값', requestRate: '요청 속도', requestRateUnlimited: '무제한(최대 처리량)', - requestRateCustom: '사용자 지정 QPS', requestRateCustomPlaceholder: '초당 요청 수, 예: 2.5', successfulRequests: '성공한 요청', requestThroughput: '요청 처리량', - timeout: '시간 초과(초)', image: 'vLLM 이미지', - ignoreEos: 'EOS 무시', + ignoreEos: '종료 토큰(EOS) 무시', + ignoreEosHelp: + 'EOS로 인한 조기 종료를 방지하여 설정한 출력 길이로 테스트하도록 돕습니다. 다른 종료 조건은 계속 적용되며 서버 지원이 필요합니다.', extraHeaders: '추가 헤더', }, vllmMonitor: { @@ -1704,6 +1700,150 @@ const message = { modelType: '모델 유형', }, }, + benchmarkPlan: { + prepareTimeoutHelp: '준비 시간 제한이며 전체 시간 제한에서 제외됩니다.', + pointTimeoutHelp: '측정점별로 시작, 워밍업 및 모든 요청 시간을 측정하며, 남은 전체 시간의 제한도 받습니다.', + totalTimeoutHelp: '준비 후 시작하며 모든 측정점과 대기 시간을 포함합니다. 시간 초과 시 테스트를 중단합니다.', + concurrencyLevels: '동시 실행 단계', + concurrencyHelp: '각 단계를 순서대로 테스트합니다. 각 값은 동시에 진행 중인 요청 수의 상한입니다.', + requestCountMode: '요청 수 설정', + fixedRequestMode: '단계별 고정 요청 수', + scaledRequestMode: '동시 실행 수로 계산', + requestsPerPoint: '단계별 요청 수', + requestCountFormula: + '단계별: 고정값 또는 max(동시 실행 수 × 배수, 최소 요청 수). 시나리오 총량: 모든 단계의 합계 × 반복 횟수 (워밍업 제외).', + controlLog: '준비 및 제어 로그', + executionLog: '실행 로그', + pointLog: '측정 지점 #{0} · {1} · 실행 로그', + archivedLog: '{0} (이전 로그 {1})', + tokenLengths: '입력 / 출력 토큰', + kind: '결과 분류', + kindServe: 'serve (일반 테스트)', + kindPD: 'pd (Prefill/Decode 측정)', + saveDetailed: '요청 상세 정보 저장', + saveDetailedHelp: + '각 요청의 길이, 지연 시간, 생성 텍스트 및 오류를 저장합니다. 비활성화해도 요약 지표는 유지되며 결과 파일 크기를 줄일 수 있습니다.', + parameters: '매개변수', + temperatureHelp: + '생성 내용의 무작위성을 제어합니다. 0은 일반적으로 더 안정적인 출력을 제공하며 값이 높을수록 무작위성이 커집니다.', + pointTimeout: '측정점별 제한 시간(초)', + temperature: '샘플링 온도', + requestUrl: 'API 주소', + invalidRequestUrl: + '/chat/completions 또는 /completions로 끝나는 전체 HTTP(S) 주소를 입력하세요. 인증 정보, 쿼리 매개변수, 프래그먼트는 사용할 수 없습니다.', + requestRateHelp: '현재 시나리오에만 적용됩니다. 무제한 속도도 동시 실행 제한을 따르며 소수 QPS를 지원합니다.', + tokenizerModeHelp: + '사용 가능한 모드는 벤치마크 이미지의 vLLM 버전에 따라 다릅니다. 작업 준비 중 토크나이저 로드를 확인합니다.', + invalidBaseUrl: '인증 정보, 쿼리, 프래그먼트가 없는 유효한 HTTP(S) URL을 입력하세요.', + invalidEndpoint: + '선택한 프로토콜에 맞고 {0}(으)로 끝나는 경로를 입력하세요. 쿼리 매개변수나 프래그먼트는 제외하세요.', + invalidTokenizer: '절대 디렉터리 경로나 저장소 ID를 입력하세요. 상대 경로, 쉼표, 줄바꿈은 지원하지 않습니다.', + invalidRequestRate: '무제한을 선택하거나 0보다 큰 유한한 수를 입력하세요. 소수도 지원합니다.', + invalidCaCert: '기본 노드에 있는 CA 인증서의 절대 파일 경로를 입력하세요. 쉼표나 줄바꿈은 사용할 수 없습니다.', + bodyOverride: '추가 본문에서 {0}을 덮어쓸 수 없습니다.', + invalidBody: '유효한 JSON 객체를 입력하세요.', + invalidConcurrencies: '동시 실행 값은 1~100개이며 각 값은 1~100000의 정수여야 합니다.', + emptyRequestCount: '동시 실행 수로 계산할 때 배수와 최소 요청 수를 모두 0으로 설정할 수 없습니다.', + requestCountLimit: '측정점별 계산된 요청 수는 1000000을 초과할 수 없습니다.', + contextExceeded: '입력·출력 토큰과 템플릿 예약량의 합이 컨텍스트 한도를 초과합니다.', + planLimit: '시나리오는 1~100개, 전체 측정점은 2000개 이하여야 합니다.', + + caCertHelp: + 'HTTPS 서비스를 검증할 CA 인증서 파일을 주 서버에서 선택하세요. 비워 두면 시스템 인증서를 사용합니다.', + extraBody: '추가 요청 본문', + entryKey: '매개변수 이름', + entryValue: '매개변수 값', + tokenizerMode: '토크나이저 모드', + requireIdle: '시작 전 서비스 유휴 상태 확인', + requireIdleHelp: + '워밍업과 부하 테스트 전에 /metrics를 한 번 확인합니다. 서비스가 사용 중이거나 유휴 상태를 확인할 수 없으면 중지합니다. 테스트 중 다른 트래픽을 차단하지는 않습니다.', + trustRemoteCode: '원격 코드 신뢰', + trustRemoteCodeHelp: + '모델 저장소의 사용자 정의 토크나이저 코드를 벤치마크 컨테이너에서 실행하도록 허용합니다. 필요하고 출처를 신뢰할 때만 켜세요.', + tokenizerModes: { auto: '자동 (권장)', slow: '느린 토크나이저', mistral: 'Mistral 전용' }, + quickDescription: '단일 요청으로 연결과 측정 과정을 확인합니다.', + regularDescription: '일상적인 성능 테스트를 위한 짧은 입력, 중간 입력, 긴 입력 부하입니다.', + fullDescription: '긴 입력과 공유 접두사를 포함하여 여러 시나리오와 동시 요청 수로 반복 측정합니다.', + customDescription: '시나리오 하나로 시작하여 매개변수를 설정하고 필요에 따라 추가합니다.', + scenarios: '시나리오', + builtIn: '기본 제공', + builtInHelp: '기본 제공 계획은 수정하거나 삭제할 수 없습니다. 테스트 생성 시 복사본을 조정하세요.', + modified: '수정됨', + + imageExists: '로컬에 있음', + imageNeedsPull: '다운로드 필요', + remark: '비고', + source: '로컬 서비스', + mode: '테스트 계획', + quick: '빠른 확인', + regular: '일반', + full: '전체', + custom: '사용자 지정', + addScenario: '시나리오 추가', + advanced: '고급 설정', + points: '측정점', + warmups: '준비 요청 수', + fixedRequests: '고정 요청 수', + multiplier: '동시 실행 수당 요청 배수', + minRequests: '최소 요청 수', + trials: '반복 횟수', + prefixRatio: '공유 접두사 비율', + totalTimeout: '전체 제한 시간 (초)', + prepareTimeout: '준비 제한 시간 (초)', + interval: '측정 간격 (초)', + context: '컨텍스트 한도 (0: 알 수 없음)', + reserve: '템플릿 예약 토큰', + storage: '저장 한도 (MiB)', + stopOnError: '오류 발생 시 후속 측정 중지', + caCert: 'CA 인증서 경로', + validTrials: '유효 / 전체 횟수', + retry: '선택한 측정점 재시도', + environment: '실행 환경', + plan: '고정 설정', + clientHelp: + '클라이언트 컨테이너는 주 노드에서 기존 서비스에 요청을 보냅니다. 추론 서비스를 시작하거나 GPU를 할당하지 않습니다.', + retryHelp: '선택한 비정상 측정점만 같은 매개변수와 새 시드로 재시도합니다.', + secretHelp: '복사본에는 API 키와 헤더가 없습니다. 필요한 경우 다시 입력하세요.', + resultHelp: + '요청 이상이 없는 성공한 실행만 중앙값과 최솟값/최댓값에 포함합니다. P99는 각 실행 P99의 중앙값입니다. 캐시와 외부 트래픽은 통제되지 않습니다.', + }, + benchmarkOverview: { + noResults: '유효한 테스트 결과가 없습니다. 실패 원인과 로그를 확인하세요.', + noGroupResults: '이 조합에 유효한 결과가 없습니다. 시나리오 또는 동시 실행 수를 변경하세요.', + partial: '부분 결과: 테스트가 완전히 성공하지 않았습니다. 유효한 측정점만 반영합니다.', + highlights: '주요 지표', + aggregate: '현재 조합의 유효한 실행 중앙값입니다. 지표를 클릭하면 상세 통계를 볼 수 있습니다.', + trend: '동시 실행 수별 추세', + std: '표준 편차', + min: '최솟값', + max: '최댓값', + tpot: '출력 토큰당 시간', + tpotHelp: '첫 토큰 이후 출력 토큰 하나를 생성하는 평균 시간입니다.', + itl: '토큰 간 지연', + itlHelp: '스트리밍 응답에서 연속 토큰 사이의 시간입니다.', + e2el: '종단 간 지연', + e2elHelp: '요청을 전송한 시점부터 전체 응답 수신 완료까지의 시간입니다.', + requestHelp: '초당 완료된 요청 수입니다.', + usageHelp: + '현재 조합의 유효한 실행 중앙값이며 전체 테스트의 요청 합계가 아닙니다. 비정상 실행은 측정점 탭에서 확인하세요.', + duration: '실행 시간', + throughput: '처리량', + latency: '지연', + usage: '요청 및 사용량(유효한 실행)', + }, + benchmarkTokenizer: { + title: '토크나이저 관리', + local: '로컬 디렉터리 등록', + upload: '토크나이저 패키지 업로드', + uploadHelp: + '모델 가중치가 없는 ZIP / tar.gz 파일을 업로드하세요. 압축 파일은 128 MiB, 압축 해제 후에는 256 MiB까지 가능합니다.', + source: '가져오기 방식', + deleteLocal: '토크나이저 “{0}”의 등록을 삭제할까요? 원본 디렉터리와 파일은 유지됩니다.', + deleteUpload: '토크나이저 “{0}” 및 업로드한 파일을 삭제할까요? 기존 테스트 보고서는 유지됩니다.', + select: '토크나이저 선택', + selectHelp: + '오프라인 환경에서는 관리 목록에서 선택하세요. 사용자 지정 입력은 로컬 디렉터리나 저장소 이름도 지원합니다.', + }, container: { createByCommand: '명령으로 생성', importContainerBackupTip: '컨테이너 백업 파일 가져오기, .tar.gz 형식만 지원합니다', diff --git a/frontend/src/lang/modules/lo.ts b/frontend/src/lang/modules/lo.ts index 366670db2..0ddf09887 100644 --- a/frontend/src/lang/modules/lo.ts +++ b/frontend/src/lang/modules/lo.ts @@ -1461,36 +1461,32 @@ const message = { statusWaiting: 'ກຳລັງລໍຖ້າ', base: 'ຂໍ້ມູນພື້ນຖານ', backend: 'Backend', - baseUrl: 'Base URL', endpoint: 'Endpoint', tokenizer: 'Tokenizer', - tokenizerPlaceholder: - 'ເລືອກ ຫຼື ປ້ອນໂຟນເດີ tokenizer ພາຍໃນເຄື່ອງ, ເຊັ່ນ: /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: 'ປ້ອນເສັ້ນທາງໂຟນເດີແບບສົມບູນໃນໂນດຫຼັກ ຫຼື ID ຄັງ Hugging Face', runConfig: 'ການກຳນົດຄ່າການລັນ', rawResult: 'ຜົນລັບດິບ (Raw Result)', resultMetrics: 'ຕົວຊີ້ວັດຜົນລັບ', contextTokens: 'ຄວາມຍາວ Context', - contextTokensHelper: 'ຂີດຈຳກັດ input token ບວກກັບ output token ສຳລັບການທົດສອບນີ້.', outputThroughput: 'ອັດຕາການສົ່ງອອກ', outputThroughputHelper: 'ຈຳນວນ output tokens ທີ່ສ້າງໄດ້ຕໍ່ວິນາທີ. ຍິ່ງສູງຍິ່ງໄວ.', totalThroughput: 'ອັດຕາການປະມວນຜົນລວມ', totalThroughputHelper: 'ຈຳນວນ input ແລະ output tokens ທີ່ປະມວນຜົນຕໍ່ວິນາທີ. ໃຊ້ວັດແທກຄວາມສາມາດໂດຍລວມ.', firstTokenLatency: 'ຄວາມໜ່ວງຂອງ Token ທຳອິດ', firstTokenLatencyHelper: 'ເວລາຕັ້ງແຕ່ສົ່ງຄຳຂໍຈົນເຖິງການໄດ້ຮັບ token ທຳອິດ. ຍິ່ງຕ່ຳຍິ່ງຕອບສະໜອງໄວ.', - tokenValueHelper: 'ປ້ອນຕົວເລກຈຳນວນເຕັມ ຫຼື ຄ່າ k, ເຊັ່ນ: 512, 1k, 32k', numPrompts: 'ຈຳນວນ Prompt', concurrency: 'ການເຮັດວຽກພ້ອມກັນ', requestRate: 'ອັດຕາຄຳຂໍ', requestRateUnlimited: 'ບໍ່ຈຳກັດ (max throughput)', - requestRateCustom: 'ກຳນົດ QPS ເອງ', requestRateCustomPlaceholder: 'ຄຳຂໍຕໍ່ວິນາທີ, ເຊັ່ນ: 2.5', successfulRequests: 'ຄຳຂໍທີ່ສຳເລັດ', requestThroughput: 'ອັດຕາຄຳຮ້ອງຂໍ', mean: 'ຄ່າສະເລ່ຍ', median: 'ຄ່າມັດທະຍະຖານ', - timeout: 'ໝົດເວລາ (ວິນາທີ)', image: 'vLLM Image', - ignoreEos: 'ລະເວັ້ນ EOS', + ignoreEos: 'ລະເວັ້ນໂທເຄັນສິ້ນສຸດ (EOS)', + ignoreEosHelp: + 'ປ້ອງກັນການຢຸດກ່ອນກຳນົດຍ້ອນ EOS ເພື່ອທົດສອບຄວາມຍາວຜົນລັບທີ່ຕັ້ງໄວ້. ເງື່ອນໄຂຢຸດອື່ນຍັງມີຜົນ ແລະຕ້ອງມີການຮອງຮັບຈາກເຊີບເວີ.', extraHeaders: 'Headers ເພີ່ມເຕີມ', }, vllmMonitor: { @@ -1695,6 +1691,147 @@ const message = { modelType: 'ປະເພດໂມເດວ', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'ເວລາຈຳກັດການກຽມການ ບໍ່ນັບໃນເວລາທັງຮອບ.', + pointTimeoutHelp: 'ຈັບເວລາແຍກຕໍ່ຈຸດ ລວມການເລີ່ມ, ອຸ່ນເຄື່ອງ ແລະ ທຸກຄຳຮ້ອງຂໍ; ຈຳກັດດ້ວຍເວລາທັງຮອບທີ່ເຫຼືອ.', + totalTimeoutHelp: 'ເລີ່ມຫຼັງກຽມການ ລວມທຸກຈຸດແລະໄລຍະຫ່າງ. ຢຸດທົດສອບເມື່ອໝົດເວລາ.', + concurrencyLevels: 'ລະດັບການເຮັດວຽກພ້ອມກັນ', + concurrencyHelp: 'ທົດສອບແຕ່ລະລະດັບຕາມລຳດັບ. ແຕ່ລະຄ່າກຳນົດຈຳນວນຄຳຮ້ອງຂໍສູງສຸດທີ່ດຳເນີນພ້ອມກັນ.', + requestCountMode: 'ຕັ້ງຄ່າຈຳນວນຄຳຮ້ອງຂໍ', + fixedRequestMode: 'ຈຳນວນຄົງທີ່ຕໍ່ລະດັບ', + scaledRequestMode: 'ຄຳນວນຕາມຈຳນວນທີ່ເຮັດວຽກພ້ອມກັນ', + requestsPerPoint: 'ຄຳຮ້ອງຂໍຕໍ່ລະດັບ', + requestCountFormula: + 'ຕໍ່ລະດັບ: ຄ່າຄົງທີ່ ຫຼື max(ຈຳນວນພ້ອມກັນ × ຕົວຄູນ, ຄຳຮ້ອງຂໍຂັ້ນຕ່ຳ). ລວມຕໍ່ສະຖານະການ: ຜົນລວມທຸກລະດັບ × ຈຳນວນຮອບຊ້ຳ, ບໍ່ລວມອຸ່ນເຄື່ອງ.', + controlLog: 'ບັນທຶກການກະກຽມ ແລະ ຄວບຄຸມ', + executionLog: 'ບັນທຶກການດຳເນີນງານ', + pointLog: 'ຈຸດທົດສອບ #{0} · {1} · ບັນທຶກການດຳເນີນງານ', + archivedLog: '{0} (ປະຫວັດ {1})', + tokenLengths: 'ໂທເຄັນຂາເຂົ້າ / ຂາອອກ', + kind: 'ໝວດໝູ່ຜົນລັບ', + kindServe: 'serve (ການທົດສອບທົ່ວໄປ)', + kindPD: 'pd (ການວັດແທກ Prefill/Decode)', + saveDetailed: 'ບັນທຶກລາຍລະອຽດຄຳຮ້ອງ', + saveDetailedHelp: + 'ບັນທຶກຄວາມຍາວ, ຄວາມລ່າຊ້າ, ຂໍ້ຄວາມທີ່ສ້າງ ແລະຂໍ້ຜິດພາດຂອງແຕ່ລະຄຳຮ້ອງ. ເມື່ອປິດ ຍັງຮັກສາຄ່າສະຫຼຸບໄວ້ ແລະຫຼຸດຂະໜາດໄຟລ໌ຜົນລັບ.', + parameters: 'ພາລາມິເຕີ', + temperatureHelp: 'ຄວບຄຸມຄວາມສຸ່ມຂອງຜົນລັບ. ຄ່າ 0 ມັກໃຫ້ຜົນລັບທີ່ຄົງທີ່ກວ່າ; ຄ່າສູງຂຶ້ນຈະເພີ່ມຄວາມສຸ່ມ.', + pointTimeout: 'ເວລາຈຳກັດຕໍ່ຈຸດ (ວິນາທີ)', + temperature: 'ອຸນຫະພູມການສຸ່ມ', + requestUrl: 'ທີ່ຢູ່ API', + invalidRequestUrl: + 'ປ້ອນທີ່ຢູ່ HTTP(S) ເຕັມທີ່ລົງທ້າຍດ້ວຍ /chat/completions ຫຼື /completions ໂດຍບໍ່ມີຂໍ້ມູນເຂົ້າລະບົບ, ພາລາມິເຕີສອບຖາມ ຫຼື ສ່ວນຫຼັງ #.', + requestRateHelp: + 'ໃຊ້ກັບສະຖານະການນີ້ເທົ່ານັ້ນ. ອັດຕາບໍ່ຈຳກັດຍັງຢູ່ພາຍໃຕ້ຂີດຈຳກັດພ້ອມກັນ; ຮອງຮັບ QPS ທົດສະນິຍົມ.', + tokenizerModeHelp: + 'ໂໝດທີ່ໃຊ້ໄດ້ຂຶ້ນກັບເວີຊັນ vLLM ໃນອິມເມຈທົດສອບ. ການໂຫຼດຕົວແຍກໂທເຄັນຈະຖືກກວດສອບໃນຂັ້ນຕອນກະກຽມວຽກ.', + invalidBaseUrl: 'ປ້ອນ URL HTTP(S) ທີ່ຖືກຕ້ອງ ໂດຍບໍ່ມີຂໍ້ມູນເຂົ້າລະບົບ, ຄຳຖາມ ຫຼືສ່ວນຍ່ອຍ.', + invalidEndpoint: + 'ປ້ອນເສັ້ນທາງທີ່ກົງກັບໂປຣໂຕຄໍທີ່ເລືອກ ແລະລົງທ້າຍດ້ວຍ {0} ໂດຍບໍ່ມີພາລາມິເຕີຄຳຖາມ ຫຼືສ່ວນຍ່ອຍຂອງ URL.', + invalidTokenizer: 'ໃຊ້ເສັ້ນທາງໂຟນເດີແບບເຕັມ ຫຼື ID ຄັງເກັບ; ບໍ່ຮອງຮັບເສັ້ນທາງສຳພັນ, ຈຸດຈ້ຳ ຫຼືຂຶ້ນແຖວໃໝ່.', + invalidRequestRate: 'ເລືອກບໍ່ຈຳກັດ ຫຼືປ້ອນຈຳນວນຈຳກັດທີ່ໃຫຍ່ກວ່າ 0; ຮອງຮັບທົດສະນິຍົມ.', + invalidCaCert: 'ປ້ອນເສັ້ນທາງເຕັມຂອງໄຟລ໌ CA ໃນໂນດຫຼັກ ໂດຍບໍ່ມີຈຸດຈ້ຳ ຫຼືຂຶ້ນແຖວໃໝ່.', + bodyOverride: 'ເນື້ອຫາເພີ່ມບໍ່ສາມາດຂຽນທັບ {0}.', + invalidBody: 'ປ້ອນວັດຖຸ JSON ທີ່ຖືກຕ້ອງ.', + invalidConcurrencies: 'ປ້ອນຄ່າພ້ອມກັນ 1–100 ລາຍການ, ແຕ່ລະຄ່າເປັນຈຳນວນເຕັມ 1–100000.', + emptyRequestCount: 'ເມື່ອຄຳນວນຕາມຈຳນວນທີ່ເຮັດວຽກພ້ອມກັນ, ຕົວຄູນແລະຈຳນວນຄຳຮ້ອງຂໍຂັ້ນຕ່ຳບໍ່ສາມາດເປັນ 0 ພ້ອມກັນ.', + requestCountLimit: 'ຄຳຮ້ອງຂໍທີ່ຄຳນວນຕໍ່ຈຸດຕ້ອງບໍ່ເກີນ 1000000.', + contextExceeded: 'ຜົນລວມໂທເຄັນຂາເຂົ້າ, ຂາອອກ ແລະສຳຮອງແມ່ແບບເກີນຂີດຈຳກັດບໍລິບົດ.', + planLimit: 'ຕ້ອງມີ 1–100 ສະຖານະການ ແລະລວມບໍ່ເກີນ 2000 ຈຸດ.', + + caCertHelp: 'ເລືອກໄຟລ໌ໃບຢັ້ງຢືນ CA ໃນເຊີບເວີຫຼັກເພື່ອກວດສອບ HTTPS. ປະວ່າງເພື່ອໃຊ້ໃບຢັ້ງຢືນຂອງລະບົບ.', + extraBody: 'ເນື້ອຫາຄຳຮ້ອງຂໍເພີ່ມເຕີມ', + entryKey: 'ຊື່ພາຣາມິເຕີ', + entryValue: 'ຄ່າພາຣາມິເຕີ', + tokenizerMode: 'ໂໝດຕົວແບ່ງໂທເຄັນ', + requireIdle: 'ກວດສອບວ່າບໍລິການວ່າງກ່ອນເລີ່ມ', + requireIdleHelp: + 'ກວດສອບ /metrics ໜຶ່ງຄັ້ງກ່ອນອຸ່ນເຄື່ອງ ແລະ ທົດສອບໂຫຼດ. ຢຸດຖ້າບໍລິການບໍ່ວ່າງ ຫຼື ບໍ່ສາມາດຢືນຢັນໄດ້ວ່າວ່າງ. ການກວດສອບນີ້ບໍ່ປ້ອງກັນການຮ້ອງຂໍອື່ນໃນລະຫວ່າງທົດສອບ.', + trustRemoteCode: 'ເຊື່ອຖືລະຫັດທາງໄກ', + trustRemoteCodeHelp: + 'ອະນຸຍາດໃຫ້ແລ່ນລະຫັດຕົວແບ່ງໂທເຄັນທີ່ກຳນົດເອງຈາກຄັງໂມເດວໃນຄອນເທນເນີທົດສອບ. ເປີດເມື່ອຈຳເປັນແລະແຫຼ່ງທີ່ມາເຊື່ອຖືໄດ້ເທົ່ານັ້ນ.', + tokenizerModes: { auto: 'ອັດຕະໂນມັດ (ແນະນຳ)', slow: 'ຕົວແບ່ງໂທເຄັນແບບຊ້າ', mistral: 'ຕົວແບ່ງໂທເຄັນ Mistral' }, + quickDescription: 'ກວດສອບການເຊື່ອມຕໍ່ແລະການວັດແທກດ້ວຍຄຳຮ້ອງຂໍດຽວ.', + regularDescription: 'ພາລະງານສັ້ນ, ປານກາງ ແລະຍາວ ສຳລັບທົດສອບປະສິດທິພາບປະຈຳວັນ.', + fullDescription: + 'ຫຼາຍສະຖານະການ, ຫຼາຍລະດັບຄຳຮ້ອງຂໍພ້ອມກັນ ແລະການວັດແທກຊ້ຳ ລວມທັງຂໍ້ມູນເຂົ້າຍາວແລະຄຳນຳໜ້າຮ່ວມກັນ.', + customDescription: 'ເລີ່ມຈາກໜຶ່ງສະຖານະການ, ຕັ້ງຄ່າພາລາມິເຕີ ແລະເພີ່ມຕາມຄວາມຕ້ອງການ.', + scenarios: 'ສະຖານະການ', + builtIn: 'ມາພ້ອມລະບົບ', + builtInHelp: 'ແຜນທີ່ມາພ້ອມລະບົບແກ້ໄຂຫຼືລຶບບໍ່ໄດ້. ປັບສຳເນົາໃນເວລາສ້າງການທົດສອບ.', + modified: 'ປັບແລ້ວ', + + imageExists: 'ມີຢູ່ໃນເຄື່ອງແລ້ວ', + imageNeedsPull: 'ຕ້ອງດາວໂຫຼດ', + remark: 'ໝາຍເຫດ', + source: 'ບໍລິການພາຍໃນເຄື່ອງ', + mode: 'ແຜນທົດສອບ', + quick: 'ກວດສອບດ່ວນ', + regular: 'ປົກກະຕິ', + full: 'ເຕັມຮູບແບບ', + custom: 'ກຳນົດເອງ', + addScenario: 'ເພີ່ມສະຖານະການ', + advanced: 'ການຕັ້ງຄ່າຂັ້ນສູງ', + points: 'ຈຸດວັດແທກ', + warmups: 'ຄຳຮ້ອງຂໍອຸ່ນເຄື່ອງ', + fixedRequests: 'ຄຳຮ້ອງຂໍຄົງທີ່', + multiplier: 'ຕົວຄູນຄຳຮ້ອງຂໍຕໍ່ການເຮັດວຽກພ້ອມກັນ', + minRequests: 'ຄຳຮ້ອງຂໍຕ່ຳສຸດ', + trials: 'ຈຳນວນຊ້ຳ', + prefixRatio: 'ອັດຕາສ່ວນຄຳນຳໜ້າຮ່ວມ', + totalTimeout: 'ເວລາຈຳກັດຮອບ (ວິນາທີ)', + prepareTimeout: 'ເວລາຈຳກັດກະກຽມ (ວິນາທີ)', + interval: 'ໄລຍະຫ່າງຈຸດ (ວິນາທີ)', + context: 'ຂີດຈຳກັດບໍລິບົດ (0: ບໍ່ຮູ້)', + reserve: 'ໂທເຄນສຳຮອງແມ່ແບບ', + storage: 'ຂີດຈຳກັດບ່ອນເກັບ (MiB)', + stopOnError: 'ຢຸດຈຸດຕໍ່ໄປເມື່ອຜິດພາດ', + caCert: 'ເສັ້ນທາງໃບຢັ້ງຢືນ CA', + validTrials: 'ຖືກຕ້ອງ / ທັງໝົດ', + retry: 'ທົດສອບຈຸດທີ່ເລືອກຄືນ', + environment: 'ສະພາບແວດລ້ອມ', + plan: 'ການຕັ້ງຄ່າຄົງທີ່', + clientHelp: + 'ຄອນເທນເນີລູກຂ່າຍເຮັດວຽກຢູ່ໂນດຫຼັກ ແລະ ສົ່ງຄຳຮ້ອງຂໍໄປບໍລິການທີ່ມີແລ້ວ. ບໍ່ເລີ່ມບໍລິການອະນຸມານ ແລະ ບໍ່ຕ້ອງການ GPU.', + retryHelp: 'ທົດສອບຄືນສະເພາະຈຸດຜິດປົກກະຕິທີ່ເລືອກ ດ້ວຍພາລາມິເຕີເດີມ ແລະ ຄ່າສຸ່ມໃໝ່.', + secretHelp: 'ສຳເນົາບໍ່ມີລະຫັດ API ແລະ ສ່ວນຫົວ. ກະລຸນາປ້ອນໃໝ່ຖ້າຈຳເປັນ.', + resultHelp: + 'ຄ່າກາງ ແລະ ຄ່າຕ່ຳສຸດ/ສູງສຸດໃຊ້ສະເພາະການທົດສອບສຳເລັດທີ່ບໍ່ມີຄຳຮ້ອງຂໍຜິດປົກກະຕິ. P99 ແມ່ນຄ່າກາງຂອງ P99 ແຕ່ລະຄັ້ງ. ແຄຊ ແລະ ການຈະລາຈອນພາຍນອກບໍ່ໄດ້ຄວບຄຸມ.', + }, + benchmarkOverview: { + noResults: 'ບໍ່ມີຜົນການທົດສອບທີ່ໃຊ້ໄດ້. ກວດສອບສາເຫດ ແລະ ບັນທຶກ.', + noGroupResults: 'ບໍ່ມີຜົນທີ່ໃຊ້ໄດ້ສຳລັບຊຸດນີ້. ເລືອກສະຖານະການ ຫຼື ຈຳນວນພ້ອມກັນອື່ນ.', + partial: 'ຜົນບາງສ່ວນ: ການທົດສອບບໍ່ສຳເລັດທັງໝົດ. ຕົວຊີ້ວັດລວມສະເພາະຈຸດທີ່ໃຊ້ໄດ້.', + highlights: 'ຕົວຊີ້ວັດຫຼັກ', + aggregate: 'ຄ່າມັດທະຍະຖານຂອງການແລ່ນທີ່ໃຊ້ໄດ້ໃນຊຸດນີ້. ຄລິກຕົວຊີ້ວັດເພື່ອເບິ່ງລາຍລະອຽດ.', + trend: 'ແນວໂນ້ມຕາມຈຳນວນພ້ອມກັນ', + std: 'ສ່ວນບ່ຽງເບນມາດຕະຖານ', + min: 'ຕ່ຳສຸດ', + max: 'ສູງສຸດ', + tpot: 'ເວລາຕໍ່ Token ຂາອອກ', + tpotHelp: 'ເວລາສ້າງສະເລ່ຍຕໍ່ Token ຂາອອກຫຼັງ Token ທຳອິດ.', + itl: 'ຄວາມຊັກຊ້າລະຫວ່າງ Token', + itlHelp: 'ເວລາລະຫວ່າງ Token ຕໍ່ເນື່ອງໃນຄຳຕອບແບບສະຕຣີມ.', + e2el: 'ຄວາມຊັກຊ້າຕັ້ງແຕ່ຕົ້ນຈົນຈົບ', + e2elHelp: 'ເວລາຈາກການສົ່ງຄຳຂໍຈົນໄດ້ຮັບຄຳຕອບຄົບຖ້ວນ.', + requestHelp: 'ຈຳນວນຄຳຂໍທີ່ສຳເລັດຕໍ່ວິນາທີ.', + usageHelp: 'ຄ່າມັດທະຍະຖານຂອງການແລ່ນທີ່ໃຊ້ໄດ້ໃນຊຸດນີ້ ບໍ່ແມ່ນຈຳນວນຄຳຂໍທັງໝົດ. ເບິ່ງການແລ່ນຜິດປົກກະຕິໃນແຖບຈຸດ.', + duration: 'ໄລຍະເວລາການແລ່ນ', + throughput: 'ອັດຕາປະມວນຜົນ', + latency: 'ຄວາມຊັກຊ້າ', + usage: 'ຄຳຂໍ ແລະ ການໃຊ້ງານ (ການແລ່ນທີ່ໃຊ້ໄດ້)', + }, + benchmarkTokenizer: { + title: 'ຈັດການຕົວແຍກໂທເຄັນ', + local: 'ລົງທະບຽນໂຟນເດີໃນເຄື່ອງ', + upload: 'ອັບໂຫຼດຊຸດຕົວແຍກໂທເຄັນ', + uploadHelp: 'ອັບໂຫຼດ ZIP / tar.gz ທີ່ບໍ່ມີນ້ຳໜັກໂມເດລ. ສູງສຸດ 128 MiB ກ່ອນແຕກ ແລະ 256 MiB ຫຼັງແຕກ.', + source: 'ວິທີນຳເຂົ້າ', + deleteLocal: 'ລຶບການລົງທະບຽນ «{0}» ບໍ? ໂຟນເດີ ແລະ ໄຟລ໌ຕົ້ນສະບັບຈະຖືກເກັບໄວ້.', + deleteUpload: 'ລຶບ «{0}» ແລະ ໄຟລ໌ທີ່ອັບໂຫຼດບໍ? ລາຍງານທົດສອບເກົ່າຈະຖືກເກັບໄວ້.', + select: 'ເລືອກຕົວແບ່ງໂທເຄັນ', + selectHelp: 'ສຳລັບອອບລາຍ ໃຫ້ເລືອກຈາກລາຍການ. ການປ້ອນເອງຮອງຮັບໂຟນເດີ ຫຼື ຊື່ຄັງ.', + }, container: { createByCommand: 'ສ້າງດ້ວຍຄຳສັ່ງ', importContainerBackupTip: 'ນຳເຂົ້າໄຟລ໌ສຳຮອງຄອນເທນເນີ, ຮອງຮັບສະເພາະ .tar.gz', diff --git a/frontend/src/lang/modules/ms.ts b/frontend/src/lang/modules/ms.ts index 721efa23d..8a1c9fcff 100644 --- a/frontend/src/lang/modules/ms.ts +++ b/frontend/src/lang/modules/ms.ts @@ -1506,16 +1506,13 @@ const message = { 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', + tokenizerPlaceholder: 'Masukkan laluan direktori mutlak pada nod utama atau ID repositori Hugging Face', 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', @@ -1524,20 +1521,19 @@ const message = { firstTokenLatency: 'Latensi Token Pertama', firstTokenLatencyHelper: 'Masa dari menghantar permintaan hingga menerima token pertama. Lebih rendah bermaksud respons lebih pantas.', - tokenValueHelper: 'Masukkan integer positif atau nilai k, cth. 512, 1k, 32k', numPrompts: 'Prompt', concurrency: 'Keserentakan', mean: 'Min', median: 'Median', requestRate: 'Kadar Permintaan', requestRateUnlimited: 'Tanpa had (throughput maksimum)', - requestRateCustom: 'QPS tersuai', requestRateCustomPlaceholder: 'Permintaan sesaat, cth. 2.5', successfulRequests: 'Permintaan berjaya', requestThroughput: 'Throughput Permintaan', - timeout: 'Tamat Masa (saat)', image: 'Imej vLLM', - ignoreEos: 'Abaikan EOS', + ignoreEos: 'Abaikan token akhir jujukan (EOS)', + ignoreEosHelp: + 'Mengelakkan penghentian awal akibat EOS untuk menguji panjang output yang ditetapkan. Syarat henti lain masih terpakai; sokongan pelayan diperlukan.', extraHeaders: 'Pengepala Tambahan', }, vllmMonitor: { @@ -1751,6 +1747,157 @@ const message = { modelType: 'Jenis model', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Had masa persediaan, tidak termasuk had masa keseluruhan.', + pointTimeoutHelp: + 'Pemasa berasingan setiap titik, termasuk permulaan, pemanasan dan semua permintaan; dihadkan oleh baki masa keseluruhan.', + totalTimeoutHelp: + 'Bermula selepas persediaan, meliputi semua titik dan sela. Ujian berhenti apabila tamat masa.', + concurrencyLevels: 'Tahap keserentakan', + concurrencyHelp: + 'Tahap diuji mengikut urutan. Setiap nilai mengehadkan bilangan permintaan yang berjalan serentak.', + requestCountMode: 'Tetapan bilangan permintaan', + fixedRequestMode: 'Permintaan tetap setiap tahap', + scaledRequestMode: 'Kira mengikut keserentakan', + requestsPerPoint: 'Permintaan setiap tahap', + requestCountFormula: + 'Setiap tahap: nilai tetap atau max(keserentakan × pengganda, permintaan minimum). Jumlah senario: jumlah semua tahap × ulangan, tidak termasuk pemanasan.', + controlLog: 'Log persediaan dan kawalan', + executionLog: 'Log pelaksanaan', + pointLog: 'Titik #{0} · {1} · Log pelaksanaan', + archivedLog: '{0} (arkib {1})', + tokenLengths: 'Token input / output', + kind: 'Kategori hasil', + kindServe: 'serve (ujian biasa)', + kindPD: 'pd (pengukuran Prefill/Decode)', + saveDetailed: 'Simpan butiran permintaan', + saveDetailedHelp: + 'Simpan panjang, kependaman, teks yang dijana dan ralat bagi setiap permintaan. Metrik ringkasan dikekalkan apabila dimatikan, sekali gus mengurangkan saiz fail hasil.', + parameters: 'Parameter', + temperatureHelp: + 'Mengawal kerawakan output. Sifar biasanya memberikan output yang lebih stabil; nilai lebih tinggi meningkatkan kerawakan.', + pointTimeout: 'Had masa setiap titik (saat)', + temperature: 'Suhu pensampelan', + requestUrl: 'URL API', + invalidRequestUrl: + 'Masukkan URL HTTP(S) penuh yang berakhir dengan /chat/completions atau /completions, tanpa kelayakan log masuk, parameter pertanyaan atau fragmen.', + requestRateHelp: + 'Terpakai hanya pada senario ini. Kadar tanpa had masih mematuhi had keserentakan; QPS perpuluhan disokong.', + tokenizerModeHelp: + 'Mod yang tersedia bergantung pada versi vLLM dalam imej penanda aras. Pemuatan pentoken disemak semasa penyediaan tugas.', + invalidBaseUrl: 'Masukkan URL HTTP(S) yang sah tanpa kelayakan, pertanyaan atau fragmen.', + invalidEndpoint: + 'Masukkan laluan yang sepadan dengan protokol dipilih dan berakhir dengan {0}, tanpa parameter pertanyaan atau fragmen.', + invalidTokenizer: + 'Gunakan direktori mutlak atau ID repositori; laluan relatif, koma dan baris baharu tidak disokong.', + invalidRequestRate: + 'Pilih tanpa had atau masukkan nombor terhingga lebih besar daripada 0; perpuluhan disokong.', + invalidCaCert: 'Masukkan laluan mutlak sijil CA pada nod utama tanpa koma atau baris baharu.', + bodyOverride: 'Badan tambahan tidak boleh menimpa {0}.', + invalidBody: 'Masukkan objek JSON yang sah.', + invalidConcurrencies: 'Berikan 1–100 nilai serentak, setiap satu integer antara 1 dan 100000.', + emptyRequestCount: + 'Apabila mengira mengikut keserentakan, pengganda dan permintaan minimum tidak boleh kedua-duanya 0.', + requestCountLimit: 'Permintaan yang dikira bagi setiap titik tidak boleh melebihi 1000000.', + contextExceeded: 'Jumlah token input, output dan rizab templat melebihi had konteks.', + planLimit: 'Berikan 1–100 senario dengan tidak lebih daripada 2000 titik.', + + caCertHelp: + 'Pilih sijil CA pada pelayan utama untuk mengesahkan perkhidmatan HTTPS. Biarkan kosong untuk menggunakan sijil sistem.', + extraBody: 'Badan permintaan tambahan', + entryKey: 'Nama parameter', + entryValue: 'Nilai parameter', + tokenizerMode: 'Mod pentoken', + requireIdle: 'Semak sama ada perkhidmatan melahu sebelum bermula', + requireIdleHelp: + 'Menyemak /metrics sekali sebelum pemanasan dan ujian beban. Berhenti jika perkhidmatan sibuk atau keadaan melahu tidak dapat disahkan. Ini tidak menghalang trafik lain semasa ujian.', + trustRemoteCode: 'Percayai kod jauh', + trustRemoteCodeHelp: + 'Membenarkan kod pentoken tersuai daripada repositori model dijalankan dalam bekas penanda aras. Aktifkan hanya jika diperlukan dan sumber dipercayai.', + tokenizerModes: { auto: 'Automatik (disyorkan)', slow: 'Pentoken perlahan', mistral: 'Pentoken Mistral' }, + quickDescription: 'Sahkan sambungan dan pengukuran dengan satu permintaan.', + regularDescription: 'Beban pendek, sederhana dan panjang untuk ujian prestasi rutin.', + fullDescription: + 'Pelbagai senario, tahap keserentakan dan ulangan, termasuk input panjang dan awalan dikongsi.', + customDescription: 'Mulakan dengan satu senario, tetapkan parameternya dan tambah lagi mengikut keperluan.', + scenarios: 'Senario', + builtIn: 'Terbina dalam', + builtInHelp: 'Pelan terbina dalam tidak boleh disunting atau dipadam. Laraskan salinan semasa mencipta ujian.', + modified: 'Diubah suai', + + imageExists: 'Tersedia secara setempat', + imageNeedsPull: 'Perlu dimuat turun', + remark: 'Catatan', + source: 'Perkhidmatan setempat', + mode: 'Pelan ujian', + quick: 'Semakan pantas', + regular: 'Biasa', + full: 'Penuh', + custom: 'Tersuai', + addScenario: 'Tambah senario', + advanced: 'Tetapan lanjutan', + points: 'Titik', + warmups: 'Permintaan pemanasan', + fixedRequests: 'Permintaan tetap', + multiplier: 'Permintaan bagi keserentakan', + minRequests: 'Permintaan minimum', + trials: 'Ulangan', + prefixRatio: 'Nisbah awalan dikongsi', + totalTimeout: 'Had masa pusingan (s)', + prepareTimeout: 'Had masa persediaan (s)', + interval: 'Sela titik (s)', + context: 'Had konteks (0: tidak diketahui)', + reserve: 'Token simpanan templat', + storage: 'Had storan (MiB)', + stopOnError: 'Hentikan titik seterusnya jika ralat', + caCert: 'Laluan sijil CA', + validTrials: 'Sah / jumlah ulangan', + retry: 'Ulang titik terpilih', + environment: 'Persekitaran', + plan: 'Konfigurasi dibekukan', + clientHelp: + 'Kontena klien berjalan pada nod utama dan menghantar permintaan kepada perkhidmatan sedia ada. Ia tidak memulakan inferens atau memerlukan GPU.', + retryHelp: 'Hanya titik bermasalah yang dipilih diulang, dengan parameter sama dan benih baharu.', + secretHelp: 'Salinan tidak mengandungi kunci API atau pengepala. Masukkan semula jika perlu.', + resultHelp: + 'Median dan minimum/maksimum hanya melibatkan ujian berjaya tanpa anomali permintaan. P99 ialah median P99 setiap ujian. Cache dan trafik luaran tidak dikawal.', + }, + benchmarkOverview: { + noResults: 'Tiada keputusan ujian yang sah. Semak sebab kegagalan dan log.', + noGroupResults: 'Tiada keputusan sah untuk gabungan ini. Pilih senario atau keserentakan lain.', + partial: 'Keputusan separa: ujian tidak berjaya sepenuhnya. Metrik hanya merangkumi titik yang sah.', + highlights: 'Metrik utama', + aggregate: 'Median pelaksanaan sah bagi gabungan ini. Klik metrik untuk butiran.', + trend: 'Trend keserentakan', + std: 'Sisihan piawai', + min: 'Minimum', + max: 'Maksimum', + tpot: 'Masa setiap token output', + tpotHelp: 'Purata masa penjanaan setiap token output selepas token pertama.', + itl: 'Kependaman antara token', + itlHelp: 'Masa antara token berturutan dalam respons penstriman.', + e2el: 'Kependaman hujung ke hujung', + e2elHelp: 'Masa dari penghantaran permintaan hingga penerimaan respons lengkap.', + requestHelp: 'Bilangan permintaan yang selesai setiap saat.', + usageHelp: + 'Median pelaksanaan sah bagi gabungan ini, bukan jumlah permintaan keseluruhan ujian. Lihat pelaksanaan tidak normal dalam tab titik.', + duration: 'Tempoh pelaksanaan', + throughput: 'Daya pemprosesan', + latency: 'Kependaman', + usage: 'Permintaan dan penggunaan (pelaksanaan sah)', + }, + benchmarkTokenizer: { + title: 'Pengurusan tokenizer', + local: 'Daftar direktori setempat', + upload: 'Muat naik pakej tokenizer', + uploadHelp: 'Muat naik ZIP / tar.gz tanpa pemberat model. Had: 128 MiB dimampatkan, 256 MiB selepas diekstrak.', + source: 'Kaedah import', + deleteLocal: 'Alih keluar pendaftaran tokenizer “{0}”? Direktori dan fail asal akan dikekalkan.', + deleteUpload: 'Padam tokenizer “{0}” serta fail yang dimuat naik? Laporan ujian terdahulu akan dikekalkan.', + select: 'Pilih tokenizer', + selectHelp: + 'Untuk ujian luar talian, pilih tokenizer terurus. Input tersuai menerima direktori setempat atau nama repositori.', + }, container: { createByCommand: 'Cipta melalui perintah', importContainerBackupTip: 'Import fail sandaran kontena, hanya format .tar.gz disokong', diff --git a/frontend/src/lang/modules/pt-br.ts b/frontend/src/lang/modules/pt-br.ts index bec9e5e99..623a9078d 100644 --- a/frontend/src/lang/modules/pt-br.ts +++ b/frontend/src/lang/modules/pt-br.ts @@ -1502,16 +1502,14 @@ const message = { 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', + 'Insira um diretório absoluto no nó principal ou um ID de repositório do Hugging Face', 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', @@ -1520,20 +1518,19 @@ const message = { 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.', - tokenValueHelper: 'Informe um inteiro positivo ou valor com k, ex.: 512, 1k, 32k', numPrompts: 'Prompts', concurrency: 'Concorrência', mean: 'Média', median: 'Mediana', 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', requestThroughput: 'Throughput de requisições', - timeout: 'Timeout (segundos)', image: 'Imagem vLLM', - ignoreEos: 'Ignorar EOS', + ignoreEos: 'Ignorar token de fim de sequência (EOS)', + ignoreEosHelp: + 'Evita parar antes por EOS para testar o comprimento de saída configurado. Outras condições de parada continuam válidas; requer suporte do servidor.', extraHeaders: 'Cabeçalhos extras', }, vllmMonitor: { @@ -1750,6 +1747,155 @@ const message = { modelType: 'Tipo de modelo', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Limite da preparação, excluído do tempo limite total.', + pointTimeoutHelp: + 'Tempo separado por ponto, incluindo início, aquecimento e solicitações; limitado pelo tempo total restante.', + totalTimeoutHelp: 'Começa após a preparação, inclui pontos e intervalos e interrompe o teste ao expirar.', + concurrencyLevels: 'Níveis de concorrência', + concurrencyHelp: 'Os níveis são executados em sequência. Cada valor limita as solicitações simultâneas.', + requestCountMode: 'Quantidade de solicitações', + fixedRequestMode: 'Solicitações fixas por nível', + scaledRequestMode: 'Calcular pela concorrência', + requestsPerPoint: 'Solicitações por nível', + requestCountFormula: + 'Por nível: valor fixo ou max(concorrência × multiplicador, mínimo de solicitações). Total do cenário: soma dos níveis × repetições, sem aquecimento.', + controlLog: 'Log de preparação e controle', + executionLog: 'Log de execução', + pointLog: 'Ponto nº {0} · {1} · Log de execução', + archivedLog: '{0} (arquivo histórico {1})', + tokenLengths: 'Tokens de entrada / saída', + kind: 'Categoria dos resultados', + kindServe: 'serve (testes comuns)', + kindPD: 'pd (medições de Prefill/Decode)', + saveDetailed: 'Salvar detalhes das solicitações', + saveDetailedHelp: + 'Salva comprimentos, latências, texto gerado e erros de cada solicitação. Ao desativar, as métricas resumidas são mantidas e o tamanho dos arquivos é reduzido.', + parameters: 'Parâmetros', + temperatureHelp: + 'Controla a aleatoriedade da saída. Zero geralmente produz resultados mais estáveis; valores maiores aumentam a aleatoriedade.', + pointTimeout: 'Tempo limite por ponto (segundos)', + temperature: 'Temperatura de amostragem', + requestUrl: 'URL da API', + invalidRequestUrl: + 'Informe uma URL HTTP(S) completa terminada em /chat/completions ou /completions, sem credenciais, parâmetros de consulta ou fragmentos.', + requestRateHelp: + 'Aplica-se apenas a este cenário. A taxa ilimitada respeita os limites de concorrência; aceita QPS fracionário.', + tokenizerModeHelp: + 'Os modos disponíveis dependem da versão do vLLM na imagem de teste. O carregamento do tokenizador é verificado durante a preparação da tarefa.', + invalidBaseUrl: 'Insira uma URL HTTP(S) válida sem credenciais, consulta ou fragmento.', + invalidEndpoint: + 'Informe um caminho compatível com o protocolo selecionado que termine em {0}, sem parâmetros de consulta ou fragmentos.', + invalidTokenizer: + 'Use um diretório absoluto ou ID de repositório; caminhos relativos, vírgulas e quebras de linha não são aceitos.', + invalidRequestRate: 'Selecione ilimitado ou insira um número finito maior que 0; decimais são aceitos.', + invalidCaCert: 'Insira o caminho absoluto do certificado CA no nó principal, sem vírgulas ou quebras de linha.', + bodyOverride: 'O corpo adicional não pode sobrescrever {0}.', + invalidBody: 'Insira um objeto JSON válido.', + invalidConcurrencies: 'Informe de 1 a 100 valores de concorrência, cada um inteiro entre 1 e 100000.', + emptyRequestCount: + 'Ao calcular pela concorrência, o multiplicador e o mínimo de solicitações não podem ser ambos 0.', + requestCountLimit: 'As solicitações calculadas por ponto não podem exceder 1000000.', + contextExceeded: 'Os tokens de entrada, saída e reserva do modelo excedem o limite de contexto.', + planLimit: 'Informe de 1 a 100 cenários com no máximo 2000 pontos.', + + caCertHelp: + 'Selecione um certificado CA no servidor principal para verificar serviços HTTPS. Deixe vazio para usar os certificados do sistema.', + extraBody: 'Corpo adicional da solicitação', + entryKey: 'Nome do parâmetro', + entryValue: 'Valor do parâmetro', + tokenizerMode: 'Modo do tokenizador', + requireIdle: 'Verificar se o serviço está ocioso antes de iniciar', + requireIdleHelp: + 'Consulta /metrics uma vez antes do aquecimento e do teste de carga. Interrompe se o serviço estiver ocupado ou se não for possível confirmar que está ocioso. Isso não impede outro tráfego durante o teste.', + trustRemoteCode: 'Confiar em código remoto', + trustRemoteCodeHelp: + 'Permite executar código de tokenização do repositório do modelo no contêiner de teste. Ative apenas quando necessário e se a fonte for confiável.', + tokenizerModes: { auto: 'Automático (recomendado)', slow: 'Tokenizador lento', mistral: 'Tokenizador Mistral' }, + quickDescription: 'Verifica a conectividade e a medição com uma única solicitação.', + regularDescription: 'Cargas curtas, médias e longas para testes rotineiros de desempenho.', + fullDescription: + 'Vários cenários, níveis de concorrência e repetições, incluindo entradas longas e prefixos compartilhados.', + customDescription: 'Comece com um cenário, configure os parâmetros e adicione outros conforme necessário.', + scenarios: 'Cenários', + builtIn: 'Integrado', + builtInHelp: 'Planos integrados não podem ser editados ou excluídos. Ajuste uma cópia ao criar um teste.', + modified: 'Modificado', + + imageExists: 'Disponível localmente', + imageNeedsPull: 'Requer download', + remark: 'Observações', + source: 'Serviço local', + mode: 'Plano de teste', + quick: 'Verificação rápida', + regular: 'Normal', + full: 'Completo', + custom: 'Personalizado', + addScenario: 'Adicionar cenário', + advanced: 'Configurações avançadas', + points: 'Pontos', + warmups: 'Requisições de aquecimento', + fixedRequests: 'Requisições fixas', + multiplier: 'Requisições por concorrência', + minRequests: 'Mínimo de requisições', + trials: 'Repetições', + prefixRatio: 'Proporção do prefixo compartilhado', + totalTimeout: 'Tempo limite da rodada (s)', + prepareTimeout: 'Tempo limite de preparação (s)', + interval: 'Intervalo entre pontos (s)', + context: 'Limite de contexto (0: desconhecido)', + reserve: 'Tokens reservados para o modelo de texto', + storage: 'Limite de armazenamento (MiB)', + stopOnError: 'Parar os próximos pontos em caso de erro', + caCert: 'Caminho do certificado CA', + validTrials: 'Válidas / total', + retry: 'Repetir pontos selecionados', + environment: 'Ambiente', + plan: 'Configuração fixada', + clientHelp: + 'O contêiner cliente roda no nó principal e envia requisições a um serviço existente. Não inicia inferência nem exige GPU.', + retryHelp: 'Apenas os pontos anormais selecionados são repetidos, com os mesmos parâmetros e novas sementes.', + secretHelp: 'As cópias não incluem chaves de API nem cabeçalhos. Informe-os novamente se necessário.', + resultHelp: + 'A mediana e os valores mínimo/máximo incluem apenas execuções bem-sucedidas sem anomalias. P99 é a mediana dos P99 de cada execução. Cache e tráfego externo não são controlados.', + }, + benchmarkOverview: { + noResults: 'Nenhum resultado válido. Consulte o motivo da falha e os logs.', + noGroupResults: 'Nenhum resultado válido nesta combinação. Selecione outro cenário ou concorrência.', + partial: + 'Resultados parciais: o teste não foi totalmente bem-sucedido. As métricas incluem apenas pontos válidos.', + highlights: 'Métricas principais', + aggregate: 'Mediana das execuções válidas nesta combinação. Clique em uma métrica para ver detalhes.', + trend: 'Tendência por concorrência', + std: 'Desvio padrão', + min: 'Mínimo', + max: 'Máximo', + tpot: 'Tempo por token de saída', + tpotHelp: 'Tempo médio de geração por token de saída após o primeiro token.', + itl: 'Latência entre tokens', + itlHelp: 'Tempo entre tokens consecutivos em uma resposta em streaming.', + e2el: 'Latência de ponta a ponta', + e2elHelp: 'Tempo entre o envio da requisição e o recebimento da resposta completa.', + requestHelp: 'Número de requisições concluídas por segundo.', + usageHelp: + 'Medianas das execuções válidas nesta combinação, não os totais de requisições do teste inteiro. Consulte execuções anormais na aba de pontos.', + duration: 'Duração da execução', + throughput: 'Taxa de processamento', + latency: 'Latência', + usage: 'Requisições e uso (execuções válidas)', + }, + benchmarkTokenizer: { + title: 'Gerenciamento de tokenizadores', + local: 'Registrar diretório local', + upload: 'Enviar pacote de tokenizador', + uploadHelp: 'Envie um ZIP / tar.gz sem os pesos do modelo. Máximo: 128 MiB compactado e 256 MiB extraído.', + source: 'Método de importação', + deleteLocal: 'Remover o registro do tokenizador “{0}”? O diretório e os arquivos originais serão mantidos.', + deleteUpload: 'Excluir o tokenizador “{0}” e seus arquivos enviados? Os relatórios anteriores serão mantidos.', + select: 'Selecionar um tokenizador', + selectHelp: + 'Para testes offline, selecione um tokenizador gerenciado. A entrada personalizada aceita diretórios locais ou nomes de repositórios.', + }, container: { createByCommand: 'Criar por comando', importContainerBackupTip: 'Importar arquivo de backup de contêiner, apenas .tar.gz é suportado', diff --git a/frontend/src/lang/modules/ru.ts b/frontend/src/lang/modules/ru.ts index 376cf3fea..33a96306f 100644 --- a/frontend/src/lang/modules/ru.ts +++ b/frontend/src/lang/modules/ru.ts @@ -1494,16 +1494,13 @@ const message = { statusWaiting: 'Ожидание', base: 'Основная информация', backend: 'Backend', - baseUrl: 'Base URL', endpoint: 'Endpoint', tokenizer: 'Токенизатор', - tokenizerPlaceholder: - 'Выберите или введите локальный каталог токенизатора, например /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: 'Введите абсолютный путь к каталогу на главном узле или ID репозитория Hugging Face', runConfig: 'Конфигурация запуска', rawResult: 'Исходный результат', resultMetrics: 'Метрики результата', contextTokens: 'Длина контекста', - contextTokensHelper: 'Лимит входных токенов плюс лимит выходных токенов для этого бенчмарка.', outputThroughput: 'Выходная пропускная способность', outputThroughputHelper: 'Выходные токены, генерируемые в секунду. Чем выше значение, тем быстрее генерация.', @@ -1513,20 +1510,19 @@ const message = { firstTokenLatency: 'Задержка первого токена', firstTokenLatencyHelper: 'Время от отправки запроса до получения первого токена. Чем ниже значение, тем быстрее ответ.', - tokenValueHelper: 'Введите положительное целое число или значение с k, например 512, 1k, 32k', numPrompts: 'Промпты', concurrency: 'Параллелизм', mean: 'Среднее', median: 'Медиана', requestRate: 'Частота запросов', requestRateUnlimited: 'Без ограничений (макс. пропускная способность)', - requestRateCustom: 'Пользовательский QPS', requestRateCustomPlaceholder: 'Запросов в секунду, например 2.5', successfulRequests: 'Успешные запросы', requestThroughput: 'Пропускная способность запросов', - timeout: 'Тайм-аут (секунды)', image: 'Образ vLLM', - ignoreEos: 'Игнорировать EOS', + ignoreEos: 'Игнорировать токен конца последовательности (EOS)', + ignoreEosHelp: + 'Предотвращает раннюю остановку по EOS для тестирования заданной длины вывода. Другие условия остановки действуют; требуется поддержка сервера.', extraHeaders: 'Дополнительные заголовки', }, vllmMonitor: { @@ -1740,6 +1736,161 @@ const message = { modelType: 'Тип модели', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Лимит подготовки, не входит в общий тайм-аут.', + pointTimeoutHelp: + 'Отдельный отсчёт для каждой точки, включая запуск, прогрев и запросы; ограничен оставшимся общим временем.', + totalTimeoutHelp: 'Отсчёт после подготовки, включая все точки и интервалы. По тайм-ауту тест останавливается.', + concurrencyLevels: 'Уровни параллелизма', + concurrencyHelp: + 'Уровни проверяются последовательно. Каждое значение ограничивает число одновременных запросов.', + requestCountMode: 'Количество запросов', + fixedRequestMode: 'Фиксированное число на уровень', + scaledRequestMode: 'Рассчитать по параллелизму', + requestsPerPoint: 'Запросов на уровень', + requestCountFormula: + 'На уровень: фиксированное значение или max(параллелизм × множитель, минимум запросов). Всего в сценарии: сумма по уровням × повторы, без прогрева.', + controlLog: 'Журнал подготовки и управления', + executionLog: 'Журнал выполнения', + pointLog: 'Точка №{0} · {1} · Журнал выполнения', + archivedLog: '{0} (архив {1})', + tokenLengths: 'Токены ввода / вывода', + kind: 'Категория результатов', + kindServe: 'serve (обычные тесты)', + kindPD: 'pd (измерения Prefill/Decode)', + saveDetailed: 'Сохранять подробности запросов', + saveDetailedHelp: + 'Сохраняет длину, задержки, сгенерированный текст и ошибки каждого запроса. При отключении сводные метрики сохраняются, а размер файлов уменьшается.', + parameters: 'Параметры', + temperatureHelp: + 'Управляет случайностью генерации. Ноль обычно даёт более стабильный результат; более высокие значения увеличивают случайность.', + pointTimeout: 'Тайм-аут одной точки (секунды)', + temperature: 'Температура сэмплирования', + requestUrl: 'Адрес API', + invalidRequestUrl: + 'Введите полный HTTP(S) URL, заканчивающийся на /chat/completions или /completions, без учётных данных, параметров запроса и фрагментов.', + requestRateHelp: + 'Применяется только к этому сценарию. Неограниченная частота учитывает предел параллелизма; допускается дробный QPS.', + tokenizerModeHelp: + 'Доступные режимы зависят от версии vLLM в образе тестирования. Загрузка токенизатора проверяется при подготовке задачи.', + invalidBaseUrl: 'Введите корректный HTTP(S) URL без учётных данных, параметров запроса и фрагмента.', + invalidEndpoint: + 'Введите путь, соответствующий выбранному протоколу и заканчивающийся на {0}, без параметров запроса и фрагментов.', + invalidTokenizer: + 'Укажите абсолютный каталог или ID репозитория; относительные пути, запятые и переносы строк недопустимы.', + invalidRequestRate: + 'Выберите отсутствие ограничения или введите конечное число больше 0; дробные числа допустимы.', + invalidCaCert: 'Укажите абсолютный путь к сертификату CA на основном узле без запятых и переносов строк.', + bodyOverride: 'Дополнительное тело не может переопределять {0}.', + invalidBody: 'Введите корректный объект JSON.', + invalidConcurrencies: 'Нужно от 1 до 100 значений параллелизма, каждое — целое число от 1 до 100000.', + emptyRequestCount: + 'При расчёте по параллелизму множитель и минимальное число запросов не могут оба быть равны 0.', + requestCountLimit: 'Расчётное число запросов на точку не должно превышать 1000000.', + contextExceeded: 'Сумма входных, выходных токенов и резерва шаблона превышает лимит контекста.', + planLimit: 'Нужно от 1 до 100 сценариев и не более 2000 точек.', + + caCertHelp: + 'Выберите сертификат CA на основном сервере для проверки HTTPS. Оставьте поле пустым для системных сертификатов.', + extraBody: 'Дополнительное тело запроса', + entryKey: 'Имя параметра', + entryValue: 'Значение параметра', + tokenizerMode: 'Режим токенизатора', + requireIdle: 'Проверять отсутствие нагрузки перед запуском', + requireIdleHelp: + 'Однократно проверяет /metrics перед прогревом и нагрузочным тестом. Останавливается, если сервис занят или отсутствие нагрузки нельзя подтвердить. Не блокирует другой трафик во время теста.', + trustRemoteCode: 'Доверять удалённому коду', + trustRemoteCodeHelp: + 'Разрешает выполнять код токенизатора из репозитория модели в контейнере тестирования. Включайте только при необходимости и доверии к источнику.', + tokenizerModes: { + auto: 'Автоматически (рекомендуется)', + slow: 'Медленный токенизатор', + mistral: 'Токенизатор Mistral', + }, + quickDescription: 'Проверка соединения и измерений одним запросом.', + regularDescription: 'Короткие, средние и длинные нагрузки для регулярных тестов производительности.', + fullDescription: + 'Разные сценарии, уровни параллелизма и повторные измерения, включая длинные входы и общие префиксы.', + customDescription: 'Начните с одного сценария, настройте параметры и добавьте другие при необходимости.', + scenarios: 'Сценарии', + builtIn: 'Встроенный', + builtInHelp: 'Встроенные планы нельзя изменить или удалить. Настройте копию при создании теста.', + modified: 'Изменён', + + imageExists: 'Есть локально', + imageNeedsPull: 'Требуется загрузка', + remark: 'Примечания', + source: 'Локальный сервис', + mode: 'План теста', + quick: 'Быстрая проверка', + regular: 'Обычный', + full: 'Полный', + custom: 'Свой', + addScenario: 'Добавить сценарий', + advanced: 'Дополнительные настройки', + points: 'Точки', + warmups: 'Запросы прогрева', + fixedRequests: 'Число запросов', + multiplier: 'Множитель параллелизма', + minRequests: 'Минимум запросов', + trials: 'Повторения', + prefixRatio: 'Доля общего префикса', + totalTimeout: 'Тайм-аут раунда (с)', + prepareTimeout: 'Тайм-аут подготовки (с)', + interval: 'Интервал точек (с)', + context: 'Лимит контекста (0: неизвестен)', + reserve: 'Резерв токенов шаблона', + storage: 'Лимит хранения (МиБ)', + stopOnError: 'Останавливать следующие точки при ошибке', + caCert: 'Путь к сертификату CA', + validTrials: 'Успешных / всего повторений', + retry: 'Повторить выбранные точки', + environment: 'Среда выполнения', + plan: 'Зафиксированная конфигурация', + clientHelp: + 'Клиентский контейнер работает на главном узле и отправляет запросы существующему сервису. Он не запускает модель и не требует GPU.', + retryHelp: 'Повторяются только выбранные проблемные точки с прежними параметрами и новыми начальными числами.', + secretHelp: 'Копии не содержат ключи API и заголовки. При необходимости введите их заново.', + resultHelp: + 'Медиана и минимум/максимум рассчитываются только по успешным запускам без аномалий запросов. P99 — медиана P99 отдельных запусков. Кеш и внешний трафик не контролируются.', + }, + benchmarkOverview: { + noResults: 'Нет достоверных результатов. Проверьте причину сбоя и журналы.', + noGroupResults: 'Нет достоверных результатов для этой комбинации. Выберите другой сценарий или параллелизм.', + partial: + 'Частичные результаты: тест завершён не полностью успешно. Метрики учитывают только достоверные точки.', + highlights: 'Основные метрики', + aggregate: 'Медиана достоверных запусков этой комбинации. Нажмите на метрику для подробностей.', + trend: 'Зависимость от параллелизма', + std: 'Станд. отклонение', + min: 'Минимум', + max: 'Максимум', + tpot: 'Время на выходной токен', + tpotHelp: 'Среднее время генерации выходного токена после первого.', + itl: 'Задержка между токенами', + itlHelp: 'Время между последовательными токенами потокового ответа.', + e2el: 'Полная задержка', + e2elHelp: 'Время от отправки запроса до получения полного ответа.', + requestHelp: 'Число завершённых запросов в секунду.', + usageHelp: + 'Медианы достоверных запусков этой комбинации, а не общее число запросов теста. Ошибочные запуски доступны на вкладке точек.', + duration: 'Длительность запуска', + throughput: 'Пропускная способность', + latency: 'Задержка', + usage: 'Запросы и использование (достоверные запуски)', + }, + benchmarkTokenizer: { + title: 'Управление токенизаторами', + local: 'Зарегистрировать локальный каталог', + upload: 'Загрузить архив токенизатора', + uploadHelp: 'Загрузите ZIP / tar.gz без весов модели. Максимум: 128 МиБ в архиве и 256 МиБ после распаковки.', + source: 'Способ импорта', + deleteLocal: 'Удалить регистрацию токенизатора «{0}»? Исходный каталог и файлы будут сохранены.', + deleteUpload: 'Удалить токенизатор «{0}» и загруженные файлы? Предыдущие отчёты сохранятся.', + select: 'Выберите токенизатор', + selectHelp: + 'Для автономных тестов выберите токенизатор из списка. Ручной ввод поддерживает локальный каталог или имя репозитория.', + }, container: { createByCommand: 'Создать с помощью команды', importContainerBackupTip: 'Импорт файла резервной копии контейнера, поддерживается только .tar.gz', diff --git a/frontend/src/lang/modules/tr.ts b/frontend/src/lang/modules/tr.ts index f09307038..bf419438a 100644 --- a/frontend/src/lang/modules/tr.ts +++ b/frontend/src/lang/modules/tr.ts @@ -1502,15 +1502,13 @@ const message = { 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', + tokenizerPlaceholder: 'Ana düğümdeki mutlak dizin yolunu veya Hugging Face depo kimliğini girin', 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.', @@ -1520,20 +1518,19 @@ const message = { 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.', - tokenValueHelper: 'Pozitif tam sayı veya k değeri girin, örn. 512, 1k, 32k', numPrompts: 'Prompt', concurrency: 'Eşzamanlılık', mean: 'Ortalama', median: 'Medyan', 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', requestThroughput: 'İstek Throughput', - timeout: 'Zaman aşımı (saniye)', image: 'vLLM İmajı', - ignoreEos: "EOS'u yok say", + ignoreEos: 'Dizi sonu belirtecini (EOS) yok say', + ignoreEosHelp: + 'Ayarlanan çıktı uzunluğunu test etmek için EOS nedeniyle erken durmayı önler. Diğer durdurma koşulları geçerlidir; sunucu desteği gerekir.', extraHeaders: 'Ek Başlıklar', }, vllmMonitor: { @@ -1747,6 +1744,157 @@ const message = { modelType: 'Model türü', }, }, + benchmarkPlan: { + prepareTimeoutHelp: 'Hazırlık süresi sınırıdır; toplam zaman aşımına dahil değildir.', + pointTimeoutHelp: + 'Her nokta ayrı ölçülür; başlangıç, ısınma ve tüm istekler dahildir. Kalan toplam süreyle sınırlıdır.', + totalTimeoutHelp: 'Hazırlık sonrası başlar, tüm noktaları ve aralıkları kapsar. Süre dolunca test durur.', + concurrencyLevels: 'Eşzamanlılık seviyeleri', + concurrencyHelp: 'Seviyeler sırayla test edilir. Her değer aynı anda devam eden istek sayısını sınırlar.', + requestCountMode: 'İstek sayısı ayarı', + fixedRequestMode: 'Seviye başına sabit istek', + scaledRequestMode: 'Eşzamanlılığa göre hesapla', + requestsPerPoint: 'Seviye başına istek', + requestCountFormula: + 'Seviye başına: sabit değer veya max(eşzamanlılık × çarpan, minimum istek). Senaryo toplamı: seviyelerin toplamı × tekrar sayısı, ısınma hariç.', + controlLog: 'Hazırlık ve kontrol günlüğü', + executionLog: 'Yürütme günlüğü', + pointLog: 'Test noktası #{0} · {1} · Yürütme günlüğü', + archivedLog: '{0} (arşiv {1})', + tokenLengths: 'Girdi / çıktı tokenları', + kind: 'Sonuç kategorisi', + kindServe: 'serve (normal testler)', + kindPD: 'pd (Prefill/Decode ölçümleri)', + saveDetailed: 'İstek ayrıntılarını kaydet', + saveDetailedHelp: + 'Her isteğin uzunluğunu, gecikmesini, üretilen metni ve hatalarını kaydeder. Devre dışı bırakıldığında özet ölçümler korunur ve sonuç dosyalarının boyutu azalır.', + parameters: 'Parametreler', + temperatureHelp: + 'Çıktının rastgeleliğini kontrol eder. Sıfır genellikle daha kararlı çıktı sağlar; yüksek değerler rastgeleliği artırır.', + pointTimeout: 'Nokta başına zaman aşımı (saniye)', + temperature: 'Örnekleme sıcaklığı', + requestUrl: 'API adresi', + invalidRequestUrl: + '/chat/completions veya /completions ile biten tam bir HTTP(S) adresi girin; kimlik bilgisi, sorgu parametresi veya parça içermemelidir.', + requestRateHelp: + 'Yalnızca bu senaryoya uygulanır. Sınırsız hız da eşzamanlılık sınırına uyar; kesirli QPS desteklenir.', + tokenizerModeHelp: + 'Kullanılabilir modlar, test imajındaki vLLM sürümüne bağlıdır. Görev hazırlanırken belirteçleyicinin yüklenebildiği kontrol edilir.', + invalidBaseUrl: 'Kimlik bilgisi, sorgu veya parça içermeyen geçerli bir HTTP(S) URL girin.', + invalidEndpoint: + 'Seçilen protokole uygun, {0} ile biten ve sorgu parametresi veya parça içermeyen bir uç nokta yolu girin.', + invalidTokenizer: + 'Mutlak dizin veya depo kimliği kullanın; göreli yollar, virgüller ve satır sonları desteklenmez.', + invalidRequestRate: 'Sınırsızı seçin veya 0’dan büyük sonlu bir sayı girin; ondalık sayılar desteklenir.', + invalidCaCert: 'Birincil düğümdeki CA sertifikasının mutlak dosya yolunu virgül veya satır sonu olmadan girin.', + bodyOverride: 'Ek gövde {0} parametresini geçersiz kılamaz.', + invalidBody: 'Geçerli bir JSON nesnesi girin.', + invalidConcurrencies: 'Her biri 1–100000 arasında tam sayı olan 1–100 eşzamanlılık değeri girin.', + emptyRequestCount: 'Eşzamanlılığa göre hesaplamada çarpan ve minimum istek sayısı birlikte 0 olamaz.', + requestCountLimit: 'Nokta başına hesaplanan istek sayısı 1000000 değerini aşamaz.', + contextExceeded: 'Giriş, çıkış tokenları ve şablon rezervi bağlam sınırını aşıyor.', + planLimit: 'Toplam en fazla 2000 noktadan oluşan 1–100 senaryo girin.', + + caCertHelp: + 'HTTPS hizmetlerini doğrulamak için ana sunucudan bir CA sertifikası seçin. Sistem sertifikaları için boş bırakın.', + extraBody: 'Ek istek gövdesi', + entryKey: 'Parametre adı', + entryValue: 'Parametre değeri', + tokenizerMode: 'Belirteçleyici modu', + requireIdle: 'Başlamadan önce hizmetin boşta olduğunu denetle', + requireIdleHelp: + 'Isınma ve yük testi öncesinde /metrics bir kez denetlenir. Hizmet meşgulse veya boşta olduğu doğrulanamazsa durur. Test sırasında başka trafiği engellemez.', + trustRemoteCode: 'Uzak koda güven', + trustRemoteCodeHelp: + 'Model deposundaki özel belirteçleyici kodunun test konteynerinde çalışmasına izin verir. Yalnızca gerektiğinde ve kaynağa güvendiğinizde etkinleştirin.', + tokenizerModes: { + auto: 'Otomatik (önerilen)', + slow: 'Yavaş belirteçleyici', + mistral: 'Mistral belirteçleyicisi', + }, + quickDescription: 'Tek bir istekle bağlantıyı ve ölçüm sürecini doğrular.', + regularDescription: 'Günlük performans testleri için kısa, orta ve uzun iş yükleri.', + fullDescription: + 'Uzun girdiler ve ortak önekler dahil, farklı senaryolar ve eşzamanlılık düzeylerinde tekrarlı ölçümler.', + customDescription: 'Bir senaryoyla başlayın, parametrelerini ayarlayın ve gerektiğinde yenilerini ekleyin.', + scenarios: 'Senaryolar', + builtIn: 'Yerleşik', + builtInHelp: 'Yerleşik planlar düzenlenemez veya silinemez. Test oluştururken bir kopyayı ayarlayın.', + modified: 'Değiştirildi', + + imageExists: 'Yerelde mevcut', + imageNeedsPull: 'İndirme gerekli', + remark: 'Notlar', + source: 'Yerel hizmet', + mode: 'Test planı', + quick: 'Hızlı kontrol', + regular: 'Normal', + full: 'Tam', + custom: 'Özel', + addScenario: 'Senaryo ekle', + advanced: 'Gelişmiş ayarlar', + points: 'Ölçüm noktaları', + warmups: 'Isınma istekleri', + fixedRequests: 'Sabit istekler', + multiplier: 'Eşzamanlılık başına istek', + minRequests: 'En az istek', + trials: 'Tekrarlar', + prefixRatio: 'Ortak önek oranı', + totalTimeout: 'Tur zaman aşımı (sn)', + prepareTimeout: 'Hazırlık zaman aşımı (sn)', + interval: 'Ölçüm aralığı (sn)', + context: 'Bağlam sınırı (0: bilinmiyor)', + reserve: 'Şablon için ayrılan token', + storage: 'Depolama sınırı (MiB)', + stopOnError: 'Hatada sonraki ölçümleri durdur', + caCert: 'CA sertifikası yolu', + validTrials: 'Geçerli / toplam tekrar', + retry: 'Seçili ölçümleri yinele', + environment: 'Çalışma ortamı', + plan: 'Sabitlenmiş yapılandırma', + clientHelp: + 'İstemci konteyneri ana düğümde çalışır ve mevcut hizmete istek gönderir. Çıkarım hizmeti başlatmaz ve GPU gerektirmez.', + retryHelp: 'Yalnızca seçili sorunlu ölçümler aynı parametreler ve yeni tohumlarla yinelenir.', + secretHelp: 'Kopyalar API anahtarlarını ve başlıkları içermez. Gerekiyorsa yeniden girin.', + resultHelp: + 'Medyan ve en düşük/en yüksek değerler yalnızca istek anomalisi olmayan başarılı çalışmaları içerir. P99, çalışma başına P99 değerlerinin medyanıdır. Önbellek ve dış trafik kontrol edilmez.', + }, + benchmarkOverview: { + noResults: 'Geçerli test sonucu yok. Hata nedenini ve günlükleri kontrol edin.', + noGroupResults: 'Bu birleşim için geçerli sonuç yok. Başka bir senaryo veya eşzamanlılık seçin.', + partial: 'Kısmi sonuçlar: test tamamen başarılı olmadı. Metrikler yalnızca geçerli noktaları kapsar.', + highlights: 'Temel metrikler', + aggregate: 'Bu birleşimdeki geçerli çalıştırmaların medyanı. Ayrıntılar için metriğe tıklayın.', + trend: 'Eşzamanlılık eğilimi', + std: 'Standart sapma', + min: 'Minimum', + max: 'Maksimum', + tpot: 'Çıktı tokeni başına süre', + tpotHelp: 'İlk tokenden sonra çıktı tokeni başına ortalama üretim süresi.', + itl: 'Tokenler arası gecikme', + itlHelp: 'Akış yanıtındaki ardışık tokenler arasındaki süre.', + e2el: 'Uçtan uca gecikme', + e2elHelp: 'İsteğin gönderilmesinden yanıtın tamamının alınmasına kadar geçen süre.', + requestHelp: 'Saniyede tamamlanan istek sayısı.', + usageHelp: + 'Bu birleşimdeki geçerli çalıştırmaların medyanlarıdır; tüm testin istek toplamları değildir. Anormal çalıştırmalar için noktalar sekmesine bakın.', + duration: 'Çalıştırma süresi', + throughput: 'İşleme hızı', + latency: 'Gecikme', + usage: 'İstekler ve kullanım (geçerli çalıştırmalar)', + }, + benchmarkTokenizer: { + title: 'Tokenizer yönetimi', + local: 'Yerel dizini kaydet', + upload: 'Tokenizer paketini yükle', + uploadHelp: 'Model ağırlıkları içermeyen ZIP / tar.gz yükleyin. Sınır: sıkıştırılmış 128 MiB, açılmış 256 MiB.', + source: 'İçe aktarma yöntemi', + deleteLocal: '“{0}” tokenizer kaydı kaldırılsın mı? Özgün dizin ve dosyalar korunur.', + deleteUpload: '“{0}” tokenizer ve yüklenen dosyaları silinsin mi? Geçmiş test raporları korunur.', + select: 'Bir tokenizer seçin', + selectHelp: + 'Çevrimdışı test için yönetilen bir tokenizer seçin. Özel giriş yerel dizin veya depo adını destekler.', + }, container: { createByCommand: 'Komutla oluştur', importContainerBackupTip: 'Konteyner yedek dosyasını içe aktar, yalnızca .tar.gz desteklenir', diff --git a/frontend/src/lang/modules/zh-Hant.ts b/frontend/src/lang/modules/zh-Hant.ts index 267a763f3..4054abb4d 100644 --- a/frontend/src/lang/modules/zh-Hant.ts +++ b/frontend/src/lang/modules/zh-Hant.ts @@ -1413,35 +1413,31 @@ const message = { statusWaiting: '等待中', base: '基礎資訊', backend: '後端', - baseUrl: '服務地址', endpoint: '介面路徑', tokenizer: '分詞器', - tokenizerPlaceholder: '請選擇或輸入本機分詞器目錄,例如 /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: '請輸入主節點上的絕對目錄或 Hugging Face 儲存庫 ID', runConfig: '執行設定', rawResult: '原始結果', resultMetrics: '結果指標', contextTokens: '上下文長度', - contextTokensHelper: '本次測試的輸入 Token 與輸出 Token 上限之和。', outputThroughput: '輸出吞吐', outputThroughputHelper: '模型每秒產生的輸出 Token 數,越高表示生成速度越快。', totalThroughput: '總吞吐', totalThroughputHelper: '每秒處理的輸入與輸出 Token 總數,用於衡量整體處理能力。', firstTokenLatency: '首 Token 延遲', firstTokenLatencyHelper: '從請求送出到收到第一個 Token 的時間,越低表示回應越快。', - tokenValueHelper: '請輸入正整數或 k 單位,例如 512、1k、32k', numPrompts: '請求數量', concurrency: '併發數', mean: '平均值', median: '中位數', requestRate: '請求速率', requestRateUnlimited: '不限速(最大吞吐)', - requestRateCustom: '自訂 QPS', requestRateCustomPlaceholder: '請輸入每秒請求數,如 2.5', successfulRequests: '成功請求', requestThroughput: '請求吞吐', - timeout: '逾時時間(秒)', image: 'vLLM 映像', - ignoreEos: '忽略 EOS', + ignoreEos: '忽略結束標記(EOS)', + ignoreEosHelp: '避免因結束標記提前停止,便於依設定輸出長度壓測;其他停止條件仍有效,需服務支援。', extraHeaders: '額外請求標頭', }, vllmMonitor: { @@ -1645,6 +1641,140 @@ const message = { modelType: '模型類型', }, }, + benchmarkPlan: { + prepareTimeoutHelp: '準備階段的時間上限,不計入整輪逾時。', + pointTimeoutHelp: '每個測點獨立計時,含啟動、預熱和全部請求,受整輪剩餘時間限制。', + totalTimeoutHelp: '準備完成後計時,涵蓋所有測點及間隔,逾時後停止。', + concurrencyLevels: '並行檔位', + concurrencyHelp: '各檔位依序測試,數值表示同時進行的請求數量上限。', + requestCountMode: '請求數量設定', + fixedRequestMode: '每檔固定請求數', + scaledRequestMode: '依並行數計算', + requestsPerPoint: '每檔請求數', + requestCountFormula: + '每檔:固定值,或 max(並行數 × 倍數,最少請求數);場景總量:各檔請求數之和 × 重複次數,不含預熱。', + controlLog: '準備與控制日誌', + executionLog: '執行日誌', + pointLog: '測點 #{0} · {1} · 執行日誌', + archivedLog: '{0}(歷史 {1})', + tokenLengths: '輸入 / 輸出 Token', + kind: '結果分類', + kindServe: 'serve(一般測試)', + kindPD: 'pd(Prefill/Decode 探測)', + saveDetailed: '儲存請求明細', + saveDetailedHelp: '儲存每筆請求的長度、延遲、生成文字和錯誤資訊。關閉後仍保留彙總指標,可減少結果檔案大小。', + parameters: '參數', + temperatureHelp: '控制生成內容的隨機性;0 通常較穩定,值越高越隨機。', + pointTimeout: '單測點逾時(秒)', + temperature: '取樣溫度', + requestUrl: '介面位址', + invalidRequestUrl: + '請輸入以 /chat/completions 或 /completions 結尾的完整 HTTP(S) 位址,不含使用者名稱密碼、查詢參數或片段。', + requestRateHelp: '僅套用於目前場景;不限速仍受並行上限限制,可輸入小數 QPS。', + tokenizerModeHelp: '可用模式取決於壓測映像中的 vLLM 版本;任務準備時會驗證分詞器能否載入。', + invalidBaseUrl: '請輸入有效的 HTTP(S) 位址,不含使用者密碼、查詢參數或片段。', + invalidEndpoint: '請輸入符合目前協定、以 {0} 結尾的介面路徑,不含查詢參數或片段。', + invalidTokenizer: '請輸入絕對目錄路徑或儲存庫識別碼,不支援相對路徑、逗號或換行。', + invalidRequestRate: '請選擇不限速或輸入大於 0 的有限數值,支援小數。', + invalidCaCert: '請輸入主節點上 CA 憑證的絕對檔案路徑,不含逗號或換行。', + bodyOverride: '額外請求本文不能覆寫參數 {0}。', + invalidBody: '請輸入有效的 JSON 物件。', + invalidConcurrencies: '並行數需要 1–100 項,每項為 1–100000 的正整數。', + emptyRequestCount: '依並行數計算時,並行倍數和最少請求數不能同時為 0。', + requestCountLimit: '計算後的單測點請求數不能超過 1000000。', + contextExceeded: '輸入 Token、輸出 Token 與範本預留之和超過上下文上限。', + planLimit: '需要 1–100 個場景,展開後的測點總數不能超過 2000。', + + caCertHelp: '選擇主節點伺服器上的 CA 憑證檔案,用於驗證 HTTPS 服務;留空使用系統憑證。', + extraBody: '額外請求本文', + entryKey: '參數名稱', + entryValue: '參數值', + tokenizerMode: '分詞器模式', + requireIdle: '開始前檢查服務閒置狀態', + requireIdleHelp: + '在預熱和壓力測試前檢查一次 /metrics。服務忙碌或無法確認閒置時停止;無法阻止測試期間的其他流量。', + trustRemoteCode: '信任遠端程式碼', + trustRemoteCodeHelp: '允許在壓測容器內執行模型儲存庫的自訂分詞器程式碼。僅在需要且來源可信時開啟。', + tokenizerModes: { auto: '自動(建議)', slow: '慢速分詞器', mistral: 'Mistral 專用' }, + quickDescription: '單一請求驗證服務連線與測量流程。', + regularDescription: '短、中、長三類負載,適合日常效能測試。', + fullDescription: '多場景、多並行與重複測量,包含長輸入和共用前綴。', + customDescription: '從一個場景開始,依需求設定參數並新增場景。', + scenarios: '場景', + builtIn: '內建', + builtInHelp: '內建方案不可編輯或刪除,可在建立測試時調整本次設定。', + modified: '已調整', + + imageExists: '本機已存在', + imageNeedsPull: '需拉取', + remark: '備註', + source: '本機服務', + mode: '測試方案', + quick: '快速驗證', + regular: '常規測試', + full: '完整測試', + custom: '自訂', + addScenario: '新增場景', + advanced: '進階設定', + points: '測點', + warmups: '預熱請求數', + fixedRequests: '固定請求數', + multiplier: '請求數並行倍數', + minRequests: '最少請求數', + trials: '重複次數', + prefixRatio: '共用前綴比例', + totalTimeout: '整輪逾時(秒)', + prepareTimeout: '準備逾時(秒)', + interval: '測點間隔(秒)', + context: '上下文上限(0 表示未知)', + reserve: '範本預留 Token', + storage: '儲存上限(MiB)', + stopOnError: '發生錯誤時停止後續測點', + caCert: 'CA 憑證路徑', + validTrials: '有效 / 總次數', + retry: '重測選取測點', + environment: '執行環境', + plan: '凍結設定', + clientHelp: '壓測容器在主節點執行,向既有服務傳送請求。不會啟動推論服務,也不需分配 GPU。', + retryHelp: '本輪只重測選取的異常測點,保留參數並重新分配隨機種子。', + secretHelp: '複製設定不包含 API Key 與請求標頭,請視需要重新填寫。', + resultHelp: + '彙總僅採用成功且無請求異常的重複測試,顯示中位數與最小/最大值。P99 是各次 P99 的中位數;快取與外部流量未受控。', + }, + benchmarkOverview: { + noResults: '沒有有效的測試結果,請查看失敗原因和日誌。', + noGroupResults: '此組合沒有有效結果,請切換場景或並行數。', + partial: '部分結果:本次測試未完整成功,指標僅代表有效測點。', + highlights: '核心指標', + aggregate: '目前組合的有效重複測試中位數;點選指標查看統計詳情。', + trend: '並行趨勢', + std: '標準差', + min: '最小值', + max: '最大值', + tpot: '單 Token 耗時', + tpotHelp: '首 Token 之後,每個輸出 Token 的平均產生時間。', + itl: 'Token 間延遲', + itlHelp: '串流回應中相鄰 Token 傳回的時間間隔。', + e2el: '端到端延遲', + e2elHelp: '從送出請求到完整接收回應的時間。', + requestHelp: '每秒完成的請求數。', + usageHelp: '僅統計目前組合的有效重複測試,數值為各次結果的中位數,並非整輪請求總計;異常測點請至測點頁查看。', + duration: '測試耗時', + throughput: '吞吐指標', + latency: '延遲指標', + usage: '請求與用量(有效測試)', + }, + benchmarkTokenizer: { + title: '分詞器管理', + local: '登記本機目錄', + upload: '上傳分詞器套件', + uploadHelp: '上傳不含模型權重的 ZIP / tar.gz 分詞器套件。壓縮檔上限 128 MiB,解壓縮後上限 256 MiB。', + source: '匯入方式', + deleteLocal: '移除分詞器「{0}」的登記紀錄?原始目錄與檔案將保留。', + deleteUpload: '刪除分詞器「{0}」及其上傳檔案?歷史測試報告將保留。', + select: '選擇分詞器', + selectHelp: '離線環境建議從管理清單選擇;自訂輸入仍支援本機目錄或儲存庫名稱。', + }, container: { createByCommand: '指令建立', importContainerBackupTip: '匯入容器備份檔案,僅支援 .tar.gz 格式', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index aa1e557c5..3fb602c14 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1426,35 +1426,31 @@ const message = { statusWaiting: '等待中', base: '基础信息', backend: '后端', - baseUrl: '服务地址', endpoint: '接口路径', tokenizer: '分词器', - tokenizerPlaceholder: '请选择或输入本地分词器目录,例如 /opt/1panel/tokenizers/DeepSeek-V3', + tokenizerPlaceholder: '请输入主节点上的绝对目录或 Hugging Face 仓库 ID', runConfig: '运行配置', rawResult: '原始结果', resultMetrics: '结果指标', contextTokens: '上下文长度', - contextTokensHelper: '本次测试的输入 Token 与输出 Token 上限之和。', outputThroughput: '输出吞吐', outputThroughputHelper: '模型每秒生成的输出 Token 数,越高表示生成速度越快。', totalThroughput: '总吞吐', totalThroughputHelper: '每秒处理的输入与输出 Token 总数,用于衡量整体处理能力。', firstTokenLatency: '首 Token 延迟', firstTokenLatencyHelper: '从请求发出到收到第一个 Token 的时间,越低表示响应越快。', - tokenValueHelper: '请输入正整数或 k 单位,例如 512、1k、32k', numPrompts: '请求数量', concurrency: '并发数', requestRate: '请求速率', requestRateUnlimited: '不限速(最大吞吐)', - requestRateCustom: '自定义 QPS', requestRateCustomPlaceholder: '请输入每秒请求数,如 2.5', successfulRequests: '成功请求', requestThroughput: '请求吞吐', mean: '平均', median: '中位数', - timeout: '超时时间(秒)', image: 'vLLM 镜像', - ignoreEos: '忽略 EOS', + ignoreEos: '忽略结束标记(EOS)', + ignoreEosHelp: '避免因结束标记提前停止,便于按设定输出长度压测;其他停止条件仍有效,需服务支持。', extraHeaders: '额外请求头', }, vllmMonitor: { @@ -1659,6 +1655,140 @@ const message = { modelType: '模型类型', }, }, + benchmarkPlan: { + prepareTimeoutHelp: '准备阶段的时间上限,不计入整轮超时。', + pointTimeoutHelp: '每个测点独立计时,含启动、预热和全部请求,受整轮剩余时间限制。', + totalTimeoutHelp: '准备完成后计时,覆盖所有测点及间隔,超时后停止。', + concurrencyLevels: '并发档位', + concurrencyHelp: '各档位依次测试,数值表示同时进行的请求数量上限。', + requestCountMode: '请求数量设置', + fixedRequestMode: '每档固定请求数', + scaledRequestMode: '按并发数计算', + requestsPerPoint: '每档请求数', + requestCountFormula: + '每档:固定值,或 max(并发数 × 倍数,最少请求数);场景总量:各档请求数之和 × 重复次数,不含预热。', + controlLog: '准备与控制日志', + executionLog: '执行日志', + pointLog: '测点 #{0} · {1} · 执行日志', + archivedLog: '{0}(历史 {1})', + tokenLengths: '输入 / 输出 Token', + kind: '结果分类', + kindServe: 'serve(常规测试)', + kindPD: 'pd(Prefill/Decode 探测)', + saveDetailed: '保存请求明细', + saveDetailedHelp: '保存每条请求的长度、延迟、生成文本和错误信息。关闭后仍保留汇总指标,可减少结果文件体积。', + parameters: '参数', + temperatureHelp: '控制生成内容的随机性;0 通常更稳定,值越高越随机。', + pointTimeout: '单测点超时(秒)', + temperature: '采样温度', + requestUrl: '接口地址', + invalidRequestUrl: + '请输入以 /chat/completions 或 /completions 结尾的完整 HTTP(S) 地址,不含用户名密码、查询参数或片段。', + requestRateHelp: '仅作用于当前场景;不限速仍受并发上限约束,可输入小数 QPS。', + tokenizerModeHelp: '可用模式取决于压测镜像中的 vLLM 版本;任务准备时会验证分词器能否加载。', + invalidBaseUrl: '请输入有效的 HTTP(S) 地址,不含用户名密码、查询参数或片段。', + invalidEndpoint: '请输入符合当前协议、以 {0} 结尾的接口路径,不含查询参数或片段。', + invalidTokenizer: '请输入绝对目录路径或仓库标识,不支持相对路径、逗号或换行。', + invalidRequestRate: '请选择不限速或输入大于 0 的有限数值,支持小数。', + invalidCaCert: '请输入主节点上 CA 证书的绝对文件路径,不含逗号或换行。', + bodyOverride: '额外请求体不能覆盖参数 {0}。', + invalidBody: '请输入合法的 JSON 对象。', + invalidConcurrencies: '并发数需要 1–100 项,每项为 1–100000 的正整数。', + emptyRequestCount: '按并发数计算时,并发倍数和最少请求数不能同时为 0。', + requestCountLimit: '计算后的单测点请求数不能超过 1000000。', + contextExceeded: '输入 Token、输出 Token 与模板预留之和超过上下文上限。', + planLimit: '需要 1–100 个场景,展开后的测点总数不能超过 2000。', + + caCertHelp: '选择主节点服务器上的 CA 证书文件,用于校验 HTTPS 服务;留空使用系统证书。', + extraBody: '额外请求体', + entryKey: '参数名', + entryValue: '参数值', + tokenizerMode: '分词器模式', + requireIdle: '开始前检查服务空闲', + requireIdleHelp: '在预热和压测前检查一次 /metrics。服务忙或无法确认空闲时停止;不能阻止测试期间的其他流量。', + trustRemoteCode: '信任远程代码', + trustRemoteCodeHelp: '允许在压测容器内执行模型仓库的自定义分词器代码。仅在需要且来源可信时开启。', + tokenizerModes: { auto: '自动(推荐)', slow: '慢速分词器', mistral: 'Mistral 专用' }, + quickDescription: '单请求验证服务连通性与测量流程。', + regularDescription: '短、中、长三类负载,适合日常性能测试。', + fullDescription: '多场景、多并发与重复测量,包含长输入和共享前缀。', + customDescription: '从一个场景开始,按需设置参数并添加场景。', + scenarios: '场景', + builtIn: '内置', + builtInHelp: '内置方案不可编辑或删除,可在创建测试时调整本次配置。', + modified: '已调整', + + imageExists: '本机已存在', + imageNeedsPull: '需拉取', + remark: '备注', + source: '本机服务', + mode: '测试方案', + quick: '快速验证', + regular: '常规测试', + full: '完整测试', + custom: '自定义', + addScenario: '添加场景', + advanced: '高级配置', + points: '测点', + warmups: '预热请求数', + fixedRequests: '固定请求数', + multiplier: '请求数并发倍数', + minRequests: '最少请求数', + trials: '重复次数', + prefixRatio: '公共前缀比例', + totalTimeout: '整轮超时(秒)', + prepareTimeout: '准备超时(秒)', + interval: '测点间隔(秒)', + context: '上下文上限(0 表示未知)', + reserve: '模板预留 Token', + storage: '存储上限(MiB)', + stopOnError: '遇到错误停止后续测点', + caCert: 'CA 证书路径', + validTrials: '有效 / 总次数', + retry: '补测选中测点', + environment: '执行环境', + plan: '冻结配置', + clientHelp: '压测容器在主节点运行,向已有服务发送请求。不会启动推理服务,也不需要分配 GPU。', + retryHelp: '本轮只补测选中的异常测点,保留参数并重新分配随机种子。', + secretHelp: '复制配置不包含 API Key 和请求头,请按需重新填写。', + resultHelp: + '汇总仅使用成功且无请求异常的重复测试,显示中位数和最小/最大值。P99 是每次测试 P99 的中位数;缓存和外部流量未受控。', + }, + benchmarkOverview: { + noResults: '没有有效的测试结果,请查看失败原因和日志。', + noGroupResults: '此组合没有有效结果,请切换场景或并发数。', + partial: '部分结果:本次测试未完整成功,指标仅代表有效测点。', + highlights: '核心指标', + aggregate: '当前组合的有效重复测试中位数;点击指标查看统计详情。', + trend: '并发趋势', + std: '标准差', + min: '最小值', + max: '最大值', + tpot: '单 Token 耗时', + tpotHelp: '首 Token 之后,每个输出 Token 的平均生成耗时。', + itl: 'Token 间延迟', + itlHelp: '流式响应中相邻 Token 返回的时间间隔。', + e2el: '端到端延迟', + e2elHelp: '从请求发出到完整响应接收完成的时间。', + requestHelp: '每秒完成的请求数。', + usageHelp: + '仅统计当前组合的有效重复测试,数值为每次测试结果的中位数,不是整轮请求总计;异常测点请在测点页查看。', + duration: '测试耗时', + throughput: '吞吐指标', + latency: '延迟指标', + usage: '请求与用量(有效测试)', + }, + benchmarkTokenizer: { + title: '分词器管理', + local: '登记本地目录', + upload: '上传分词器包', + uploadHelp: '上传 ZIP / tar.gz 分词器包,不含模型权重。压缩包最大 128 MiB,解压后最大 256 MiB。', + source: '导入方式', + deleteLocal: '移除分词器「{0}」的登记记录?原目录和文件将保留。', + deleteUpload: '删除分词器「{0}」及其上传文件?历史测试报告将保留。', + select: '选择分词器', + selectHelp: '离线环境推荐从管理列表选择;自定义输入仍支持本地目录或仓库名称。', + }, container: { createByCommand: '命令创建', importContainerBackupTip: '导入容器备份文件,仅支持 .tar.gz 格式', diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 1761725fd..d43eb9e98 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,4 +1,5 @@ import { resolve } from 'path'; +import { benchmarkReportPlugin } from './build/benchmark-report'; import { wrapperEnv } from './src/utils/get-env'; import viteCompression from 'vite-plugin-compression'; import eslintPlugin from 'vite-plugin-eslint2'; @@ -99,6 +100,7 @@ export default defineConfig(async ({ mode }: ConfigEnv): Promise => }, }, plugins: [ + benchmarkReportPlugin(__dirname), patchCodeFilterOverflow(), vue(), eslintPlugin({