From 5a34f382f4a0459993f25d91a6cb96f6b7cae3d2 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 15:03:22 +0300 Subject: [PATCH 01/16] feat(dashboard): models and combos catalog with filters and health tests --- .../dashboard/models/CatalogBulkActionBar.tsx | 90 ++ .../dashboard/models/CatalogTestBadge.tsx | 81 ++ .../dashboard/models/ComboCatalogFilters.tsx | 131 +++ .../dashboard/models/ComboCatalogTable.tsx | 265 ++++++ .../dashboard/models/ModelCatalogFilters.tsx | 184 ++++ .../dashboard/models/ModelCatalogTable.tsx | 104 ++- .../dashboard/models/catalogTestStorage.ts | 148 +++ .../dashboard/models/comboCatalogUtils.ts | 206 +++++ .../dashboard/models/modelCatalogUtils.ts | 108 ++- src/app/(dashboard)/dashboard/models/page.tsx | 860 ++++++++++++++---- .../dashboard/models/useCatalogTestRunner.ts | 428 +++++++++ .../constants/sidebarVisibility/sections.ts | 4 +- .../dashboard/catalogTestStorage.test.tsx | 171 ++++ .../unit/dashboard/comboCatalogUtils.test.tsx | 271 ++++++ .../unit/dashboard/modelCatalogUtils.test.tsx | 147 ++- .../dashboard/modelsCombosCatalog.test.tsx | 372 ++++++++ 16 files changed, 3380 insertions(+), 190 deletions(-) create mode 100644 src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx create mode 100644 src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx create mode 100644 src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx create mode 100644 src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx create mode 100644 src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx create mode 100644 src/app/(dashboard)/dashboard/models/catalogTestStorage.ts create mode 100644 src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts create mode 100644 src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts create mode 100644 tests/unit/dashboard/catalogTestStorage.test.tsx create mode 100644 tests/unit/dashboard/comboCatalogUtils.test.tsx create mode 100644 tests/unit/dashboard/modelsCombosCatalog.test.tsx diff --git a/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx new file mode 100644 index 000000000000..56508db69fc0 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx @@ -0,0 +1,90 @@ +"use client"; + +import { Button } from "@/shared/components"; +import type { ProgressState } from "./useCatalogTestRunner"; + +export default function CatalogBulkActionBar({ + selectedCount, + filteredCount, + running, + progress, + hasTestResults, + onTestSelected, + onTestFiltered, + onCancel, + onClearResults, + entityLabel: _entityLabel = "models", +}: { + selectedCount: number; + filteredCount: number; + running: boolean; + progress: ProgressState; + hasTestResults: boolean; + onTestSelected: () => void; + onTestFiltered: () => void; + onCancel: () => void; + onClearResults: () => void; + entityLabel?: "models" | "combos"; +}) { + const percent = progress.total > 0 ? Math.round((progress.completed / progress.total) * 100) : 0; + + return ( +
+
+ + + + {running && ( + + )} + + {hasTestResults && !running && ( + + )} +
+ + {running && ( +
+
+
+
+ + {progress.message || `${percent}%`} + +
+ )} +
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx new file mode 100644 index 000000000000..3050aec1c029 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx @@ -0,0 +1,81 @@ +"use client"; + +import { Badge } from "@/shared/components"; +import type { CatalogTestResult } from "./catalogTestStorage"; + +function formatLatency(ms?: number): string { + if (typeof ms !== "number" || Number.isNaN(ms)) return ""; + if (ms < 1000) return `${Math.round(ms)}ms`; + return `${(ms / 1000).toFixed(1)}s`; +} + +function formatTimeAgo(timestamp?: number): string { + if (!timestamp) return ""; + const diffSec = Math.floor((Date.now() - timestamp) / 1000); + if (diffSec < 60) return "Just now"; + const diffMin = Math.floor(diffSec / 60); + if (diffMin < 60) return `${diffMin}m ago`; + const diffHours = Math.floor(diffMin / 60); + if (diffHours < 24) return `${diffHours}h ago`; + return new Date(timestamp).toLocaleDateString(); +} + +export default function CatalogTestBadge({ + result, + loading = false, +}: { + result?: CatalogTestResult; + loading?: boolean; +}) { + if (loading) { + return ( +
+
+ ); + } + + if (!result) { + return ( + + — + + ); + } + + const variant = + result.status === "ok" ? "success" : result.status === "slow" ? "warning" : "error"; + + const label = + result.status === "ok" + ? "OK" + : result.status === "slow" + ? "Slow" + : result.errorClass + ? result.errorClass.replace("-", " ") + : "Error"; + + const latencyStr = formatLatency(result.latencyMs); + const timeStr = formatTimeAgo(result.testedAt); + + return ( +
+
+ + {label} + + {latencyStr && ( + {latencyStr} + )} +
+ {timeStr && {timeStr}} +
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx new file mode 100644 index 000000000000..de950611e392 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx @@ -0,0 +1,131 @@ +"use client"; + +import { Button, Input } from "@/shared/components"; +import type { ComboCatalogFilters } from "./comboCatalogUtils"; + +function humanize(value: string): string { + return value + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replaceAll(/[_-]+/g, " ") + .replace(/^\w/, (first) => first.toUpperCase()); +} + +export default function ComboCatalogFiltersComponent({ + filters, + onChange, + onClear, + strategyOptions, + hasActiveFilters, + totalCount, +}: { + filters: ComboCatalogFilters; + onChange: (patch: Partial) => void; + onClear: () => void; + strategyOptions: string[]; + hasActiveFilters: boolean; + totalCount: number; +}) { + return ( +
+
+ onChange({ query: event.target.value })} + className="min-w-0 flex-1" + /> + +
+ + {totalCount} {totalCount === 1 ? "combo" : "combos"} + + {hasActiveFilters && ( + + )} +
+
+ +
+ + + + + + + + + +
+
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx new file mode 100644 index 000000000000..769977d794b3 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx @@ -0,0 +1,265 @@ +"use client"; + +import { Badge, Button } from "@/shared/components"; +import CatalogTestBadge from "./CatalogTestBadge"; +import type { CatalogTestResult } from "./catalogTestStorage"; +import { getComboTestKey } from "./catalogTestStorage"; +import type { ComboCatalogRow, ComboSortDirection, ComboSortField } from "./comboCatalogUtils"; + +function formatCount(value: number): string { + return new Intl.NumberFormat().format(value); +} + +function humanize(value: string): string { + return value + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replaceAll(/[_-]+/g, " ") + .replace(/^\w/, (first) => first.toUpperCase()); +} + +function SortableHeading({ + field, + label, + activeField, + direction, + onSort, +}: { + field: ComboSortField; + label: string; + activeField: ComboSortField; + direction: ComboSortDirection; + onSort: (field: ComboSortField) => void; +}) { + const active = field === activeField; + return ( + + + + ); +} + +export default function ComboCatalogTable({ + rows, + sortField, + sortDirection, + onSort, + page, + pageCount, + startIndex, + totalCount, + selectedIds, + onToggleSelect, + onToggleSelectAll, + testResults, + activeTestingKey, + onTestCombo, + onPrevious, + onNext, +}: { + rows: ComboCatalogRow[]; + sortField: ComboSortField; + sortDirection: ComboSortDirection; + onSort: (field: ComboSortField) => void; + page: number; + pageCount: number; + startIndex: number; + totalCount: number; + selectedIds: Set; + onToggleSelect: (id: string) => void; + onToggleSelectAll: () => void; + testResults: Record; + activeTestingKey: string | null; + onTestCombo: (comboName: string) => void; + onPrevious: () => void; + onNext: () => void; +}) { + const allOnPageSelected = rows.length > 0 && rows.every((row) => selectedIds.has(row.id)); + const someOnPageSelected = rows.some((row) => selectedIds.has(row.id)) && !allOnPageSelected; + + const firstResult = startIndex + 1; + const lastResult = startIndex + rows.length; + + return ( + <> +
+ + + + + + + + + + + + + + + {rows.map((combo) => { + const isSelected = selectedIds.has(combo.id); + const testKey = getComboTestKey(combo.name); + const isTesting = activeTestingKey === testKey; + const result = testResults[testKey]; + + return ( + + + + + + + + + + ); + })} + +
Combos catalog with health test results
+ { + if (el) el.indeterminate = someOnPageSelected; + }} + onChange={onToggleSelectAll} + aria-label="Select all combos on this page" + className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" + /> + + Health Test + + Actions +
+ onToggleSelect(combo.id)} + aria-label={`Select combo ${combo.name}`} + className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" + /> + +
{combo.displayName}
+ {combo.displayName !== combo.name && ( + {combo.name} + )} + {combo.description && ( +

+ {combo.description} +

+ )} +
+ + {humanize(combo.strategy)} + + + + {combo.memberCount} {combo.memberCount === 1 ? "model" : "models"} + + {combo.models.length > 0 && ( +
+ {combo.models.slice(0, 3).map((m, idx) => ( + + {m.label || m.model.split("/").pop()} + + ))} + {combo.models.length > 3 && ( + + +{combo.models.length - 3} more + + )} +
+ )} +
+ + {combo.status === "active" ? "Active" : "Paused"} + + + + + +
+
+ +
+

+ Showing {formatCount(firstResult)}–{formatCount(lastResult)} of {formatCount(totalCount)} + {" combos"} +

+
+ + Page {page} of {pageCount} + + + +
+
+ + ); +} diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx new file mode 100644 index 000000000000..c3465885199b --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx @@ -0,0 +1,184 @@ +"use client"; + +import { Button, Input } from "@/shared/components"; +import type { CatalogFilters } from "./modelCatalogUtils"; + +function humanize(value: string): string { + return value + .replace(/([a-z])([A-Z])/g, "$1 $2") + .replaceAll(/[_-]+/g, " ") + .replace(/^\w/, (first) => first.toUpperCase()); +} + +export default function ModelCatalogFiltersComponent({ + filters, + onChange, + onClear, + providerOptions, + typeOptions, + subtypeOptions, + capabilityOptions, + hasActiveFilters, + totalCount, +}: { + filters: CatalogFilters; + onChange: (patch: Partial) => void; + onClear: () => void; + providerOptions: Array<[string, string]>; + typeOptions: string[]; + subtypeOptions: string[]; + capabilityOptions: string[]; + hasActiveFilters: boolean; + totalCount: number; +}) { + return ( +
+
+ onChange({ query: event.target.value })} + className="min-w-0 flex-1" + /> + +
+ + {totalCount} {totalCount === 1 ? "model" : "models"} + + {hasActiveFilters && ( + + )} +
+
+ +
+ + + + + + + + + + + + + + + +
+
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx index fa4e480b18e2..724f91b2c318 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx @@ -1,4 +1,7 @@ import { Badge, Button } from "@/shared/components"; +import CatalogTestBadge from "./CatalogTestBadge"; +import type { CatalogTestResult } from "./catalogTestStorage"; +import { getModelTestKey } from "./catalogTestStorage"; import type { CatalogModelRow, CatalogSortDirection, CatalogSortField } from "./modelCatalogUtils"; function formatCount(value: number): string { @@ -80,6 +83,13 @@ export default function ModelCatalogTable({ onPrevious, onNext, labels, + selectedIds = new Set(), + onToggleSelect, + onToggleSelectAll, + testResults = {}, + activeTestingKey = null, + onTestModel, + providerHealthMap = {}, }: { rows: CatalogModelRow[]; sortField: CatalogSortField; @@ -104,17 +114,42 @@ export default function ModelCatalogTable({ custom: string; free: string; }; + selectedIds?: Set; + onToggleSelect?: (id: string) => void; + onToggleSelectAll?: () => void; + testResults?: Record; + activeTestingKey?: string | null; + onTestModel?: (providerId: string, modelId: string) => void; + providerHealthMap?: Record; }) { const firstResult = startIndex + 1; const lastResult = startIndex + rows.length; + const rowIds = rows.map((r) => `${r.providerId}:${r.id}`); + const allOnPageSelected = rowIds.length > 0 && rowIds.every((id) => selectedIds.has(id)); + const someOnPageSelected = rowIds.some((id) => selectedIds.has(id)) && !allOnPageSelected; + return ( <>
- +
+ {onToggleSelectAll && ( + + )} {labels.flags} + + {onTestModel && ( + + )} {rows.map((model) => { + const rowId = `${model.providerId}:${model.id}`; + const isSelected = selectedIds.has(rowId); + const testKey = getModelTestKey(model.providerId, model.id); + const isTesting = activeTestingKey === testKey; + const result = testResults[testKey]; + const providerHealth = providerHealthMap[model.providerId]; + const capabilities = capabilityLabels(model); const additionalCapabilities = capabilities.slice(3); return ( + {onToggleSelect && ( + + )} + + {onTestModel && ( + + )} ); })} diff --git a/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts b/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts new file mode 100644 index 000000000000..e0ed9aa6a7b5 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts @@ -0,0 +1,148 @@ +export const CATALOG_TEST_RESULTS_KEY = "omniroute.catalogTestResults.v1"; +export const MAX_TEST_RESULTS_CAP = 2000; + +export type CatalogTestStatus = "ok" | "slow" | "error"; +export type CatalogTestErrorClass = "rate-limited" | "quota" | "timeout" | "other"; + +export interface CatalogTestResult { + id: string; + targetType: "model" | "combo"; + providerId?: string; + modelId?: string; + comboName?: string; + status: CatalogTestStatus; + latencyMs?: number; + testedAt: number; + error?: string; + errorClass?: CatalogTestErrorClass; + statusCode?: number; +} + +export function getModelTestKey(providerId: string, modelId: string): string { + return `model:${providerId}:${modelId}`; +} + +export function getComboTestKey(comboName: string): string { + return `combo:${comboName}`; +} + +export function classifyError( + error?: string, + statusCode?: number, + flags?: { rateLimited?: boolean; isQuota?: boolean; isTimeout?: boolean } +): CatalogTestErrorClass | undefined { + if (flags?.rateLimited || statusCode === 429 || /rate.?limit|429/i.test(error ?? "")) { + return "rate-limited"; + } + if (flags?.isQuota || /quota|insufficient balance|credit|billing|exhausted/i.test(error ?? "")) { + return "quota"; + } + if ( + flags?.isTimeout || + statusCode === 408 || + statusCode === 504 || + /timeout|timed out|abort/i.test(error ?? "") + ) { + return "timeout"; + } + if (error || statusCode) { + return "other"; + } + return undefined; +} + +export function normalizeTestStatus(status: string, latencyMs?: number): CatalogTestStatus { + if (status === "slow") return "slow"; + if (status === "ok") { + if (typeof latencyMs === "number" && latencyMs >= 5000) { + return "slow"; + } + return "ok"; + } + return "error"; +} + +export function capTestResults( + results: Record, + max = MAX_TEST_RESULTS_CAP +): Record { + const entries = Object.entries(results); + if (entries.length <= max) return results; + + // Keep newest entries first + entries.sort(([, a], [, b]) => (b.testedAt || 0) - (a.testedAt || 0)); + const capped: Record = {}; + for (let index = 0; index < max; index++) { + capped[entries[index][0]] = entries[index][1]; + } + return capped; +} + +export function loadCatalogTestResults(): Record { + if (typeof window === "undefined" || !window.localStorage) { + return {}; + } + try { + const raw = window.localStorage.getItem(CATALOG_TEST_RESULTS_KEY); + if (!raw) return {}; + const parsed: unknown = JSON.parse(raw); + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + return {}; + } + const sanitized: Record = {}; + for (const [key, value] of Object.entries(parsed as Record)) { + if ( + value && + typeof value === "object" && + !Array.isArray(value) && + "status" in value && + typeof (value as { status: unknown }).status === "string" + ) { + sanitized[key] = value as CatalogTestResult; + } + } + return sanitized; + } catch { + return {}; + } +} + +export function saveCatalogTestResults( + results: Record +): Record { + const capped = capTestResults(results); + if (typeof window !== "undefined" && window.localStorage) { + try { + window.localStorage.setItem(CATALOG_TEST_RESULTS_KEY, JSON.stringify(capped)); + } catch { + // Ignore quota errors or storage restrictions + } + } + return capped; +} + +export function saveSingleTestResult(result: CatalogTestResult): Record { + const current = loadCatalogTestResults(); + current[result.id] = result; + return saveCatalogTestResults(current); +} + +export function saveBatchTestResults( + results: CatalogTestResult[] +): Record { + const current = loadCatalogTestResults(); + for (const result of results) { + current[result.id] = result; + } + return saveCatalogTestResults(current); +} + +export function clearCatalogTestResults(): void { + if (typeof window !== "undefined" && window.localStorage) { + try { + window.localStorage.removeItem(CATALOG_TEST_RESULTS_KEY); + } catch { + // Ignore + } + } +} diff --git a/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts b/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts new file mode 100644 index 000000000000..b50cffc13c46 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts @@ -0,0 +1,206 @@ +import type { CatalogTestResult } from "./catalogTestStorage"; +import { getComboTestKey } from "./catalogTestStorage"; + +export interface ComboCatalogStep { + model: string; + provider?: string; + connectionId?: string; + weight?: number; + label?: string; +} + +export interface ComboCatalogRow { + id: string; + name: string; + displayName: string; + strategy: string; + description?: string; + models: ComboCatalogStep[]; + memberCount: number; + status: "active" | "paused"; + contextLength?: number; +} + +export interface ComboCatalogFilters { + query: string; + strategy: string; + status: string; + minMembers?: number; + maxMembers?: number; + testResult: string; +} + +export type ComboSortField = "name" | "strategy" | "memberCount" | "status"; +export type ComboSortDirection = "asc" | "desc"; + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +export function flattenCombos(rawCombos: unknown): ComboCatalogRow[] { + if (!Array.isArray(rawCombos)) return []; + + const rows: ComboCatalogRow[] = []; + for (const item of rawCombos) { + if (!isRecord(item)) continue; + + const id = typeof item.id === "string" ? item.id : String(item.name || ""); + const name = typeof item.name === "string" ? item.name : ""; + if (!name) continue; + + const displayName = + typeof item.displayName === "string" && item.displayName.trim().length > 0 + ? item.displayName + : name; + + const strategy = typeof item.strategy === "string" ? item.strategy : "priority"; + const description = typeof item.description === "string" ? item.description : undefined; + + const modelsList: ComboCatalogStep[] = []; + if (Array.isArray(item.models)) { + for (const m of item.models) { + if (typeof m === "string") { + modelsList.push({ model: m }); + } else if (isRecord(m) && typeof m.model === "string") { + modelsList.push({ + model: m.model, + provider: typeof m.provider === "string" ? m.provider : undefined, + connectionId: typeof m.connectionId === "string" ? m.connectionId : undefined, + weight: typeof m.weight === "number" ? m.weight : undefined, + label: typeof m.label === "string" ? m.label : undefined, + }); + } + } + } + + const isInactive = + item.isActive === false || item.enabled === false || item.status === "paused"; + const status: "active" | "paused" = isInactive ? "paused" : "active"; + + const contextLength = + typeof item.context_length === "number" + ? item.context_length + : typeof item.computed_context_length === "number" + ? item.computed_context_length + : undefined; + + rows.push({ + id, + name, + displayName, + strategy, + description, + models: modelsList, + memberCount: modelsList.length, + status, + contextLength, + }); + } + + return rows; +} + +function searchableComboText(combo: ComboCatalogRow): string { + const parts = [ + combo.name, + combo.displayName, + combo.strategy, + combo.description ?? "", + ...combo.models.flatMap((m) => [m.model, m.provider ?? "", m.label ?? ""]), + ]; + return parts.filter(Boolean).join(" ").toLocaleLowerCase(); +} + +export function filterCatalogCombos( + combos: ComboCatalogRow[], + filters: ComboCatalogFilters, + testResults: Record = {} +): ComboCatalogRow[] { + const query = filters.query.trim().toLocaleLowerCase(); + + return combos.filter((combo) => { + if (filters.strategy !== "all" && combo.strategy !== filters.strategy) { + return false; + } + + if (filters.status !== "all" && combo.status !== filters.status) { + return false; + } + + if ( + typeof filters.minMembers === "number" && + !Number.isNaN(filters.minMembers) && + combo.memberCount < filters.minMembers + ) { + return false; + } + + if ( + typeof filters.maxMembers === "number" && + !Number.isNaN(filters.maxMembers) && + combo.memberCount > filters.maxMembers + ) { + return false; + } + + if (filters.testResult !== "all") { + const testKey = getComboTestKey(combo.name); + const test = testResults[testKey]; + const resultStatus = test ? test.status : "untested"; + if (resultStatus !== filters.testResult) { + return false; + } + } + + if (query !== "" && !searchableComboText(combo).includes(query)) { + return false; + } + + return true; + }); +} + +function compareText(left: string, right: string): number { + const normalizedLeft = left.toLocaleLowerCase(); + const normalizedRight = right.toLocaleLowerCase(); + return normalizedLeft < normalizedRight ? -1 : normalizedLeft > normalizedRight ? 1 : 0; +} + +export function sortCatalogCombos( + combos: ComboCatalogRow[], + field: ComboSortField, + direction: ComboSortDirection +): ComboCatalogRow[] { + const multiplier = direction === "asc" ? 1 : -1; + return [...combos].sort((left, right) => { + if (field === "memberCount") { + const diff = left.memberCount - right.memberCount; + if (diff !== 0) return diff * multiplier; + } else { + const leftVal = String(left[field] ?? ""); + const rightVal = String(right[field] ?? ""); + const comp = compareText(leftVal, rightVal); + if (comp !== 0) return comp * multiplier; + } + return compareText(left.name, right.name); + }); +} + +export function getComboCatalogPage( + rows: T[], + requestedPage: number, + requestedPageSize: number +): { rows: T[]; page: number; pageCount: number } { + const pageSize = + Number.isFinite(requestedPageSize) && requestedPageSize > 0 ? requestedPageSize : 50; + const pageCount = Math.ceil(rows.length / pageSize); + if (pageCount === 0) return { rows: [], page: 0, pageCount: 0 }; + + const safePage = Number.isFinite(requestedPage) ? Math.floor(requestedPage) : 0; + const page = Math.min(Math.max(0, safePage), pageCount - 1); + return { + rows: rows.slice(page * pageSize, (page + 1) * pageSize), + page, + pageCount, + }; +} diff --git a/src/app/(dashboard)/dashboard/models/modelCatalogUtils.ts b/src/app/(dashboard)/dashboard/models/modelCatalogUtils.ts index 88f766f830e9..88445c07eb50 100644 --- a/src/app/(dashboard)/dashboard/models/modelCatalogUtils.ts +++ b/src/app/(dashboard)/dashboard/models/modelCatalogUtils.ts @@ -1,3 +1,7 @@ +import { isFreeModel } from "@/shared/utils/freeModels"; +import type { CatalogTestResult } from "./catalogTestStorage"; +import { getModelTestKey } from "./catalogTestStorage"; + export interface CatalogModel { id: string; name: string; @@ -25,12 +29,28 @@ export interface CatalogFilters { query: string; providerId: string; type: string; + subtype?: string; + capability?: string; + minContextLength?: number; + minMaxOutputTokens?: number; + pricing?: string; // "all" | "free" | "paid" + providerHealth?: string; // "all" | "healthy" | "degraded" | "down" + testResult?: string; // "all" | "untested" | "ok" | "slow" | "error" +} + +export interface CatalogFilterOptions { + providerHealthMap?: Record; + testResults?: Record; } function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } +function isString(value: unknown): value is string { + return typeof value === "string"; +} + /** Convert the provider-grouped API payload into stable rows for the dashboard table. */ export function flattenCatalog(catalog: unknown): CatalogModelRow[] { if (!isRecord(catalog)) return []; @@ -75,8 +95,47 @@ export function flattenCatalog(catalog: unknown): CatalogModelRow[] { return rows; } -function isString(value: unknown): value is string { - return typeof value === "string"; +export function extractCatalogCapabilities(models: CatalogModelRow[]): string[] { + const caps = new Set(); + for (const model of models) { + if (model.capabilities) { + for (const [key, value] of Object.entries(model.capabilities)) { + if (value === true) { + caps.add(key.toLowerCase()); + } else if (Array.isArray(value)) { + for (const item of value) { + if (typeof item === "string" && item.trim()) { + caps.add(item.toLowerCase()); + } + } + } + } + } + } + return [...caps].sort((left, right) => left.localeCompare(right)); +} + +function modelHasCapability(model: CatalogModelRow, targetCap: string): boolean { + if (!model.capabilities) return false; + const target = targetCap.toLowerCase(); + for (const [key, value] of Object.entries(model.capabilities)) { + if (key.toLowerCase() === target && value === true) return true; + if (Array.isArray(value)) { + if (value.some((item) => typeof item === "string" && item.toLowerCase() === target)) { + return true; + } + } + } + return false; +} + +export function isModelFree(model: CatalogModelRow): boolean { + if (model.free === true) return true; + try { + return isFreeModel(model.providerId, { id: model.id }); + } catch { + return false; + } } function searchableText(model: CatalogModelRow): string { @@ -102,12 +161,55 @@ function searchableText(model: CatalogModelRow): string { export function filterCatalogModels( models: CatalogModelRow[], - filters: CatalogFilters + filters: CatalogFilters, + options: CatalogFilterOptions = {} ): CatalogModelRow[] { const query = filters.query.trim().toLocaleLowerCase(); + const { providerHealthMap = {}, testResults = {} } = options; + return models.filter((model) => { if (filters.providerId !== "all" && model.providerId !== filters.providerId) return false; if (filters.type !== "all" && model.type !== filters.type) return false; + if (filters.subtype && filters.subtype !== "all" && model.subtype !== filters.subtype) { + return false; + } + if (filters.capability && filters.capability !== "all") { + if (!modelHasCapability(model, filters.capability)) return false; + } + if (typeof filters.minContextLength === "number" && !Number.isNaN(filters.minContextLength)) { + if ( + typeof model.context_length !== "number" || + model.context_length < filters.minContextLength + ) { + return false; + } + } + if ( + typeof filters.minMaxOutputTokens === "number" && + !Number.isNaN(filters.minMaxOutputTokens) + ) { + if ( + typeof model.max_output_tokens !== "number" || + model.max_output_tokens < filters.minMaxOutputTokens + ) { + return false; + } + } + if (filters.pricing && filters.pricing !== "all") { + const free = isModelFree(model); + if (filters.pricing === "free" && !free) return false; + if (filters.pricing === "paid" && free) return false; + } + if (filters.providerHealth && filters.providerHealth !== "all") { + const health = providerHealthMap[model.providerId] ?? "healthy"; + if (health !== filters.providerHealth) return false; + } + if (filters.testResult && filters.testResult !== "all") { + const testKey = getModelTestKey(model.providerId, model.id); + const test = testResults[testKey]; + const resultStatus = test ? test.status : "untested"; + if (resultStatus !== filters.testResult) return false; + } return query === "" || searchableText(model).includes(query); }); } diff --git a/src/app/(dashboard)/dashboard/models/page.tsx b/src/app/(dashboard)/dashboard/models/page.tsx index cf39486cfa9c..6cadfa06949a 100644 --- a/src/app/(dashboard)/dashboard/models/page.tsx +++ b/src/app/(dashboard)/dashboard/models/page.tsx @@ -3,17 +3,34 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useTranslations } from "next-intl"; -import { Button, Card, Input } from "@/shared/components"; +import { Button, Card } from "@/shared/components"; +import CatalogBulkActionBar from "./CatalogBulkActionBar"; +import ComboCatalogFiltersComponent from "./ComboCatalogFilters"; +import ComboCatalogTable from "./ComboCatalogTable"; import { + filterCatalogCombos, + flattenCombos, + getComboCatalogPage, + sortCatalogCombos, + type ComboCatalogFilters, + type ComboCatalogRow, + type ComboSortDirection, + type ComboSortField, +} from "./comboCatalogUtils"; +import ModelCatalogFiltersComponent from "./ModelCatalogFilters"; +import ModelCatalogTable from "./ModelCatalogTable"; +import { + extractCatalogCapabilities, filterCatalogModels, flattenCatalog, getCatalogPage, sortCatalogModels, + type CatalogFilters, type CatalogModelRow, type CatalogSortDirection, type CatalogSortField, } from "./modelCatalogUtils"; -import ModelCatalogTable from "./ModelCatalogTable"; +import { useCatalogTestRunner } from "./useCatalogTestRunner"; const PAGE_SIZE = 50; @@ -23,239 +40,734 @@ function commonText(translator: Translator, key: string, fallback: string): stri return typeof translator.has === "function" && translator.has(key) ? translator(key) : fallback; } +type CatalogTab = "models" | "combos"; + +function getUrlParams(): URLSearchParams { + if (typeof window !== "undefined") { + return new URLSearchParams(window.location.search); + } + return new URLSearchParams(); +} + +function setUrlParams(params: URLSearchParams) { + if (typeof window !== "undefined") { + const query = params.toString(); + const newUrl = query ? `${window.location.pathname}?${query}` : window.location.pathname; + window.history.replaceState(null, "", newUrl); + } +} + +function parseInitialModelFilters(params: URLSearchParams): CatalogFilters { + return { + query: params.get("query") || "", + providerId: params.get("provider") || "all", + type: params.get("type") || "all", + subtype: params.get("subtype") || "all", + capability: params.get("capability") || "all", + pricing: params.get("pricing") || "all", + providerHealth: params.get("health") || "all", + testResult: params.get("testResult") || "all", + minContextLength: params.get("minContext") ? Number(params.get("minContext")) : undefined, + minMaxOutputTokens: params.get("minOutput") ? Number(params.get("minOutput")) : undefined, + }; +} + +function parseInitialComboFilters( + params: URLSearchParams, + tabParam: string | null +): ComboCatalogFilters { + return { + query: params.get("cQuery") || (tabParam === "combos" ? params.get("query") || "" : ""), + strategy: params.get("strategy") || "all", + status: params.get("status") || "all", + testResult: + params.get("cTestResult") || + (tabParam === "combos" ? params.get("testResult") || "all" : "all"), + minMembers: params.get("minMembers") ? Number(params.get("minMembers")) : undefined, + maxMembers: params.get("maxMembers") ? Number(params.get("maxMembers")) : undefined, + }; +} + export default function ModelCatalogPage() { const commonTranslator = useTranslations("common") as unknown as Translator; - const providersTranslator = useTranslations("providers") as unknown as Translator; + + // Active Tab + const [activeTab, setActiveTab] = useState(() => { + const params = getUrlParams(); + const tabParam = params.get("tab"); + return tabParam === "combos" ? "combos" : "models"; + }); + + // Models State const [models, setModels] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(false); - const [query, setQuery] = useState(""); - const [providerId, setProviderId] = useState("all"); - const [modelType, setModelType] = useState("all"); - const [sortField, setSortField] = useState("provider"); - const [sortDirection, setSortDirection] = useState("asc"); - const [requestedPage, setRequestedPage] = useState(0); + const [modelsLoading, setModelsLoading] = useState(true); + const [modelsError, setModelsError] = useState(false); + const [modelSortField, setModelSortField] = useState("provider"); + const [modelSortDirection, setModelSortDirection] = useState("asc"); + const [requestedModelPage, setRequestedModelPage] = useState(0); + const [selectedModelIds, setSelectedModelIds] = useState>(new Set()); + + // Combos State + const [combos, setCombos] = useState([]); + const [combosLoading, setCombosLoading] = useState(true); + const [combosError, setCombosError] = useState(false); + const [comboSortField, setComboSortField] = useState("name"); + const [comboSortDirection, setComboSortDirection] = useState("asc"); + const [requestedComboPage, setRequestedComboPage] = useState(0); + const [selectedComboIds, setSelectedComboIds] = useState>(new Set()); + + // Provider Health State + const [providerHealthMap, setProviderHealthMap] = useState< + Record + >({}); + + // Model Filters + const [modelFilters, setModelFilters] = useState(() => + parseInitialModelFilters(getUrlParams()) + ); + + // Combo Filters + const [comboFilters, setComboFilters] = useState(() => { + const params = getUrlParams(); + return parseInitialComboFilters(params, params.get("tab")); + }); + + // Test Runner Hook + const { + testResults, + running, + activeItemKey, + progress, + testSingleModel, + testSingleCombo, + testBulkModels, + testBulkCombos, + cancelTest, + clearResults, + } = useCatalogTestRunner(); + const requestController = useRef(null); - const loadCatalog = useCallback(async () => { + // Sync state with browser navigation (Back / Forward) + useEffect(() => { + const handlePopState = () => { + const params = getUrlParams(); + const tabParam = params.get("tab"); + setActiveTab(tabParam === "combos" ? "combos" : "models"); + setModelFilters(parseInitialModelFilters(params)); + setComboFilters(parseInitialComboFilters(params, tabParam)); + }; + + window.addEventListener("popstate", handlePopState); + return () => { + window.removeEventListener("popstate", handlePopState); + }; + }, []); + + // Sync state to URL search parameters + const syncUrlParams = useCallback( + (tab: CatalogTab, mFilters: CatalogFilters, cFilters: ComboCatalogFilters) => { + const params = new URLSearchParams(); + if (tab === "combos") { + params.set("tab", "combos"); + } + + if (tab === "models") { + if (mFilters.query) params.set("query", mFilters.query); + if (mFilters.providerId !== "all") params.set("provider", mFilters.providerId); + if (mFilters.type !== "all") params.set("type", mFilters.type); + if (mFilters.subtype && mFilters.subtype !== "all") params.set("subtype", mFilters.subtype); + if (mFilters.capability && mFilters.capability !== "all") + params.set("capability", mFilters.capability); + if (mFilters.pricing && mFilters.pricing !== "all") params.set("pricing", mFilters.pricing); + if (mFilters.providerHealth && mFilters.providerHealth !== "all") + params.set("health", mFilters.providerHealth); + if (mFilters.testResult && mFilters.testResult !== "all") + params.set("testResult", mFilters.testResult); + if (typeof mFilters.minContextLength === "number") + params.set("minContext", String(mFilters.minContextLength)); + if (typeof mFilters.minMaxOutputTokens === "number") + params.set("minOutput", String(mFilters.minMaxOutputTokens)); + } else { + if (cFilters.query) params.set("query", cFilters.query); + if (cFilters.strategy !== "all") params.set("strategy", cFilters.strategy); + if (cFilters.status !== "all") params.set("status", cFilters.status); + if (cFilters.testResult !== "all") params.set("testResult", cFilters.testResult); + if (typeof cFilters.minMembers === "number") + params.set("minMembers", String(cFilters.minMembers)); + if (typeof cFilters.maxMembers === "number") + params.set("maxMembers", String(cFilters.maxMembers)); + } + + setUrlParams(params); + }, + [] + ); + + const switchTab = (tab: CatalogTab) => { + setActiveTab(tab); + syncUrlParams(tab, modelFilters, comboFilters); + }; + + const updateModelFilters = (patch: Partial) => { + const updated = { ...modelFilters, ...patch }; + setModelFilters(updated); + setRequestedModelPage(0); + syncUrlParams("models", updated, comboFilters); + }; + + const clearModelFilters = () => { + const cleared: CatalogFilters = { + query: "", + providerId: "all", + type: "all", + subtype: "all", + capability: "all", + pricing: "all", + providerHealth: "all", + testResult: "all", + minContextLength: undefined, + minMaxOutputTokens: undefined, + }; + setModelFilters(cleared); + setRequestedModelPage(0); + syncUrlParams("models", cleared, comboFilters); + }; + + const updateComboFilters = (patch: Partial) => { + const updated = { ...comboFilters, ...patch }; + setComboFilters(updated); + setRequestedComboPage(0); + syncUrlParams("combos", modelFilters, updated); + }; + + const clearComboFilters = () => { + const cleared: ComboCatalogFilters = { + query: "", + strategy: "all", + status: "all", + testResult: "all", + minMembers: undefined, + maxMembers: undefined, + }; + setComboFilters(cleared); + setRequestedComboPage(0); + syncUrlParams("combos", modelFilters, cleared); + }; + + // Data Loading + const loadData = useCallback(async () => { requestController.current?.abort(); const controller = new AbortController(); requestController.current = controller; - try { - const response = await fetch("/api/models/catalog", { signal: controller.signal }); - if (!response.ok) throw new Error("catalog request failed"); - const payload: unknown = await response.json(); - const catalog = - typeof payload === "object" && payload !== null && "catalog" in payload - ? payload.catalog - : null; - setModels(flattenCatalog(catalog)); - setError(false); - } catch { - if (!controller.signal.aborted) setError(true); - } finally { - if (!controller.signal.aborted) setLoading(false); - } + // Load models + const fetchModels = async () => { + try { + const response = await fetch("/api/models/catalog", { signal: controller.signal }); + if (!response.ok) throw new Error("catalog request failed"); + const payload: unknown = await response.json(); + const catalog = + typeof payload === "object" && payload !== null && "catalog" in payload + ? (payload as { catalog: unknown }).catalog + : null; + setModels(flattenCatalog(catalog)); + setModelsError(false); + } catch { + if (!controller.signal.aborted) setModelsError(true); + } finally { + if (!controller.signal.aborted) setModelsLoading(false); + } + }; + + // Load combos + const fetchCombos = async () => { + try { + const response = await fetch("/api/combos", { signal: controller.signal }); + if (!response.ok) throw new Error("combos request failed"); + const payload: unknown = await response.json(); + const rawCombos = + typeof payload === "object" && payload !== null && "combos" in payload + ? (payload as { combos: unknown }).combos + : null; + setCombos(flattenCombos(rawCombos)); + setCombosError(false); + } catch { + if (!controller.signal.aborted) setCombosError(true); + } finally { + if (!controller.signal.aborted) setCombosLoading(false); + } + }; + + // Load provider health matrix + const fetchHealth = async () => { + try { + const response = await fetch("/api/providers/health-matrix", { signal: controller.signal }); + if (!response.ok) return; + const payload: unknown = await response.json(); + if (typeof payload === "object" && payload !== null && "providers" in payload) { + const list = ( + payload as { + providers: Array<{ provider: string; state: "healthy" | "degraded" | "down" }>; + } + ).providers; + const map: Record = {}; + for (const item of list || []) { + if (item.provider) map[item.provider] = item.state; + } + setProviderHealthMap(map); + } + } catch { + // Soft fail + } + }; + + await Promise.allSettled([fetchModels(), fetchCombos(), fetchHealth()]); }, []); useEffect(() => { - const initialFetch = window.setTimeout(() => { - void loadCatalog(); + const timer = window.setTimeout(() => { + void loadData(); }, 0); return () => { - window.clearTimeout(initialFetch); + window.clearTimeout(timer); requestController.current?.abort(); }; - }, [loadCatalog]); + }, [loadData]); - const refreshCatalog = useCallback(() => { - setLoading(true); - setError(false); - void loadCatalog(); - }, [loadCatalog]); + const refreshAll = useCallback(() => { + setModelsLoading(true); + setCombosLoading(true); + setModelsError(false); + setCombosError(false); + void loadData(); + }, [loadData]); + // Derived filter options for models const providerOptions = useMemo( () => - [...new Map(models.map((model) => [model.providerId, model.provider])).entries()].sort( + [...new Map(models.map((m) => [m.providerId, m.provider])).entries()].sort( ([left], [right]) => left.localeCompare(right) ), [models] ); const typeOptions = useMemo( + () => [...new Set(models.map((m) => m.type))].sort((a, b) => a.localeCompare(b)), + [models] + ); + const subtypeOptions = useMemo( () => - [...new Set(models.map((model) => model.type))].sort((left, right) => - left.localeCompare(right) + [...new Set(models.map((m) => m.subtype).filter((s): s is string => Boolean(s)))].sort( + (a, b) => a.localeCompare(b) ), [models] ); + const capabilityOptions = useMemo(() => extractCatalogCapabilities(models), [models]); + // Derived filter options for combos + const strategyOptions = useMemo( + () => [...new Set(combos.map((c) => c.strategy))].sort((a, b) => a.localeCompare(b)), + [combos] + ); + + // Filtered & Sorted Models const visibleModels = useMemo(() => { - const filtered = filterCatalogModels(models, { query, providerId, type: modelType }); - return sortCatalogModels(filtered, sortField, sortDirection); - }, [models, modelType, providerId, query, sortDirection, sortField]); - const page = getCatalogPage(visibleModels, requestedPage, PAGE_SIZE); - - const updateQuery = (value: string) => { - setQuery(value); - setRequestedPage(0); + const filtered = filterCatalogModels(models, modelFilters, { + providerHealthMap, + testResults, + }); + return sortCatalogModels(filtered, modelSortField, modelSortDirection); + }, [models, modelFilters, providerHealthMap, testResults, modelSortField, modelSortDirection]); + const modelPage = getCatalogPage(visibleModels, requestedModelPage, PAGE_SIZE); + + // Filtered & Sorted Combos + const visibleCombos = useMemo(() => { + const filtered = filterCatalogCombos(combos, comboFilters, testResults); + return sortCatalogCombos(filtered, comboSortField, comboSortDirection); + }, [combos, comboFilters, testResults, comboSortField, comboSortDirection]); + const comboPage = getComboCatalogPage(visibleCombos, requestedComboPage, PAGE_SIZE); + + // Selection handlers for models + const toggleSelectModel = (id: string) => { + setSelectedModelIds((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); + }; + + const toggleSelectAllModelsOnPage = () => { + const pageIds = modelPage.rows.map((r) => `${r.providerId}:${r.id}`); + const allSelected = pageIds.length > 0 && pageIds.every((id) => selectedModelIds.has(id)); + setSelectedModelIds((prev) => { + const next = new Set(prev); + if (allSelected) { + for (const id of pageIds) next.delete(id); + } else { + for (const id of pageIds) next.add(id); + } + return next; + }); }; - const updateProvider = (value: string) => { - setProviderId(value); - setRequestedPage(0); + // Selection handlers for combos + const toggleSelectCombo = (id: string) => { + setSelectedComboIds((prev) => { + const next = new Set(prev); + if (next.has(id)) next.delete(id); + else next.add(id); + return next; + }); }; - const updateType = (value: string) => { - setModelType(value); - setRequestedPage(0); + const toggleSelectAllCombosOnPage = () => { + const pageIds = comboPage.rows.map((r) => r.id); + const allSelected = pageIds.length > 0 && pageIds.every((id) => selectedComboIds.has(id)); + setSelectedComboIds((prev) => { + const next = new Set(prev); + if (allSelected) { + for (const id of pageIds) next.delete(id); + } else { + for (const id of pageIds) next.add(id); + } + return next; + }); }; - const handleSort = (field: CatalogSortField) => { - if (field === sortField) { - setSortDirection((current) => (current === "asc" ? "desc" : "asc")); + // Bulk test triggers + const handleTestSelected = () => { + if (activeTab === "models") { + const selected = models + .filter((m) => selectedModelIds.has(`${m.providerId}:${m.id}`)) + .map((m) => ({ providerId: m.providerId, modelId: m.id })); + void testBulkModels(selected); } else { - setSortField(field); - setSortDirection("asc"); + const selected = combos + .filter((c) => selectedComboIds.has(c.id)) + .map((c) => ({ comboName: c.name })); + void testBulkCombos(selected); } - setRequestedPage(0); }; + const handleTestAllFiltered = () => { + if (activeTab === "models") { + const toTest = visibleModels.map((m) => ({ + providerId: m.providerId, + modelId: m.id, + })); + void testBulkModels(toTest); + } else { + const toTest = visibleCombos.map((c) => ({ comboName: c.name })); + void testBulkCombos(toTest); + } + }; + + const hasModelFiltersActive = + modelFilters.query !== "" || + modelFilters.providerId !== "all" || + modelFilters.type !== "all" || + (modelFilters.subtype && modelFilters.subtype !== "all") || + (modelFilters.capability && modelFilters.capability !== "all") || + (modelFilters.pricing && modelFilters.pricing !== "all") || + (modelFilters.providerHealth && modelFilters.providerHealth !== "all") || + (modelFilters.testResult && modelFilters.testResult !== "all") || + typeof modelFilters.minContextLength === "number" || + typeof modelFilters.minMaxOutputTokens === "number"; + + const hasComboFiltersActive = + comboFilters.query !== "" || + comboFilters.strategy !== "all" || + comboFilters.status !== "all" || + comboFilters.testResult !== "all" || + typeof comboFilters.minMembers === "number" || + typeof comboFilters.maxMembers === "number"; + + const hasTestResults = Object.keys(testResults).length > 0; + const text = (key: string, fallback: string) => commonText(commonTranslator, key, fallback); - const providerText = (key: string, fallback: string) => - commonText(providersTranslator, key, fallback); return (
-

Model catalog

+

Models & Combos

- Browse model metadata from every provider in one place. + Browse and health-test models and combo routing pipelines across every provider.

-
+ + {/* Tab Navigation */} +
+ + +
- -
- updateQuery(event.target.value)} - className="min-w-0 flex-1" - /> -
- - -
-
- - {loading && models.length === 0 ? ( -
- {text("loading", "Loading...")} -
- ) : error && models.length === 0 ? ( -
-

Unable to load the model catalog.

-

Check the connection and try again.

- -
- ) : visibleModels.length === 0 ? ( -
- -

- {models.length === 0 - ? text("noModelsFound", "No models are available yet.") - : "No models match these filters."} -

- {models.length > 0 && ( - +
+ ) : visibleModels.length === 0 ? ( +
+ +

+ {models.length === 0 + ? text("noModelsFound", "No models are available yet.") + : "No models match these filters."} +

+ {models.length > 0 && ( + + )} +
+ ) : ( + { + if (field === modelSortField) { + setModelSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); + } else { + setModelSortField(field); + setModelSortDirection("asc"); + } + setRequestedModelPage(0); }} + page={modelPage.page + 1} + pageCount={modelPage.pageCount} + startIndex={modelPage.page * PAGE_SIZE} + totalCount={visibleModels.length} + loading={modelsLoading} + error={modelsError} + onPrevious={() => setRequestedModelPage((c) => Math.max(0, c - 1))} + onNext={() => + setRequestedModelPage((c) => Math.min(modelPage.pageCount - 1, c + 1)) + } + labels={{ + provider: text("provider", "Provider"), + model: text("model", "Model"), + type: text("type", "Type"), + capabilities: "Capabilities", + context: "Context", + output: text("output", "Max output"), + flags: "Flags", + custom: text("custom", "Custom"), + free: text("free", "Free"), + }} + selectedIds={selectedModelIds} + onToggleSelect={toggleSelectModel} + onToggleSelectAll={toggleSelectAllModelsOnPage} + testResults={testResults} + activeTestingKey={activeItemKey} + onTestModel={testSingleModel} + providerHealthMap={providerHealthMap} + /> + )} +
+ + )} + + {/* Combos Tab Content */} + {activeTab === "combos" && ( +
+ + + + + + {combosLoading && combos.length === 0 ? ( +
+ {text("loading", "Loading...")} +
+ ) : combosError && combos.length === 0 ? ( +
- Clear filters - +

Unable to load combos.

+

Check the connection and try again.

+ +
+ ) : visibleCombos.length === 0 ? ( +
+ +

+ {combos.length === 0 + ? "No combos are available yet." + : "No combos match these filters."} +

+ {combos.length > 0 && ( + + )} +
+ ) : ( + { + if (field === comboSortField) { + setComboSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); + } else { + setComboSortField(field); + setComboSortDirection("asc"); + } + setRequestedComboPage(0); + }} + page={comboPage.page + 1} + pageCount={comboPage.pageCount} + startIndex={comboPage.page * PAGE_SIZE} + totalCount={visibleCombos.length} + selectedIds={selectedComboIds} + onToggleSelect={toggleSelectCombo} + onToggleSelectAll={toggleSelectAllCombosOnPage} + testResults={testResults} + activeTestingKey={activeItemKey} + onTestCombo={testSingleCombo} + onPrevious={() => setRequestedComboPage((c) => Math.max(0, c - 1))} + onNext={() => + setRequestedComboPage((c) => Math.min(comboPage.pageCount - 1, c + 1)) + } + /> )} -
- ) : ( - setRequestedPage((current) => Math.max(0, current - 1))} - onNext={() => setRequestedPage((current) => Math.min(page.pageCount - 1, current + 1))} - labels={{ - provider: text("provider", "Provider"), - model: text("model", "Model"), - type: text("type", "Type"), - capabilities: "Capabilities", - context: "Context", - output: text("output", "Max output"), - flags: "Flags", - custom: text("custom", "Custom"), - free: text("free", "Free"), - }} - /> - )} - + + + )} ); } diff --git a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts new file mode 100644 index 000000000000..af28723ab181 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts @@ -0,0 +1,428 @@ +"use client"; + +import { useCallback, useRef, useState } from "react"; +import { + classifyError, + clearCatalogTestResults, + getComboTestKey, + getModelTestKey, + loadCatalogTestResults, + normalizeTestStatus, + saveBatchTestResults, + saveSingleTestResult, + type CatalogTestResult, +} from "./catalogTestStorage"; + +interface SingleModelTestResponse { + status?: string; + latencyMs?: number; + error?: string; + statusCode?: number; + rateLimited?: boolean; +} + +interface BatchModelTestResponse { + results?: Record< + string, + { + status: string; + latencyMs: number; + error?: string; + statusCode?: number; + rateLimited?: boolean; + isQuota?: boolean; + isTimeout?: boolean; + } + >; +} + +interface ComboTestTargetResult { + model: string; + provider?: string; + status?: string; + latencyMs?: number; + error?: string; + statusCode?: number; +} + +interface ComboTestResponse { + comboName?: string; + resolvedBy?: string | null; + results?: ComboTestTargetResult[]; + error?: string; +} + +export interface ProgressState { + completed: number; + total: number; + message: string; +} + +async function runWithConcurrency( + items: T[], + limit: number, + signal: AbortSignal, + worker: (item: T) => Promise +): Promise { + let index = 0; + const executing = new Set>(); + + while (index < items.length && !signal.aborted) { + while (executing.size < limit && index < items.length && !signal.aborted) { + const item = items[index++]; + const task: Promise = (async () => { + try { + if (!signal.aborted) { + await worker(item); + } + } finally { + executing.delete(task); + } + })(); + executing.add(task); + } + if (executing.size > 0) { + await Promise.race(executing); + } + } + await Promise.all(executing); +} + +export function useCatalogTestRunner() { + const [testResults, setTestResults] = useState>(() => + loadCatalogTestResults() + ); + const [running, setRunning] = useState(false); + const [activeItemKey, setActiveItemKey] = useState(null); + const [progress, setProgress] = useState({ + completed: 0, + total: 0, + message: "", + }); + + const abortControllerRef = useRef(null); + + const cancelTest = useCallback(() => { + if (abortControllerRef.current) { + abortControllerRef.current.abort(); + abortControllerRef.current = null; + } + setRunning(false); + setActiveItemKey(null); + setProgress((prev) => ({ + ...prev, + message: "Cancelled", + })); + }, []); + + const testSingleModel = useCallback( + async (providerId: string, modelId: string): Promise => { + const key = getModelTestKey(providerId, modelId); + setActiveItemKey(key); + + const controller = new AbortController(); + try { + const res = await fetch("/api/models/test", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ providerId, modelId }), + signal: controller.signal, + }); + + const data: unknown = await res.json().catch(() => null); + const json = ( + typeof data === "object" && data !== null ? data : {} + ) as SingleModelTestResponse; + + const status = normalizeTestStatus( + typeof json.status === "string" ? json.status : res.ok ? "ok" : "error", + typeof json.latencyMs === "number" ? json.latencyMs : undefined + ); + + const errorClass = classifyError( + json.error, + typeof json.statusCode === "number" ? json.statusCode : res.status, + { rateLimited: json.rateLimited } + ); + + const result: CatalogTestResult = { + id: key, + targetType: "model", + providerId, + modelId, + status, + latencyMs: json.latencyMs, + testedAt: Date.now(), + error: json.error, + errorClass, + statusCode: json.statusCode ?? res.status, + }; + + const updated = saveSingleTestResult(result); + setTestResults({ ...updated }); + return result; + } catch (err) { + const errorText = err instanceof Error ? err.message : String(err); + const result: CatalogTestResult = { + id: key, + targetType: "model", + providerId, + modelId, + status: "error", + testedAt: Date.now(), + error: errorText, + errorClass: classifyError(errorText), + }; + const updated = saveSingleTestResult(result); + setTestResults({ ...updated }); + return result; + } finally { + setActiveItemKey((current) => (current === key ? null : current)); + } + }, + [] + ); + + const testSingleCombo = useCallback(async (comboName: string): Promise => { + const key = getComboTestKey(comboName); + setActiveItemKey(key); + + const controller = new AbortController(); + try { + const res = await fetch("/api/combos/test", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ comboName }), + signal: controller.signal, + }); + + const data: unknown = await res.json().catch(() => null); + const json = (typeof data === "object" && data !== null ? data : {}) as ComboTestResponse; + + const okResult = json.results?.find((r) => r.status === "ok"); + const status = + res.ok && (json.resolvedBy || okResult) + ? normalizeTestStatus("ok", okResult?.latencyMs) + : "error"; + + const lastError = + json.results?.find((r) => r.error)?.error || + json.error || + (status === "error" ? "Combo test failed" : undefined); + const latencyMs = okResult?.latencyMs ?? json.results?.[0]?.latencyMs; + const statusCode = okResult?.statusCode ?? json.results?.[0]?.statusCode ?? res.status; + + const result: CatalogTestResult = { + id: key, + targetType: "combo", + comboName, + status, + latencyMs, + testedAt: Date.now(), + error: lastError, + errorClass: classifyError(lastError, statusCode), + statusCode, + }; + + const updated = saveSingleTestResult(result); + setTestResults({ ...updated }); + return result; + } catch (err) { + const errorText = err instanceof Error ? err.message : String(err); + const result: CatalogTestResult = { + id: key, + targetType: "combo", + comboName, + status: "error", + testedAt: Date.now(), + error: errorText, + errorClass: classifyError(errorText), + }; + const updated = saveSingleTestResult(result); + setTestResults({ ...updated }); + return result; + } finally { + setActiveItemKey((current) => (current === key ? null : current)); + } + }, []); + + const testBulkModels = useCallback( + async (models: Array<{ providerId: string; modelId: string }>) => { + if (models.length === 0) return; + + const controller = new AbortController(); + abortControllerRef.current = controller; + setRunning(true); + + const byProvider = new Map(); + for (const m of models) { + const list = byProvider.get(m.providerId) || []; + list.push(m.modelId); + byProvider.set(m.providerId, list); + } + + const batches: Array<{ providerId: string; modelIds: string[] }> = []; + for (const [providerId, modelIds] of byProvider.entries()) { + for (let i = 0; i < modelIds.length; i += 100) { + batches.push({ providerId, modelIds: modelIds.slice(i, i + 100) }); + } + } + + const totalModels = models.length; + let completedCount = 0; + setProgress({ + completed: 0, + total: totalModels, + message: `Testing 0 of ${totalModels} models...`, + }); + + try { + await runWithConcurrency(batches, 2, controller.signal, async (batch) => { + if (controller.signal.aborted) return; + + try { + const res = await fetch("/api/models/test-all", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + providerId: batch.providerId, + modelIds: batch.modelIds, + respectRateLimit: true, + }), + signal: controller.signal, + }); + + const data: unknown = await res.json().catch(() => null); + const json = ( + typeof data === "object" && data !== null ? data : {} + ) as BatchModelTestResponse; + + const mappedResults: CatalogTestResult[] = []; + const resultsRecord = json.results ?? {}; + + for (const modelId of batch.modelIds) { + const entry = resultsRecord[modelId]; + if (entry) { + mappedResults.push({ + id: getModelTestKey(batch.providerId, modelId), + targetType: "model", + providerId: batch.providerId, + modelId, + status: normalizeTestStatus(entry.status, entry.latencyMs), + latencyMs: entry.latencyMs, + testedAt: Date.now(), + error: entry.error, + errorClass: classifyError(entry.error, entry.statusCode, { + rateLimited: entry.rateLimited, + isQuota: entry.isQuota, + isTimeout: entry.isTimeout, + }), + statusCode: entry.statusCode, + }); + } else { + mappedResults.push({ + id: getModelTestKey(batch.providerId, modelId), + targetType: "model", + providerId: batch.providerId, + modelId, + status: "error", + testedAt: Date.now(), + error: res.ok ? "No test result reported" : `HTTP ${res.status}`, + errorClass: classifyError(undefined, res.status), + statusCode: res.status, + }); + } + } + + const updated = saveBatchTestResults(mappedResults); + setTestResults({ ...updated }); + } catch (batchErr) { + if (!controller.signal.aborted) { + const errText = batchErr instanceof Error ? batchErr.message : String(batchErr); + const failedResults = batch.modelIds.map((modelId) => ({ + id: getModelTestKey(batch.providerId, modelId), + targetType: "model" as const, + providerId: batch.providerId, + modelId, + status: "error" as const, + testedAt: Date.now(), + error: errText, + errorClass: classifyError(errText), + })); + const updated = saveBatchTestResults(failedResults); + setTestResults({ ...updated }); + } + } finally { + completedCount += batch.modelIds.length; + setProgress({ + completed: Math.min(completedCount, totalModels), + total: totalModels, + message: `Testing ${Math.min(completedCount, totalModels)} of ${totalModels} models...`, + }); + } + }); + } finally { + setRunning(false); + abortControllerRef.current = null; + } + }, + [] + ); + + const testBulkCombos = useCallback( + async (combos: Array<{ comboName: string }>) => { + if (combos.length === 0) return; + + const controller = new AbortController(); + abortControllerRef.current = controller; + setRunning(true); + + const totalCombos = combos.length; + let completedCount = 0; + setProgress({ + completed: 0, + total: totalCombos, + message: `Testing 0 of ${totalCombos} combos...`, + }); + + try { + await runWithConcurrency(combos, 2, controller.signal, async (item) => { + if (controller.signal.aborted) return; + + try { + await testSingleCombo(item.comboName); + } finally { + completedCount += 1; + setProgress({ + completed: Math.min(completedCount, totalCombos), + total: totalCombos, + message: `Testing ${Math.min(completedCount, totalCombos)} of ${totalCombos} combos...`, + }); + } + }); + } finally { + setRunning(false); + abortControllerRef.current = null; + } + }, + [testSingleCombo] + ); + + const clearResults = useCallback(() => { + clearCatalogTestResults(); + setTestResults({}); + }, []); + + return { + testResults, + running, + activeItemKey, + progress, + testSingleModel, + testSingleCombo, + testBulkModels, + testBulkCombos, + cancelTest, + clearResults, + }; +} diff --git a/src/shared/constants/sidebarVisibility/sections.ts b/src/shared/constants/sidebarVisibility/sections.ts index 31d03fc6f805..47efb722a589 100644 --- a/src/shared/constants/sidebarVisibility/sections.ts +++ b/src/shared/constants/sidebarVisibility/sections.ts @@ -44,9 +44,9 @@ const OMNI_PROXY_ITEMS: readonly SidebarItemDefinition[] = [ id: "model-catalog", href: "/dashboard/models", i18nKey: "modelCatalog", - labelFallback: "Model catalog", + labelFallback: "Models & Combos", subtitleKey: "modelCatalogSubtitle", - subtitleFallback: "Browse models across providers", + subtitleFallback: "Browse models and combos across providers", icon: "view_list", }, { diff --git a/tests/unit/dashboard/catalogTestStorage.test.tsx b/tests/unit/dashboard/catalogTestStorage.test.tsx new file mode 100644 index 000000000000..d22640b58a0c --- /dev/null +++ b/tests/unit/dashboard/catalogTestStorage.test.tsx @@ -0,0 +1,171 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { + CATALOG_TEST_RESULTS_KEY, + classifyError, + clearCatalogTestResults, + getComboTestKey, + getModelTestKey, + loadCatalogTestResults, + MAX_TEST_RESULTS_CAP, + normalizeTestStatus, + saveBatchTestResults, + saveCatalogTestResults, + saveSingleTestResult, + type CatalogTestResult, +} from "@/app/(dashboard)/dashboard/models/catalogTestStorage"; + +describe("catalogTestStorage", () => { + beforeEach(() => { + localStorage.clear(); + }); + + afterEach(() => { + localStorage.clear(); + }); + + it("loads empty results when localStorage is empty", () => { + const results = loadCatalogTestResults(); + expect(results).toEqual({}); + }); + + it("handles corrupt JSON in localStorage gracefully without throwing", () => { + localStorage.setItem(CATALOG_TEST_RESULTS_KEY, "this is not valid json {{{"); + const results = loadCatalogTestResults(); + expect(results).toEqual({}); + }); + + it("handles non-object JSON gracefully", () => { + localStorage.setItem(CATALOG_TEST_RESULTS_KEY, JSON.stringify(["item1", "item2"])); + const results = loadCatalogTestResults(); + expect(results).toEqual({}); + }); + + it("saves and loads single and batch test results", () => { + const modelResult: CatalogTestResult = { + id: getModelTestKey("alpha", "chat-1"), + targetType: "model", + providerId: "alpha", + modelId: "chat-1", + status: "ok", + latencyMs: 250, + testedAt: 1000, + }; + + saveSingleTestResult(modelResult); + let loaded = loadCatalogTestResults(); + expect(loaded[modelResult.id]).toEqual(modelResult); + + const comboResult: CatalogTestResult = { + id: getComboTestKey("fast-combo"), + targetType: "combo", + comboName: "fast-combo", + status: "slow", + latencyMs: 5100, + testedAt: 2000, + }; + + saveBatchTestResults([comboResult]); + loaded = loadCatalogTestResults(); + expect(loaded[modelResult.id]).toEqual(modelResult); + expect(loaded[comboResult.id]).toEqual(comboResult); + }); + + it("clears test results from localStorage", () => { + const modelResult: CatalogTestResult = { + id: getModelTestKey("alpha", "chat-1"), + targetType: "model", + providerId: "alpha", + modelId: "chat-1", + status: "ok", + latencyMs: 150, + testedAt: 1000, + }; + + saveSingleTestResult(modelResult); + expect(loadCatalogTestResults()[modelResult.id]).toBeDefined(); + + clearCatalogTestResults(); + expect(loadCatalogTestResults()).toEqual({}); + expect(localStorage.getItem(CATALOG_TEST_RESULTS_KEY)).toBeNull(); + }); + + it("caps results to MAX_TEST_RESULTS_CAP by dropping the oldest entries", () => { + const entries: Record = {}; + const totalEntries = MAX_TEST_RESULTS_CAP + 10; + + for (let index = 0; index < totalEntries; index++) { + const id = `model:provider:${index}`; + entries[id] = { + id, + targetType: "model", + providerId: "provider", + modelId: String(index), + status: "ok", + latencyMs: 100, + testedAt: index * 10, + }; + } + + saveCatalogTestResults(entries); + const loaded = loadCatalogTestResults(); + const loadedKeys = Object.keys(loaded); + expect(loadedKeys.length).toBe(MAX_TEST_RESULTS_CAP); + + // Oldest items (index 0 to 9) should have been pruned + expect(loaded["model:provider:0"]).toBeUndefined(); + expect(loaded["model:provider:9"]).toBeUndefined(); + // Newest items should be kept + expect(loaded[`model:provider:${totalEntries - 1}`]).toBeDefined(); + }); + + describe("classifyError", () => { + it("classifies rate limit errors", () => { + expect(classifyError("Rate limit exceeded", 429)).toBe("rate-limited"); + expect(classifyError(undefined, 429)).toBe("rate-limited"); + expect(classifyError("too many requests", 500, { rateLimited: true })).toBe("rate-limited"); + expect(classifyError("Rate limit reached for requests per minute")).toBe("rate-limited"); + }); + + it("classifies quota errors", () => { + expect(classifyError("Insufficient balance or quota", 403)).toBe("quota"); + expect(classifyError("credit limit reached", 400, { isQuota: true })).toBe("quota"); + expect(classifyError(undefined, 403, { isQuota: true })).toBe("quota"); + }); + + it("classifies timeout errors", () => { + expect(classifyError("Gateway Timeout", 504)).toBe("timeout"); + expect(classifyError("Request timed out", 408)).toBe("timeout"); + expect(classifyError("Connection timed out", 500, { isTimeout: true })).toBe("timeout"); + }); + + it("classifies other errors as other", () => { + expect(classifyError("Internal Server Error", 500)).toBe("other"); + expect(classifyError("Invalid authorization token", 401)).toBe("other"); + }); + + it("returns undefined when no error is present", () => { + expect(classifyError()).toBeUndefined(); + }); + }); + + describe("normalizeTestStatus", () => { + it("returns ok for ok status with reasonable latency", () => { + expect(normalizeTestStatus("ok", 300)).toBe("ok"); + }); + + it("returns slow if status is ok but latency is >= 5000ms", () => { + expect(normalizeTestStatus("ok", 5000)).toBe("slow"); + expect(normalizeTestStatus("ok", 7500)).toBe("slow"); + }); + + it("returns slow if status is slow", () => { + expect(normalizeTestStatus("slow", 1000)).toBe("slow"); + }); + + it("returns error for failed statuses", () => { + expect(normalizeTestStatus("error")).toBe("error"); + expect(normalizeTestStatus("rate_limited")).toBe("error"); + expect(normalizeTestStatus("unknown")).toBe("error"); + }); + }); +}); diff --git a/tests/unit/dashboard/comboCatalogUtils.test.tsx b/tests/unit/dashboard/comboCatalogUtils.test.tsx new file mode 100644 index 000000000000..84d510cbc063 --- /dev/null +++ b/tests/unit/dashboard/comboCatalogUtils.test.tsx @@ -0,0 +1,271 @@ +import { describe, expect, it } from "vitest"; +import { + filterCatalogCombos, + flattenCombos, + getComboCatalogPage, + sortCatalogCombos, + type ComboCatalogRow, +} from "@/app/(dashboard)/dashboard/models/comboCatalogUtils"; + +const sampleCombos: ComboCatalogRow[] = [ + { + id: "combo-1", + name: "alpha-priority", + displayName: "Alpha Priority", + strategy: "priority", + description: "Fast fallback chain", + models: [ + { model: "openai/gpt-4o", provider: "openai" }, + { model: "anthropic/claude-3-5-sonnet", provider: "anthropic" }, + ], + memberCount: 2, + status: "active", + contextLength: 128000, + }, + { + id: "combo-2", + name: "beta-round-robin", + displayName: "Beta Round Robin", + strategy: "round-robin", + description: "Load balanced across 5 models", + models: [{ model: "m1" }, { model: "m2" }, { model: "m3" }, { model: "m4" }, { model: "m5" }], + memberCount: 5, + status: "paused", + contextLength: 64000, + }, + { + id: "combo-3", + name: "gamma-fusion", + strategy: "fusion", + description: "Parallel judge panel", + models: [{ model: "m1" }], + memberCount: 1, + status: "active", + }, +]; + +describe("flattenCombos", () => { + it("extracts and normalizes combo rows from API payload", () => { + const rawCombos = [ + { + id: "c1", + name: "test-combo", + strategy: "weighted", + models: [{ model: "m1" }], + isActive: false, + }, + { + id: "c2", + name: "active-combo", + strategy: "round-robin", + models: [{ model: "m1" }, { model: "m2" }], + isActive: true, + }, + ]; + + const result = flattenCombos(rawCombos); + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ + id: "c1", + name: "test-combo", + displayName: "test-combo", + strategy: "weighted", + description: undefined, + models: [{ model: "m1" }], + memberCount: 1, + status: "paused", + contextLength: undefined, + }); + expect(result[1].status).toBe("active"); + expect(result[1].memberCount).toBe(2); + }); + + it("handles empty or invalid inputs", () => { + expect(flattenCombos(null)).toEqual([]); + expect(flattenCombos(undefined)).toEqual([]); + expect(flattenCombos("invalid")).toEqual([]); + }); +}); + +describe("filterCatalogCombos", () => { + it("filters combos by query across name, displayName, description, and model ids", () => { + expect( + filterCatalogCombos(sampleCombos, { + query: "alpha", + strategy: "all", + status: "all", + testResult: "all", + }) + ).toEqual([sampleCombos[0]]); + + expect( + filterCatalogCombos(sampleCombos, { + query: "claude-3-5", + strategy: "all", + status: "all", + testResult: "all", + }) + ).toEqual([sampleCombos[0]]); + + expect( + filterCatalogCombos(sampleCombos, { + query: "judge", + strategy: "all", + status: "all", + testResult: "all", + }) + ).toEqual([sampleCombos[2]]); + }); + + it("filters combos by strategy", () => { + expect( + filterCatalogCombos(sampleCombos, { + query: "", + strategy: "priority", + status: "all", + testResult: "all", + }) + ).toEqual([sampleCombos[0]]); + }); + + it("filters combos by status", () => { + expect( + filterCatalogCombos(sampleCombos, { + query: "", + strategy: "all", + status: "paused", + testResult: "all", + }) + ).toEqual([sampleCombos[1]]); + + expect( + filterCatalogCombos(sampleCombos, { + query: "", + strategy: "all", + status: "active", + testResult: "all", + }) + ).toEqual([sampleCombos[0], sampleCombos[2]]); + }); + + it("filters combos by member count range", () => { + expect( + filterCatalogCombos(sampleCombos, { + query: "", + strategy: "all", + status: "all", + minMembers: 2, + maxMembers: 4, + testResult: "all", + }) + ).toEqual([sampleCombos[0]]); + + expect( + filterCatalogCombos(sampleCombos, { + query: "", + strategy: "all", + status: "all", + minMembers: 3, + testResult: "all", + }) + ).toEqual([sampleCombos[1]]); + }); + + it("filters combos by test result", () => { + const testResults = { + "combo:alpha-priority": { + id: "combo:alpha-priority", + targetType: "combo" as const, + comboName: "alpha-priority", + status: "ok" as const, + latencyMs: 120, + testedAt: 1000, + }, + "combo:beta-round-robin": { + id: "combo:beta-round-robin", + targetType: "combo" as const, + comboName: "beta-round-robin", + status: "error" as const, + latencyMs: 50, + testedAt: 1000, + }, + }; + + expect( + filterCatalogCombos( + sampleCombos, + { + query: "", + strategy: "all", + status: "all", + testResult: "ok", + }, + testResults + ) + ).toEqual([sampleCombos[0]]); + + expect( + filterCatalogCombos( + sampleCombos, + { + query: "", + strategy: "all", + status: "all", + testResult: "error", + }, + testResults + ) + ).toEqual([sampleCombos[1]]); + + expect( + filterCatalogCombos( + sampleCombos, + { + query: "", + strategy: "all", + status: "all", + testResult: "untested", + }, + testResults + ) + ).toEqual([sampleCombos[2]]); + }); +}); + +describe("sortCatalogCombos", () => { + it("sorts by name ascending and descending", () => { + const sortedAsc = sortCatalogCombos(sampleCombos, "name", "asc"); + expect(sortedAsc.map((c) => c.name)).toEqual([ + "alpha-priority", + "beta-round-robin", + "gamma-fusion", + ]); + + const sortedDesc = sortCatalogCombos(sampleCombos, "name", "desc"); + expect(sortedDesc.map((c) => c.name)).toEqual([ + "gamma-fusion", + "beta-round-robin", + "alpha-priority", + ]); + }); + + it("sorts by memberCount", () => { + const sorted = sortCatalogCombos(sampleCombos, "memberCount", "desc"); + expect(sorted.map((c) => c.memberCount)).toEqual([5, 2, 1]); + }); +}); + +describe("getComboCatalogPage", () => { + it("paginates combo rows correctly", () => { + expect(getComboCatalogPage(sampleCombos, 0, 2)).toEqual({ + rows: [sampleCombos[0], sampleCombos[1]], + page: 0, + pageCount: 2, + }); + expect(getComboCatalogPage(sampleCombos, 1, 2)).toEqual({ + rows: [sampleCombos[2]], + page: 1, + pageCount: 2, + }); + }); +}); diff --git a/tests/unit/dashboard/modelCatalogUtils.test.tsx b/tests/unit/dashboard/modelCatalogUtils.test.tsx index a82e223536e4..e521e5acd530 100644 --- a/tests/unit/dashboard/modelCatalogUtils.test.tsx +++ b/tests/unit/dashboard/modelCatalogUtils.test.tsx @@ -1,11 +1,14 @@ import { describe, expect, it } from "vitest"; import { + extractCatalogCapabilities, filterCatalogModels, flattenCatalog, getCatalogPage, sortCatalogModels, + type CatalogFilters, type CatalogModelRow, } from "@/app/(dashboard)/dashboard/models/modelCatalogUtils"; +import type { CatalogTestResult } from "@/app/(dashboard)/dashboard/models/catalogTestStorage"; const models: CatalogModelRow[] = [ { @@ -14,8 +17,11 @@ const models: CatalogModelRow[] = [ id: "zeta-chat", name: "Zeta Chat", type: "chat", + subtype: "instruction", context_length: 128_000, + max_output_tokens: 4_096, input_modalities: ["text", "image"], + capabilities: { reasoning: true, vision: true }, }, { providerId: "alpha", @@ -23,6 +29,9 @@ const models: CatalogModelRow[] = [ id: "alpha-embed", name: "Alpha Embed", type: "embedding", + subtype: "dense", + context_length: 8_192, + max_output_tokens: 512, capabilities: { tools: true }, custom: true, }, @@ -32,10 +41,22 @@ const models: CatalogModelRow[] = [ id: "alpha-chat", name: "Alpha Chat", type: "chat", + max_output_tokens: 2_048, free: true, }, ]; +const defaultFilters: CatalogFilters = { + query: "", + providerId: "all", + type: "all", + subtype: "all", + capability: "all", + pricing: "all", + providerHealth: "all", + testResult: "all", +}; + describe("flattenCatalog", () => { it("creates one row per model while retaining the provider identity", () => { expect( @@ -56,20 +77,132 @@ describe("flattenCatalog", () => { }); }); +describe("extractCatalogCapabilities", () => { + it("derives all unique capabilities from catalog models", () => { + const caps = extractCatalogCapabilities(models); + expect(caps).toContain("reasoning"); + expect(caps).toContain("vision"); + expect(caps).toContain("tools"); + }); +}); + describe("filterCatalogModels", () => { it("searches case-insensitively across provider, model, and capability metadata", () => { - expect(filterCatalogModels(models, { query: "IMAGE", providerId: "all", type: "all" })).toEqual( - [models[0]] - ); - expect( - filterCatalogModels(models, { query: "alpha labs", providerId: "all", type: "all" }) - ).toEqual([models[1], models[2]]); + expect(filterCatalogModels(models, { ...defaultFilters, query: "IMAGE" })).toEqual([models[0]]); + expect(filterCatalogModels(models, { ...defaultFilters, query: "alpha labs" })).toEqual([ + models[1], + models[2], + ]); }); it("combines provider and type filters", () => { - expect(filterCatalogModels(models, { query: "", providerId: "alpha", type: "chat" })).toEqual([ + expect( + filterCatalogModels(models, { ...defaultFilters, providerId: "alpha", type: "chat" }) + ).toEqual([models[2]]); + }); + + it("filters by subtype", () => { + expect(filterCatalogModels(models, { ...defaultFilters, subtype: "instruction" })).toEqual([ + models[0], + ]); + expect(filterCatalogModels(models, { ...defaultFilters, subtype: "dense" })).toEqual([ + models[1], + ]); + }); + + it("filters by capability", () => { + expect(filterCatalogModels(models, { ...defaultFilters, capability: "reasoning" })).toEqual([ + models[0], + ]); + expect(filterCatalogModels(models, { ...defaultFilters, capability: "tools" })).toEqual([ + models[1], + ]); + }); + + it("filters by minContextLength", () => { + expect(filterCatalogModels(models, { ...defaultFilters, minContextLength: 8_000 })).toEqual([ + models[0], + models[1], + ]); + expect(filterCatalogModels(models, { ...defaultFilters, minContextLength: 100_000 })).toEqual([ + models[0], + ]); + }); + + it("filters by minMaxOutputTokens", () => { + expect(filterCatalogModels(models, { ...defaultFilters, minMaxOutputTokens: 2_000 })).toEqual([ + models[0], + models[2], + ]); + expect(filterCatalogModels(models, { ...defaultFilters, minMaxOutputTokens: 4_000 })).toEqual([ + models[0], + ]); + }); + + it("filters by pricing (free vs paid)", () => { + expect(filterCatalogModels(models, { ...defaultFilters, pricing: "free" })).toEqual([ models[2], ]); + expect(filterCatalogModels(models, { ...defaultFilters, pricing: "paid" })).toEqual([ + models[0], + models[1], + ]); + }); + + it("filters by providerHealth", () => { + const healthMap: Record = { + zeta: "healthy", + alpha: "degraded", + }; + expect( + filterCatalogModels( + models, + { ...defaultFilters, providerHealth: "healthy" }, + { providerHealthMap: healthMap } + ) + ).toEqual([models[0]]); + + expect( + filterCatalogModels( + models, + { ...defaultFilters, providerHealth: "degraded" }, + { providerHealthMap: healthMap } + ) + ).toEqual([models[1], models[2]]); + }); + + it("filters by testResult", () => { + const testResults: Record = { + "model:zeta:zeta-chat": { + id: "model:zeta:zeta-chat", + targetType: "model", + providerId: "zeta", + modelId: "zeta-chat", + status: "ok", + testedAt: 1000, + }, + "model:alpha:alpha-embed": { + id: "model:alpha:alpha-embed", + targetType: "model", + providerId: "alpha", + modelId: "alpha-embed", + status: "error", + error: "Failed", + testedAt: 1000, + }, + }; + + expect( + filterCatalogModels(models, { ...defaultFilters, testResult: "ok" }, { testResults }) + ).toEqual([models[0]]); + + expect( + filterCatalogModels(models, { ...defaultFilters, testResult: "error" }, { testResults }) + ).toEqual([models[1]]); + + expect( + filterCatalogModels(models, { ...defaultFilters, testResult: "untested" }, { testResults }) + ).toEqual([models[2]]); }); }); diff --git a/tests/unit/dashboard/modelsCombosCatalog.test.tsx b/tests/unit/dashboard/modelsCombosCatalog.test.tsx new file mode 100644 index 000000000000..13dec81f123f --- /dev/null +++ b/tests/unit/dashboard/modelsCombosCatalog.test.tsx @@ -0,0 +1,372 @@ +// @vitest-environment jsdom +import React, { act } from "react"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("next-intl", () => ({ + useTranslations: () => { + const translate = (key: string) => key; + return Object.assign(translate, { has: () => false }); + }, +})); + +import ModelCatalogPage from "@/app/(dashboard)/dashboard/models/page"; +import { + CATALOG_TEST_RESULTS_KEY, + getModelTestKey, +} from "@/app/(dashboard)/dashboard/models/catalogTestStorage"; + +describe("Models and Combos Catalog Page UI", () => { + let container: HTMLDivElement; + let root: Root; + + beforeEach(() => { + ( + globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean } + ).IS_REACT_ACT_ENVIRONMENT = true; + container = document.createElement("div"); + document.body.appendChild(container); + root = createRoot(container); + localStorage.clear(); + window.history.replaceState(null, "", "/dashboard/models"); + }); + + afterEach(() => { + act(() => root.unmount()); + container.remove(); + vi.restoreAllMocks(); + vi.unstubAllGlobals(); + localStorage.clear(); + }); + + const setupMockFetch = () => { + const fetchMock = vi.fn().mockImplementation((url: string, init?: RequestInit) => { + const urlStr = typeof url === "string" ? url : String(url); + + if (urlStr.includes("/api/models/catalog")) { + return Promise.resolve({ + ok: true, + json: async () => ({ + catalog: { + alpha: { + provider: "Alpha Labs", + models: [ + { + id: "alpha-chat", + name: "Alpha Chat", + type: "chat", + subtype: "general", + free: true, + context_length: 128_000, + capabilities: { tools: true, vision: true }, + }, + { + id: "alpha-embed", + name: "Alpha Embed", + type: "embedding", + context_length: 8_192, + }, + ], + }, + beta: { + provider: "Beta AI", + models: [ + { + id: "beta-coder", + name: "Beta Coder", + type: "chat", + subtype: "code", + capabilities: { reasoning: true }, + }, + ], + }, + }, + }), + }); + } + + if (urlStr.includes("/api/combos/test")) { + return Promise.resolve({ + ok: true, + json: async () => ({ + comboName: "combo-1", + strategy: "priority", + resolvedBy: "alpha/alpha-chat", + results: [{ model: "alpha-chat", provider: "alpha", status: "ok", latencyMs: 210 }], + testedAt: new Date().toISOString(), + }), + }); + } + + if (urlStr.includes("/api/combos")) { + return Promise.resolve({ + ok: true, + json: async () => ({ + combos: [ + { + id: "c-1", + name: "combo-1", + displayName: "First Combo", + strategy: "priority", + description: "Fallback chain", + models: [{ model: "alpha/alpha-chat" }, { model: "beta/beta-coder" }], + isActive: true, + }, + { + id: "c-2", + name: "combo-2", + displayName: "Second Combo", + strategy: "round-robin", + models: [{ model: "alpha/alpha-embed" }], + isActive: false, + }, + ], + total: 2, + }), + }); + } + + if (urlStr.includes("/api/providers/health-matrix")) { + return Promise.resolve({ + ok: true, + json: async () => ({ + providers: [ + { provider: "alpha", state: "healthy" }, + { provider: "beta", state: "degraded" }, + ], + }), + }); + } + + if (urlStr.includes("/api/models/test-all")) { + const body = init?.body ? JSON.parse(String(init.body)) : {}; + const results: Record = {}; + for (const mid of body.modelIds || []) { + results[mid] = { status: "ok", latencyMs: 140 }; + } + return Promise.resolve({ + ok: true, + json: async () => ({ results }), + }); + } + + if (urlStr.includes("/api/models/test")) { + return Promise.resolve({ + ok: true, + json: async () => ({ + status: "ok", + latencyMs: 185, + responseText: "Hello from test", + }), + }); + } + + return Promise.reject(new Error(`Unhandled mock url: ${urlStr}`)); + }); + + vi.stubGlobal("fetch", fetchMock); + return fetchMock; + }; + + it("renders tabs and switches between Models and Combos with deep linking", async () => { + setupMockFetch(); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + expect(container.textContent).toContain("Alpha Labs"); + const tabs = container.querySelectorAll('[role="tab"]'); + expect(tabs.length).toBe(2); + expect(tabs[0].textContent).toContain("Models"); + expect(tabs[1].textContent).toContain("Combos"); + expect(tabs[0].getAttribute("aria-selected")).toBe("true"); + + // Click combos tab + act(() => { + (tabs[1] as HTMLElement).click(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + expect(tabs[1].getAttribute("aria-selected")).toBe("true"); + expect(window.location.search).toContain("tab=combos"); + expect(container.textContent).toContain("First Combo"); + }); + + it("restores active tab from deep link query parameter ?tab=combos", async () => { + setupMockFetch(); + window.history.replaceState(null, "", "/dashboard/models?tab=combos"); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + const tabs = container.querySelectorAll('[role="tab"]'); + expect(tabs[1].getAttribute("aria-selected")).toBe("true"); + expect(container.textContent).toContain("First Combo"); + }); + + it("executes single model test and displays status badge and latency", async () => { + const fetchMock = setupMockFetch(); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + const testButtons = container.querySelectorAll("button[data-testid^='test-model-']"); + expect(testButtons.length).toBeGreaterThan(0); + + await act(async () => { + (testButtons[0] as HTMLElement).click(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 20))); + + expect(fetchMock).toHaveBeenCalledWith( + "/api/models/test", + expect.objectContaining({ + method: "POST", + body: JSON.stringify({ providerId: "alpha", modelId: "alpha-chat" }), + }) + ); + + // Verify localStorage has saved result + const saved = JSON.parse(localStorage.getItem(CATALOG_TEST_RESULTS_KEY) || "{}"); + const key = getModelTestKey("alpha", "alpha-chat"); + expect(saved[key]).toBeDefined(); + expect(saved[key].status).toBe("ok"); + expect(saved[key].latencyMs).toBe(185); + }); + + it("restores previously stored test results from localStorage on mount", async () => { + const key = getModelTestKey("alpha", "alpha-chat"); + localStorage.setItem( + CATALOG_TEST_RESULTS_KEY, + JSON.stringify({ + [key]: { + id: key, + targetType: "model", + providerId: "alpha", + modelId: "alpha-chat", + status: "ok", + latencyMs: 123, + testedAt: Date.now(), + }, + }) + ); + + setupMockFetch(); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + // Badge showing ok or latency should be visible in the row + expect(container.textContent).toContain("123ms"); + }); + + it("runs bulk model testing batching per provider with concurrency <= 2 and max 100 ids", async () => { + const fetchMock = setupMockFetch(); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + const testAllFilteredBtn = container.querySelector( + "button[data-testid='test-all-filtered-btn']" + ) as HTMLElement; + expect(testAllFilteredBtn).toBeDefined(); + + await act(async () => { + testAllFilteredBtn.click(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 30))); + + const testAllCalls = fetchMock.mock.calls.filter((call) => + String(call[0]).includes("/api/models/test-all") + ); + expect(testAllCalls.length).toBeGreaterThanOrEqual(1); + + for (const call of testAllCalls) { + const body = JSON.parse(String(call[1]?.body)); + expect(body.modelIds.length).toBeLessThanOrEqual(100); + expect(body.respectRateLimit).toBe(true); + expect(typeof body.providerId).toBe("string"); + } + }); + + it("stops bulk scheduling when Cancel is clicked", async () => { + let callCount = 0; + vi.stubGlobal( + "fetch", + vi.fn().mockImplementation((url: string) => { + const urlStr = String(url); + if (urlStr.includes("/api/models/catalog")) { + // Provide 5 providers to ensure multiple batches + return Promise.resolve({ + ok: true, + json: async () => ({ + catalog: { + p1: { provider: "P1", models: [{ id: "m1", name: "m1", type: "chat" }] }, + p2: { provider: "P2", models: [{ id: "m2", name: "m2", type: "chat" }] }, + p3: { provider: "P3", models: [{ id: "m3", name: "m3", type: "chat" }] }, + p4: { provider: "P4", models: [{ id: "m4", name: "m4", type: "chat" }] }, + }, + }), + }); + } + if (urlStr.includes("/api/providers/health-matrix")) { + return Promise.resolve({ ok: true, json: async () => ({ providers: [] }) }); + } + if (urlStr.includes("/api/combos")) { + return Promise.resolve({ ok: true, json: async () => ({ combos: [], total: 0 }) }); + } + if (urlStr.includes("/api/models/test-all")) { + callCount++; + // Simulate latency + return new Promise((resolve) => { + setTimeout( + () => + resolve({ + ok: true, + json: async () => ({ results: { m1: { status: "ok", latencyMs: 50 } } }), + }), + 50 + ); + }); + } + return Promise.reject(new Error("unexpected")); + }) + ); + + act(() => { + root.render(); + }); + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + + const testAllFilteredBtn = container.querySelector( + "button[data-testid='test-all-filtered-btn']" + ) as HTMLElement; + + act(() => { + testAllFilteredBtn.click(); + }); + + const cancelBtn = container.querySelector( + "button[data-testid='cancel-tests-btn']" + ) as HTMLElement; + expect(cancelBtn).toBeDefined(); + + act(() => { + cancelBtn.click(); + }); + + await act(async () => new Promise((resolve) => window.setTimeout(resolve, 80))); + // Should have aborted and not called all 4 providers + expect(callCount).toBeLessThan(4); + }); +}); From a5def8857c011e2f804a6ec63de2cb6099325e98 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 15:04:28 +0300 Subject: [PATCH 02/16] i18n(dashboard): translate models and combos catalog across all 66 locales --- src/i18n/messages/am.json | 3 +++ src/i18n/messages/ar.json | 3 +++ src/i18n/messages/az.json | 3 +++ src/i18n/messages/bg.json | 3 +++ src/i18n/messages/bn.json | 3 +++ src/i18n/messages/bs.json | 3 +++ src/i18n/messages/cs.json | 3 +++ src/i18n/messages/da.json | 3 +++ src/i18n/messages/de.json | 3 +++ src/i18n/messages/el.json | 3 +++ src/i18n/messages/en.json | 2 ++ src/i18n/messages/es.json | 3 +++ src/i18n/messages/et.json | 3 +++ src/i18n/messages/fa.json | 3 +++ src/i18n/messages/fi.json | 3 +++ src/i18n/messages/fr.json | 3 +++ src/i18n/messages/ga.json | 3 +++ src/i18n/messages/gu.json | 3 +++ src/i18n/messages/ha.json | 3 +++ src/i18n/messages/he.json | 3 +++ src/i18n/messages/hi.json | 3 +++ src/i18n/messages/hr.json | 3 +++ src/i18n/messages/hu.json | 3 +++ src/i18n/messages/hy.json | 3 +++ src/i18n/messages/id.json | 3 +++ src/i18n/messages/ig.json | 3 +++ src/i18n/messages/it.json | 3 +++ src/i18n/messages/ja.json | 3 +++ src/i18n/messages/ka.json | 3 +++ src/i18n/messages/km.json | 3 +++ src/i18n/messages/kn.json | 3 +++ src/i18n/messages/ko.json | 3 +++ src/i18n/messages/lt.json | 3 +++ src/i18n/messages/lv.json | 3 +++ src/i18n/messages/ml.json | 3 +++ src/i18n/messages/mr.json | 3 +++ src/i18n/messages/ms.json | 3 +++ src/i18n/messages/mt.json | 3 +++ src/i18n/messages/my.json | 3 +++ src/i18n/messages/ne.json | 3 +++ src/i18n/messages/nl.json | 3 +++ src/i18n/messages/no.json | 3 +++ src/i18n/messages/or.json | 3 +++ src/i18n/messages/pa.json | 3 +++ src/i18n/messages/phi.json | 3 +++ src/i18n/messages/pl.json | 3 +++ src/i18n/messages/pt-BR.json | 3 +++ src/i18n/messages/pt.json | 3 +++ src/i18n/messages/ro.json | 3 +++ src/i18n/messages/ru.json | 3 +++ src/i18n/messages/si.json | 3 +++ src/i18n/messages/sk.json | 3 +++ src/i18n/messages/sl.json | 3 +++ src/i18n/messages/sr.json | 3 +++ src/i18n/messages/sv.json | 3 +++ src/i18n/messages/sw.json | 3 +++ src/i18n/messages/ta.json | 3 +++ src/i18n/messages/te.json | 3 +++ src/i18n/messages/th.json | 3 +++ src/i18n/messages/tr.json | 3 +++ src/i18n/messages/uk-UA.json | 3 +++ src/i18n/messages/ur.json | 3 +++ src/i18n/messages/uz.json | 3 +++ src/i18n/messages/vi.json | 6 ++++-- src/i18n/messages/yo.json | 3 +++ src/i18n/messages/zh-CN.json | 3 +++ src/i18n/messages/zh-TW.json | 3 +++ 67 files changed, 201 insertions(+), 2 deletions(-) diff --git a/src/i18n/messages/am.json b/src/i18n/messages/am.json index ed33df7a6502..87a52e75f2f2 100644 --- a/src/i18n/messages/am.json +++ b/src/i18n/messages/am.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ለአቅራቢ ማሰራጨት በተከራይ ደረጃ የሚላመዱ ምናባዊ የመቀበያ መስመሮችን ያንቁ (#9654)፦ የአንድ ተከራይ ድንገተኛ ጭማሪ ከእንግዲህ በሌላው ላይ 503 ስህተት አያስከትልም። የOMNIROUTE_CHAT_VIRTUAL_LANES የአካባቢ ተለዋዋጭ ከዚህ የዳሽቦርድ ማሻሻያ ቅድሚያ ይኖረዋል፤ ለውጦች አገልጋዩ ዳግም ሲጀመር ተግባራዊ ይሆናሉ።", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "የዳሽቦርድ አቅራቢ ገጾች፦ ነፃ ባጁን አቅራቢው በሚያከብራቸው ምልክቶች ላይ ብቻ ያሳዩ — የማሳያ ስም ግምታዊ ደንብን፣ ቡሊያን ያልሆኑ የነፃ መስኮችን እና ሰነድ የተደረገለት ነፃ ደረጃ በሌላቸው የተመዘገቡ አቅራቢዎች ላይ ያሉ :free ቅጥያዎችን ያስወግዳል። ማጥፋት ታሪካዊውን የባጅ ደንብ ይጠብቃል።", "featureFlagProxySkipRecentlyFailedDescription": "የፕሮክሲ ፑሎች እና የ opencode የየመለያው ዙር ምርጫ፣ አሁን ያልተሳካውን ፕሮክሲ (ውድቅ የተደረገ TCP ሙከራ ወይም በእሱ በኩል የተቀበለ 429) በድጋሚ እንዳያቀርቡ ያደርጋሉ፤ ይህም በእያንዳንዱ ድግግሞሽ እስከ ከፍተኛው ገደብ ድረስ በእጥፍ ለሚጨምር የየሂደቱ ጊዜ ነው። ምንም የፕሮክሲ ሁኔታ አይጻፍም፤ እያንዳንዱ እጩ ወደ ጎን ሲቀመጥ ምርጫው አይለወጥም። በነባሪ በርቷል፤ `false` ተራውን ምርጫ ይመልሳል።", + "featureFlagProxyPoolSharedEgressOrderDescription": "ኮታቸው በegress አድራሻ ለተመደበላቸው አቅራቢዎች፣ በቅርቡ ውድቅ ከተደረገ አባል ጋር የታየውን egress አድራሻ የሚጋራ የፑል አባልን ከጤናማ አባላት ዝቅ ብሎ ደረጃ ይስጡ። የቅደም ተከተል ብቻ ነው፣ በጭራሽ አይገለልም። የሚያነበውን የውድቅ ማድረጊያ ምልክት የሚያመነጨውን PROXY_SKIP_RECENTLY_FAILED ይፈልጋል። በነባሪነት ጠፍቷል፡ የምርጫ ቅደም ተከተሉ ልክ እንደ መደበኛ ዙር ነው።", "featureFlagProxyPoolEgressObservationDescription": "በዳሽቦርዱ ውስጥ ከፕሮክሲ ፑል ሥር፣ ባለፉት 24 ሰዓታት ምን ያህል የታዩ የመውጫ IPዎች አባላቱን እንዳገለገሉ፣ ምን ያህል ግንኙነቶች እንደተጠቀሙባቸው እና ከአንድ IP ጀርባ የታየውን ከፍተኛ ቁጥር አሳይ። ለንባብ ብቻ ነው፣ ከፕሮክሲ ሎጉ ይሰላል፣ ለማዞሪያም ፈጽሞ ጥቅም ላይ አይውልም። በነባሪ ጠፍቷል፦ የፑሉ አርታዒ አይለወጥም፣ የምልከታ መስመሩም null ይመልሳል።", "featureFlagProxyHealthBlockedResetsStreakDescription": "በፕሮክሲ ጤና ፍተሻ ውስጥ፣ ዒላማው ውድቅ ያደረገው ሙከራ (401/403/429፦ ፕሮክሲው አስተላልፏል፣ መዳረሻው ግን ይህን የመውጫ IP ውድቅ አድርጓል) ልክ እንደተሳካ ሙከራ የፕሮክሲውን ተከታታይ የውድቀት ቆጠራ ዳግም እንዲጀምር ፍቀድ። በነባሪ ጠፍቷል፦ ውድቅ መደረጉ ገለልተኛ ሆኖ ይቆያል እና ቆጠራውን እንዳለ ያቆያል። 5xx በሁለቱም ሁኔታ የማያረጋግጥ ሆኖ ይቆያል፣ እና ውድቅ መደረግ ፕሮክሲን ፈጽሞ አያስወግድም፣ አያሰናክልም ወይም ዳግም አያነቃም።", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ራስ-ሰር የማጽዳት ሂደቱ ከOMNIROUTE_BATCH_RETENTION_DAYS በላይ የቆዩ የተጠናቀቁ (completed/failed/cancelled/expired) Batch API ሥራዎችን ከየመስመራቸው ማረጋገጫ ነጥቦች ጋር እንዲሰርዝ እና የራሳቸው expires_at ያለፈባቸው የተሰቀሉ ፋይሎችን BLOB ይዘት እንዲያጸዳ ይፍቀዱ። በነባሪ የተሰናከለ ነው፦ ኦፕሬተር እስኪያነቃው ድረስ እያንዳንዱ ነባር ጭነት ይህን ውሂብ ልክ እንደበፊቱ ያቆያል። በኦፕሬተር የሚጀመረው DELETE /api/v1/batches/delete-completed መስመር በሁለቱም ሁኔታ አይነካም -- ይህ የተለየ፣ ቅድመ ሁኔታ የሌለው ይፋዊ API ውል ነው።", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AIን የሚያገናኙባቸው URLs", "apiManager": "API ቁልፎች", "apiManagerSubtitle": "የAPI ቁልፎችን እና መዳረሻን ያስተዳድሩ", + "modelCatalog": "ሞዴሎች እና ኮምቦዎች", + "modelCatalogSubtitle": "በአቅራቢዎች ዙሪያ ሞዴሎችን እና ኮምቦዎችን ያስሱ", "embeddedServices": "የተካተቱ አገልግሎቶች", "embeddedServicesSubtitle": "በአካባቢው የሚሰሩ አማራጭ አገልግሎቶች", "logs": "ምዝግቦች", diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 18680e384972..0db20b97acdc 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "فعّل مسارات القبول الافتراضية التكيفية لكل مستأجر (tenant) لتوزيع المزودين (#9654): لم يعد انفجار حركة أحد المستأجرين يسبب خطأ 503 لمستأجر آخر. متغير البيئة OMNIROUTE_CHAT_VIRTUAL_LANES له الأولوية على هذا الإعداد في لوحة التحكم؛ تصبح التغييرات سارية بعد إعادة تشغيل الخادم.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "صفحات مزوّدي لوحة المعلومات: اعرض شارة «مجاني» فقط استنادًا إلى الإشارات التي يعتمدها المزوّد — مع إلغاء أسلوب الاستدلال المستند إلى اسم العرض، وحقول المجانية غير المنطقية، واللواحق :free لدى المزوّدين المسجّلين الذين ليست لديهم فئة مجانية موثّقة. عند التعطيل، تُستخدم قاعدة الشارة السابقة.", "featureFlagProxySkipRecentlyFailedDescription": "تمنع مجموعات الوكلاء والتناوب لكل حساب في opencode إعادة استخدام وكيل فشل للتو (رفض فحص TCP، أو تم تلقي 429 من خلاله) لمدة خاصة بكل عملية تتضاعف مع كل تكرار، حتى حد أقصى. لا تُكتب أي حالة للوكيل؛ وعند استبعاد جميع المرشحين، يظل الاختيار دون تغيير. مفعّل افتراضيًا؛ تعيد القيمة `false` الاختيار العادي.", + "featureFlagProxyPoolSharedEgressOrderDescription": "بالنسبة للمزودين الذين يتم تقسيم حصتهم حسب عنوان الخروج، رتّب عضو التجمع الذي يشارك عنوان الخروج المرصود لعضو رُفض مؤخراً مباشرة بعد الأعضاء السليمين. ترتيب فقط، دون استبعاد أبداً. يتطلب PROXY_SKIP_RECENTLY_FAILED، والذي يولّد إشارة الرفض التي يقرؤها. معطل افتراضياً: ترتيب الاختيار يطابق التدوير العادي تماماً.", "featureFlagProxyPoolEgressObservationDescription": "اعرض، أسفل مجموعة وكلاء في لوحة المعلومات، عدد عناوين IP الصادرة المرصودة التي خدمت أعضاءها خلال آخر 24 ساعة، وعدد الاتصالات التي استخدمتها، وأكبر عدد شوهد خلف عنوان IP واحد. للقراءة فقط، ويُحتسب من سجل الوكيل، ولا يُستخدم مطلقًا للتوجيه. معطّل افتراضيًا: يظل محرر المجموعة دون تغيير ويُرجع مسار الرصد null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "في فحص سلامة الوكلاء، اسمح للفحص الذي رفضه الهدف (401/403/429: قام الوكيل بالترحيل، لكن الوجهة رفضت عنوان IP الصادر هذا) بإعادة تعيين سلسلة حالات الفشل المتتالية للوكيل، كما لو كان فحصًا تمت خدمته. معطّل افتراضيًا: يظل الرفض محايدًا ويحافظ على السلسلة. تظل استجابة 5xx غير حاسمة في كلتا الحالتين، ولا يؤدي الرفض مطلقًا إلى إزالة وكيل أو تعطيله أو إعادة تنشيطه.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "اسمح لعملية التنظيف التلقائي بحذف مهام Batch API النهائية (المكتملة/الفاشلة/الملغاة/منتهية الصلاحية) الأقدم من OMNIROUTE_BATCH_RETENTION_DAYS، إلى جانب نقاط التحقق الخاصة بكل سطر، ومسح محتوى BLOB للملفات المرفوعة التي تجاوزت قيمة expires_at الخاصة بها. معطّل افتراضيًا: يحتفظ كل تثبيت حالي بهذه البيانات كما كان تمامًا إلى أن يفعّله أحد المشغّلين. لا يتأثر المسار DELETE /api/v1/batches/delete-completed الذي يشغّله المشغّل في كلتا الحالتين — فهو عقد API عام منفصل وغير مشروط.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "عناوين URL لاتصال AI الخاص بك", "apiManager": "مدير API", "apiManagerSubtitle": "إدارة مفاتيح واجهة برمجة التطبيقات والوصول إليها", + "modelCatalog": "النماذج والتركيبات", + "modelCatalogSubtitle": "استعرض النماذج والتركيبات عبر المزودين", "embeddedServices": "الخدمات المدمجة", "embeddedServicesSubtitle": "إدارة خدمات الوكيل المحلية", "logs": "سجلات", diff --git a/src/i18n/messages/az.json b/src/i18n/messages/az.json index 841e44169d81..fef9ceb68fc7 100644 --- a/src/i18n/messages/az.json +++ b/src/i18n/messages/az.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Təchizatçı göndərişi üçün hər bir icarəçi (tenant) üzrə adaptiv virtual qəbul zolaqlarını aktivləşdirin (#9654): bir icarəçinin ani yükü artıq digərinə 503 qaytarmır. OMNIROUTE_CHAT_VIRTUAL_LANES mühit dəyişəni bu idarəetmə paneli ayarından üstündür; dəyişikliklər server yenidən işə salındıqda qüvvəyə minir.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "İdarə panelindəki provayder səhifələri: Pulsuz nişanını yalnız provayderin dəstəklədiyi siqnallar əsasında göstərin — sənədləşdirilmiş pulsuz səviyyəsi olmayan qeydiyyatdan keçmiş provayderlər üçün göstərilən ad evristikasından, Boolean tipli olmayan pulsuz sahələrdən və :free şəkilçilərindən artıq istifadə edilmir. Deaktiv olduqda əvvəlki nişan qaydası saxlanılır.", "featureFlagProxySkipRecentlyFailedDescription": "Proksi hovuzları və opencode-un hər hesab üzrə rotasiyası yenicə uğursuz olmuş proksini (TCP yoxlaması rədd edilib və ya onun vasitəsilə 429 cavabı alınıb) hər təkrarda ikiqat artan, lakin maksimum hədlə məhdudlaşan, hər proses üçün müəyyən edilmiş müddət ərzində yenidən təqdim etmir. Heç bir proksi statusu yazılmır; bütün namizədlər kənara qoyulduqda seçim dəyişməz qalır. Defolt olaraq aktivdir; `false` adi seçimi bərpa edir.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Kvotası çıxış ünvanına görə qruplaşdırılan provayderlər üçün, bu yaxınlarda imtina edilmiş üzvün müşahidə olunan çıxış ünvanını paylaşan hovuz üzvünü sağlam üzvlərdən dərhal sonra sıralayın. Yalnız sıralama üçündür, heç vaxt xaric edilmir. Oxuduğu imtina siqnalını generasiya edən PROXY_SKIP_RECENTLY_FAILED tələb olunur. Standart olaraq qeyri-aktivdir: seçim ardıcıllığı dəqiq adi növbələşmədir.", "featureFlagProxyPoolEgressObservationDescription": "İdarə panelində proksi hovuzunun altında son 24 saat ərzində onun üzvlərinə xidmət göstərən neçə çıxış IP-sinin müşahidə edildiyini, neçə bağlantının onlardan istifadə etdiyini və bir IP-nin arxasında müşahidə edilən ən yüksək sayı göstərin. Yalnız oxuma üçündür, proksi jurnalından hesablanır və marşrutlaşdırma üçün heç vaxt istifadə edilmir. Defolt olaraq deaktivdir: hovuz redaktoru dəyişməz qalır və müşahidə marşrutu null cavabı verir.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proksinin sağlamlıq yoxlamasında hədəfin rədd etdiyi yoxlamanın (401/403/429: proksi sorğunu ötürüb, təyinat nöqtəsi bu çıxış IP-sini rədd edib) uğurla ötürülmüş yoxlama kimi proksinin ardıcıl uğursuzluq sayğacını sıfırlamasına icazə verin. Defolt olaraq deaktivdir: rədd cavabı neytral qalır və ardıcıl uğursuzluq sayğacını dəyişmir. 5xx hər iki halda qeyri-müəyyən qalır və rədd cavabı heç vaxt proksini silmir, deaktiv etmir və ya yenidən aktivləşdirmir.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Avtomatik təmizləmə prosesinə OMNIROUTE_BATCH_RETENTION_DAYS müddətindən daha köhnə olan son vəziyyətdəki (tamamlanmış/uğursuz/ləğv edilmiş/müddəti bitmiş) Batch API tapşırıqlarını onların hər sətir üzrə nəzarət nöqtələri ilə birlikdə silməyə və öz expires_at vaxtı keçmiş yüklənmiş faylların BLOB məzmununu təmizləməyə icazə verin. Defolt olaraq deaktivdir: operator bunu aktiv edənədək bütün mövcud quraşdırmalar bu məlumatları əvvəlki kimi saxlayır. Operator tərəfindən işə salınan DELETE /api/v1/batches/delete-completed marşrutu istənilən halda bundan təsirlənmir — bu, ayrıca və qeyd-şərtsiz ictimai API müqaviləsidir.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AI bağlantı URL-ləriniz", "apiManager": "API açarları", "apiManagerSubtitle": "API açarlarını və girişi idarə edin", + "modelCatalog": "Modellər və Kombolar", + "modelCatalogSubtitle": "Provayderlər üzrə modelləri və komboları nəzərdən keçirin", "embeddedServices": "Daxili Xidmətlər", "embeddedServicesSubtitle": "Lokal proksi xidmətlərini idarə edin", "logs": "Jurnallar", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index 673e539c59c5..00cc53dab72a 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Активирайте адаптивни виртуални ленти за допускане за всеки наемател (tenant) при изпращане към доставчици (#9654): скокът в натоварването на един наемател вече не връща 503 на друг. Променливата на средата OMNIROUTE_CHAT_VIRTUAL_LANES има предимство пред тази настройка в таблото; промените влизат в сила след рестартиране на сървъра.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Страници на доставчиците в таблото: показва значката „Безплатно“ само при сигнали, които доставчикът зачита — премахва евристиката за показваното име, небулевите полета за безплатен достъп и суфиксите :free при регистрирани доставчици без документиран безплатен план. При „Изкл.“ се запазва предишното правило за значката.", "featureFlagProxySkipRecentlyFailedDescription": "Пуловете от проксита и ротацията на opencode за всеки акаунт временно спират повторното използване на прокси, което току-що е дало грешка (отказана TCP проверка или получен чрез него отговор 429), за период в рамките на процеса, който се удвоява при всяко повторение до достигане на максимална стойност. Не се записва състояние на проксито; ако всички кандидати бъдат временно изключени, изборът остава непроменен. Включено по подразбиране; `false` възстановява обикновения избор.", + "featureFlagProxyPoolSharedEgressOrderDescription": "За доставчици, чиято квота е групирана по изходящ адрес, подрежда член на пула, споделящ наблюдавания изходящ адрес на наскоро отказан член, непосредствено след изправните членове. Само подреждане, никога изключване. Изисква PROXY_SKIP_RECENTLY_FAILED, който генерира сигнала за отказ, който се разчита. Изключено по подразбиране: редът на избор е точно стандартната ротация.", "featureFlagProxyPoolEgressObservationDescription": "Показва под пул от проксита в таблото колко наблюдавани изходящи IP адреса са обслужвали членовете му през последните 24 ч., колко връзки са ги използвали и най-големия брой връзки зад един IP адрес. Само за четене, изчислява се от дневника на проксито и никога не се използва за маршрутизиране. Изключено по подразбиране: редакторът на пула остава непроменен, а маршрутът за наблюдение връща null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "При проверката на състоянието на прокситата позволява на проверка, отказана от целта (401/403/429: проксито е препратило заявката, но местоназначението е отказало този изходящ IP адрес), да нулира поредицата от последователни неуспехи на проксито, както при успешно обслужена проверка. Изключено по подразбиране: отказът остава неутрален и запазва поредицата. Отговор 5xx остава неубедителен и в двата случая, а отказът никога не премахва, деактивира или активира повторно прокси.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Позволява на автоматичното почистване да изтрива задания на Batch API в крайно състояние (завършени/неуспешни/отменени/изтекли), по-стари от OMNIROUTE_BATCH_RETENTION_DAYS, заедно с контролните им точки за всеки ред, както и да изчиства BLOB съдържанието на качените файлове след собствената им стойност expires_at. Изключено по подразбиране: всяка съществуваща инсталация продължава да съхранява тези данни точно както преди, докато оператор не активира опцията. Маршрутът DELETE /api/v1/batches/delete-completed, задействан от оператор, не се влияе и в двата случая — той е отделен, безусловен договор на публичния API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Вашите URL адреси за връзка с AI", "apiManager": "API мениджър", "apiManagerSubtitle": "Управление на API ключове и достъп", + "modelCatalog": "Модели и комбинации", + "modelCatalogSubtitle": "Преглед на модели и комбинации от различните доставчици", "embeddedServices": "Вградени услуги", "embeddedServicesSubtitle": "Управление на локални прокси услуги", "logs": "трупи", diff --git a/src/i18n/messages/bn.json b/src/i18n/messages/bn.json index 3eb09187689f..f14e80d1bb5a 100644 --- a/src/i18n/messages/bn.json +++ b/src/i18n/messages/bn.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "প্রোভাইডার ডিসপ্যাচের জন্য প্রতি-টেন্যান্ট অ্যাডাপ্টিভ ভার্চুয়াল অ্যাডমিশন লেন সক্ষম করুন (#9654): এক টেন্যান্টের বিস্ফোরণ আর অন্য টেন্যান্টে 503 ফেরায় না। OMNIROUTE_CHAT_VIRTUAL_LANES এনভায়রনমেন্ট ভেরিয়েবল এই ড্যাশবোর্ড সেটিংয়ের উপরে প্রাধান্য পায়; পরিবর্তনগুলি সার্ভার পুনরায় চালু হলে কার্যকর হয়।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ড্যাশবোর্ডের প্রোভাইডার পেজগুলো: প্রোভাইডার যে সংকেতগুলোকে স্বীকৃতি দেয়, শুধু সেগুলোর ভিত্তিতেই Free ব্যাজ দেখান — নথিভুক্ত ফ্রি টিয়ার নেই এমন নিবন্ধিত প্রোভাইডারগুলোর ক্ষেত্রে ডিসপ্লে-নেম হিউরিস্টিক, নন-বুলিয়ান ফ্রি ফিল্ড এবং :free সাফিক্স বাদ দেওয়া হয়। বন্ধ রাখলে আগের ব্যাজের নিয়ম বজায় থাকে।", "featureFlagProxySkipRecentlyFailedDescription": "প্রক্সি পুল এবং opencode-এর প্রতি-অ্যাকাউন্ট রোটেশন এমন কোনো প্রক্সিকে পুনরায় ব্যবহার করা বন্ধ রাখে, যা সদ্য ব্যর্থ হয়েছে (TCP প্রোব প্রত্যাখ্যাত হয়েছে অথবা সেটির মাধ্যমে 429 পাওয়া গেছে)। প্রতি-প্রসেসে এই বিরতির সময়কাল প্রতিবার পুনরাবৃত্তির সঙ্গে দ্বিগুণ হয়, সর্বোচ্চ সীমা পর্যন্ত। প্রক্সির কোনো স্ট্যাটাস লেখা হয় না; সব প্রার্থীকে সরিয়ে রাখলেও নির্বাচন অপরিবর্তিত থাকে। ডিফল্টভাবে চালু; `false` সাধারণ নির্বাচন ফিরিয়ে আনে।", + "featureFlagProxyPoolSharedEgressOrderDescription": "যেসকল প্রোভাইডারের কোটা egress address অনুসারে ভাগ করা হয়, তাদের ক্ষেত্রে সম্প্রতি প্রত্যাখ্যাত কোনো মেম্বারের পর্যবেক্ষিত egress address শেয়ার করা পুল মেম্বারকে সুস্থ মেম্বারদের ঠিক নিচে স্থান দিন। শুধুমাত্র ক্রম নির্ধারণের জন্য, কখনোই বাদ দেওয়া হয় না। এর জন্য PROXY_SKIP_RECENTLY_FAILED প্রয়োজন, যা এটি দ্বারা পঠিত প্রত্যাখ্যানের সংকেত তৈরি করে। ডিফল্টভাবে নিষ্ক্রিয়: নির্বাচনের ক্রম অবিকল সাধারণ রোটেশন অনুযায়ী হবে।", "featureFlagProxyPoolEgressObservationDescription": "ড্যাশবোর্ডে একটি প্রক্সি পুলের অধীনে দেখান, গত ২৪ ঘণ্টায় পর্যবেক্ষিত কতটি egress IP তার সদস্যদের সেবা দিয়েছে, কতটি সংযোগ সেগুলো ব্যবহার করেছে এবং একটি IP-এর পেছনে সর্বাধিক কতজন সদস্য দেখা গেছে। এটি শুধু পাঠযোগ্য, প্রক্সি লগ থেকে গণনা করা হয় এবং রাউটিংয়ে কখনো ব্যবহার করা হয় না। ডিফল্টভাবে বন্ধ: পুল এডিটর অপরিবর্তিত থাকে এবং পর্যবেক্ষণ রুট null প্রদান করে।", "featureFlagProxyHealthBlockedResetsStreakDescription": "প্রক্সি হেলথ সুইপে, টার্গেট প্রত্যাখ্যান করেছে এমন কোনো প্রোবকে (401/403/429: প্রক্সি রিলে করেছে, কিন্তু গন্তব্য এই egress IP প্রত্যাখ্যান করেছে) সফলভাবে পরিবেশিত প্রোবের মতো প্রক্সির ধারাবাহিক ব্যর্থতার ধারা রিসেট করতে দিন। ডিফল্টভাবে বন্ধ: প্রত্যাখ্যান নিরপেক্ষ থাকে এবং ধারাটি বজায় রাখে। উভয় ক্ষেত্রেই 5xx অনির্ণায়ক থাকে এবং কোনো প্রত্যাখ্যান কখনোই প্রক্সিকে সরায়, নিষ্ক্রিয় করে বা পুনরায় সক্রিয় করে না।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "স্বয়ংক্রিয় ক্লিনআপ সুইপকে OMNIROUTE_BATCH_RETENTION_DAYS-এর চেয়ে পুরোনো টার্মিনাল (সম্পন্ন/ব্যর্থ/বাতিল/মেয়াদোত্তীর্ণ) Batch API জবগুলো তাদের প্রতি-লাইনের চেকপয়েন্টসহ মুছে ফেলতে এবং আপলোড করা ফাইলগুলোর নিজস্ব expires_at পেরিয়ে গেলে সেগুলোর BLOB কনটেন্ট মুছে দিতে দিন। ডিফল্টভাবে বন্ধ: কোনো অপারেটর এটি চালু না করা পর্যন্ত প্রতিটি বিদ্যমান ইনস্টলেশন আগের মতোই এই ডেটা সংরক্ষণ করবে। অপারেটর-ট্রিগার করা DELETE /api/v1/batches/delete-completed রুট উভয় ক্ষেত্রেই অপরিবর্তিত থাকবে — এটি একটি পৃথক, নিঃশর্ত পাবলিক API চুক্তি।", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "আপনার AI কানেকশন ইউআরএল", "apiManager": "API কী", "apiManagerSubtitle": "API কী এবং অ্যাক্সেস পরিচালনা করুন", + "modelCatalog": "মডেল এবং কম্বো", + "modelCatalogSubtitle": "বিভিন্ন প্রোভাইডারের মডেল এবং কম্বো ব্রাউজ করুন", "embeddedServices": "এমবেডেড সার্ভিস", "embeddedServicesSubtitle": "স্থানীয় প্রক্সি সার্ভিস পরিচালনা করুন", "logs": "লগ", diff --git a/src/i18n/messages/bs.json b/src/i18n/messages/bs.json index 9886faf7ceb6..a420c1659679 100644 --- a/src/i18n/messages/bs.json +++ b/src/i18n/messages/bs.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogući adaptivne virtualne trake prijema po tenantu za dispatch provajdera (#9654): burst jednog tenanta više ne uzrokuje 503 grešku drugom. Env varijabla OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost nad ovim override-om na dashboardu; promjene stupaju na snagu nakon ponovnog pokretanja servera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stranice provajdera na dashboardu: prikaži Free bedž samo na signalima koje provajder priznaje — uklanja heuristiku display-name-a, ne-boolean free polja i :free sufikse na registrovanim provajderima bez dokumentiranog besplatnog nivoa. Isključeno zadržava historijsko pravilo za bedževe.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pool-ovi i rotacija po računu za opencode prestaju ponovo posluživati proxy koji je upravo zakazao (odbijena TCP proba ili primljeni 429 kroz njega) za period po procesu koji se udvostručuje pri svakom ponavljanju, do određenog limita. Status proxy-ja se ne zapisuje; sa svakim odloženim kandidatom izbor ostaje nepromijenjen. Podrazumijevano uključeno; `false` vraća običnu selekciju.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Za provajdere čija je kvota grupisana prema egress adresi, rangirajte člana poola koji dijeli zabilježenu egress adresu nedavno odbijenog člana odmah ispod zdravih članova. Samo redoslijed, nikada isključeno. Zahtijeva PROXY_SKIP_RECENTLY_FAILED, koji generiše signal odbijanja koji se očitava. Podrazumijevano isključeno: redoslijed odabira je tačno obična rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Prikaži, unutar proxy pool-a na dashboardu, koliko je opaženih egress IP-ova poslužilo njegove članove u posljednjih 24 h, koliko je konekcija ih koristilo i najviše viđenih iza jednog IP-a. Samo za čitanje, izračunato iz proxy log-a, nikada ne koristi se za rutiranje. Podrazumijevano isključeno: editor pool-a ostaje nepromijenjen, a ruta za opažanje vraća null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "U skeniranju zdravlja proxy-ja, dopusti da proba koju je cilj odbio (401/403/429: proxy je proslijedio, destinacija je odbila ovaj egress IP) resetuje niz uzastopnih neuspjeha proxy-ja, kao i poslužena proba. Podrazumijevano isključeno: odbijanje ostaje neutralno i zadržava niz. 5xx ostaje neodređen u oba slučaja, a odbijanje nikada ne uklanja, onemogućuje ili ponovo aktivira proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dopusti automatskom skeniranju za čišćenje da obriše terminalne (završene/neuspjele/otkazane/istekle) Batch API poslove starije od OMNIROUTE_BATCH_RETENTION_DAYS, zajedno sa njihovim checkpointima po liniji, i očisti BLOB sadržaj uploadovanih datoteka nakon njihovog expires_at. Podrazumijevano isključeno: svaka postojeća instalacija čuva ove podatke tačno kao i ranije dok operator ne odobri. Ruta DELETE /api/v1/batches/delete-completed pokrenuta od strane operatora nije pogođena u oba slučaja -- to je zaseban, bezuvjetni javni API ugovor.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Vaši AI connection URL-ovi", "apiManager": "API ključevi", "apiManagerSubtitle": "Upravljanje API ključevima i pristupom", + "modelCatalog": "Modeli i kombinacije", + "modelCatalogSubtitle": "Pregledajte modele i kombinacije kod različitih provajdera", "embeddedServices": "Ugrađene usluge", "embeddedServicesSubtitle": "Opcionalne lokalne usluge", "logs": "Logovi", diff --git a/src/i18n/messages/cs.json b/src/i18n/messages/cs.json index 6b412ff71d0f..87214ac8c15b 100644 --- a/src/i18n/messages/cs.json +++ b/src/i18n/messages/cs.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Povolte adaptivní virtuální vstupní pruhy pro každého tenanta při odesílání poskytovatelům (#9654): špička jednoho tenanta už nezpůsobí 503 u jiného. Proměnná prostředí OMNIROUTE_CHAT_VIRTUAL_LANES má přednost před tímto nastavením na řídicím panelu; změny se projeví po restartu serveru.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stránky poskytovatelů na řídicím panelu: zobrazí odznak Zdarma pouze na základě příznaků, které poskytovatel podporuje — přestane používat heuristiku zobrazovaného názvu, nebooleovská pole free a přípony :free u registrovaných poskytovatelů bez zdokumentované bezplatné úrovně. Vypnutí zachová původní pravidlo pro odznak.", "featureFlagProxySkipRecentlyFailedDescription": "Fondy proxy serverů a rotace opencode pro jednotlivé účty dočasně přestanou znovu nabízet proxy server, který právě selhal (odmítnutá sonda TCP nebo odpověď 429 přijatá přes tento server), a to na dobu platnou pro daný proces, která se při každém opakování zdvojnásobí až do stanoveného maxima. Stav proxy serveru se nezapisuje; pokud jsou odloženi všichni kandidáti, volba se nemění. Ve výchozím nastavení zapnuto; `false` obnoví prostý výběr.", + "featureFlagProxyPoolSharedEgressOrderDescription": "U poskytovatelů, jejichž kvóta je seskupována podle odchozí adresy, zařadí člena fondu sdílejícího zjištěnou odchozí adresu nedávno odmítnutého člena těsně za zdravé členy. Pouze mění pořadí, nikdy nevylučuje. Vyžaduje PROXY_SKIP_RECENTLY_FAILED, který generuje signál odmítnutí, z něhož čte. Ve výchozím nastavení vypnuto: pořadí výběru přesně odpovídá běžné rotaci.", "featureFlagProxyPoolEgressObservationDescription": "Zobrazit pod fondem proxy serverů na řídicím panelu, kolik pozorovaných odchozích IP adres obsluhovalo jeho členy za posledních 24 h, kolik připojení je použilo a jaký byl nejvyšší počet připojení zaznamenaný za jednou IP adresou. Pouze pro čtení, vypočítáváno z protokolu proxy serveru a nikdy nepoužíváno ke směrování. Ve výchozím nastavení vypnuto: editor fondu zůstává beze změny a trasa pozorování vrací null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Při kontrole stavu proxy serveru umožnit, aby sonda odmítnutá cílem (401/403/429: proxy server požadavek předal, ale cíl odmítl tuto odchozí IP adresu) vynulovala řadu po sobě jdoucích selhání proxy serveru stejně jako úspěšně obsloužená sonda. Ve výchozím nastavení vypnuto: odmítnutí zůstává neutrální a řadu zachovává. Odpověď 5xx zůstává v obou případech neprůkazná a odmítnutí nikdy neodebere, nezakáže ani znovu neaktivuje proxy server.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Povolit automatickému čištění odstraňovat úlohy Batch API v koncovém stavu (dokončené/neúspěšné/zrušené/expirované), které jsou starší než OMNIROUTE_BATCH_RETENTION_DAYS, spolu s jejich kontrolními body pro jednotlivé řádky a mazat obsah BLOB nahraných souborů po uplynutí jejich vlastního expires_at. Ve výchozím nastavení vypnuto: každá stávající instalace uchovává tato data přesně jako dříve, dokud správce tuto funkci nepovolí. Trasa DELETE /api/v1/batches/delete-completed spouštěná správcem zůstává v obou případech beze změny – jde o samostatný, nepodmíněný veřejný kontrakt API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Vaše adresy URL připojení AI", "apiManager": "Správce API", "apiManagerSubtitle": "Správa klíčů API a přístupu", + "modelCatalog": "Modely a kombinace", + "modelCatalogSubtitle": "Procházejte modely a kombinace napříč poskytovateli", "embeddedServices": "Vestavěné služby", "embeddedServicesSubtitle": "Správa místních proxy služeb", "logs": "Protokoly", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index 4acfee478b5b..2371c827cdf9 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivér adaptive virtuelle adgangsbaner pr. tenant til providerudlevering (#9654): en tenants burst giver ikke længere en anden 503. Miljøvariablen OMNIROUTE_CHAT_VIRTUAL_LANES har forrang over denne dashboard-indstilling; ændringer træder i kraft ved genstart af serveren.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Udbydersider i dashboardet: Vis kun Gratis-mærket for signaler, som udbyderen respekterer — dette fjerner heuristikken for visningsnavne, ikke-booleske gratis-felter og :free-suffikser hos registrerede udbydere uden et dokumenteret gratis niveau. Deaktiveret bevarer den tidligere regel for mærket.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy-puljer og rotationen pr. konto for opencode undgår i en periode pr. proces, der fordobles ved hver gentagelse op til en øvre grænse, at genbruge en proxy, som netop har fejlet (afvist TCP-probe eller en 429 modtaget gennem den). Der skrives ingen proxy-status; hvis alle kandidater sættes til side, forbliver valget uændret. Aktiveret som standard; `false` gendanner det almindelige valg.", + "featureFlagProxyPoolSharedEgressOrderDescription": "For udbydere, hvis kvote er opdelt efter egress-adresse, rangeres et poolmedlem, der deler et nyligt afvist medlems observerede egress-adresse, lige under sunde medlemmer. Kun rækkefølge, udelukkes aldrig. Kræver PROXY_SKIP_RECENTLY_FAILED, som genererer det afvisningssignal, den aflæser. Deaktiveret som standard: udvælgelsesrækkefølgen er præcis den almindelige rotation.", "featureFlagProxyPoolEgressObservationDescription": "Vis under en proxy-pulje i dashboardet, hvor mange observerede udgående IP-adresser der har betjent dens medlemmer inden for de seneste 24 timer, hvor mange forbindelser der brugte dem, og det højeste antal observeret bag én IP-adresse. Skrivebeskyttet, beregnet ud fra proxy-loggen og aldrig brugt til routing. Deaktiveret som standard: puljeeditoren er uændret, og observationsruten returnerer null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Lad en probe, som målet afviste (401/403/429: proxyen videresendte anmodningen, men destinationen afviste denne udgående IP-adresse), nulstille proxyens række af fortløbende fejl i proxyens helbredskontrol, ligesom en besvaret probe. Deaktiveret som standard: En afvisning forbliver neutral og bevarer rækken. En 5xx forbliver uafklaret i begge tilfælde, og en afvisning fjerner, deaktiverer eller genaktiverer aldrig en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Lad den automatiske oprydningskørsel slette afsluttede (gennemførte/mislykkede/annullerede/udløbne) Batch API-job, der er ældre end OMNIROUTE_BATCH_RETENTION_DAYS, sammen med deres kontrolpunkter pr. linje, og rydde BLOB-indholdet i uploadede filer, hvis deres expires_at er overskredet. Slået fra som standard: Alle eksisterende installationer beholder disse data præcis som før, indtil en operatør aktivt slår funktionen til. Den operatørudløste rute DELETE /api/v1/batches/delete-completed påvirkes ikke uanset indstillingen – den er en separat, ubetinget offentlig API-kontrakt.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Dine AI-forbindelses-URL'er", "apiManager": "API-nøgler", "apiManagerSubtitle": "Administrer API-nøgler og adgang", + "modelCatalog": "Modeller & kombinationer", + "modelCatalogSubtitle": "Gennemse modeller og kombinationer på tværs af udbydere", "embeddedServices": "Integrerede tjenester", "embeddedServicesSubtitle": "Administrer lokale proxytjenester", "logs": "Logfiler", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index ee0351961858..a2804dd3a4fb 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivieren Sie adaptive virtuelle Zulassungsspuren pro Tenant für die Provider-Zustellung (#9654): Ein Burst eines Tenants führt nicht mehr zu 503 bei einem anderen. Die Umgebungsvariable OMNIROUTE_CHAT_VIRTUAL_LANES hat Vorrang vor dieser Dashboard-Einstellung; Änderungen werden erst nach einem Serverneustart wirksam.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Dashboard-Anbieterseiten: Das Kostenlos-Badge wird nur bei Signalen angezeigt, die der Anbieter berücksichtigt — die Heuristik für Anzeigenamen, nicht boolesche Kostenlos-Felder und :free-Suffixe bei registrierten Anbietern ohne dokumentierten kostenlosen Tarif werden nicht mehr verwendet. Bei deaktivierter Option gilt weiterhin die bisherige Badge-Regel.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy-Pools und die kontobasierte Rotation von opencode verwenden einen Proxy, der gerade fehlgeschlagen ist (abgelehnte TCP-Prüfung oder darüber empfangener 429-Statuscode), für einen prozessbezogenen Zeitraum nicht erneut. Dieser Zeitraum verdoppelt sich bei jeder Wiederholung bis zu einer Obergrenze. Es wird kein Proxy-Status gespeichert; wenn alle Kandidaten zurückgestellt wurden, bleibt die Auswahl unverändert. Standardmäßig aktiviert; `false` stellt die einfache Auswahl wieder her.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Für Provider, deren Quota nach Egress-Adresse gebündelt ist: Stuft ein Pool-Mitglied, das die beobachtete Egress-Adresse eines kürzlich abgewiesenen Mitglieds teilt, direkt unter fehlerfreien Mitgliedern ein. Nur Sortierung, niemals ausgeschlossen. Erfordert PROXY_SKIP_RECENTLY_FAILED, welches das ausgelesene Ablehnungssignal erzeugt. Standardmäßig deaktiviert: Die Auswahlreihenfolge entspricht genau der einfachen Rotation.", "featureFlagProxyPoolEgressObservationDescription": "Zeigt im Dashboard unter einem Proxy-Pool an, wie viele beobachtete Egress-IPs dessen Mitglieder in den letzten 24 h genutzt haben, wie viele Verbindungen über sie liefen und wie viele Verbindungen maximal hinter einer einzelnen IP beobachtet wurden. Schreibgeschützt, aus dem Proxy-Protokoll berechnet und niemals für das Routing verwendet. Standardmäßig deaktiviert: Der Pool-Editor bleibt unverändert und die Beobachtungsroute gibt null zurück.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Ermöglicht bei der Proxy-Zustandsprüfung, dass eine vom Ziel abgelehnte Prüfung (401/403/429: Der Proxy hat die Anfrage weitergeleitet, das Ziel hat diese Egress-IP abgelehnt) die Serie aufeinanderfolgender Fehler des Proxys zurücksetzt, wie bei einer erfolgreich beantworteten Prüfung. Standardmäßig deaktiviert: Eine Ablehnung bleibt neutral und die Serie wird beibehalten. Ein 5xx-Status bleibt in beiden Fällen nicht aussagekräftig, und eine Ablehnung entfernt, deaktiviert oder reaktiviert niemals einen Proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Erlaubt dem automatischen Bereinigungslauf, beendete Batch-API-Aufträge (completed/failed/cancelled/expired), die älter als OMNIROUTE_BATCH_RETENTION_DAYS sind, zusammen mit ihren zeilenweisen Prüfpunkten zu löschen und den BLOB-Inhalt hochgeladener Dateien nach Ablauf ihres jeweiligen expires_at zu leeren. Standardmäßig deaktiviert: Jede bestehende Installation behält diese Daten genau wie bisher, bis ein Betreiber die Funktion aktiviert. Die vom Betreiber ausgelöste Route DELETE /api/v1/batches/delete-completed bleibt unabhängig davon unverändert – sie ist ein separater, bedingungslos geltender öffentlicher API-Vertrag.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Ihre AI-Verbindungs-URLs", "apiManager": "API-Manager", "apiManagerSubtitle": "Verwalten Sie API-Schlüssel und Zugriff", + "modelCatalog": "Modelle & Combos", + "modelCatalogSubtitle": "Modelle und Combos über Provider hinweg durchsuchen", "embeddedServices": "Eingebettete Dienste", "embeddedServicesSubtitle": "Lokale Proxy-Dienste verwalten", "logs": "Protokolle", diff --git a/src/i18n/messages/el.json b/src/i18n/messages/el.json index 9b15dd921783..2cd37945cd06 100644 --- a/src/i18n/messages/el.json +++ b/src/i18n/messages/el.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ενεργοποίηση προσαρμοστικών εικονικών λωρίδων αποδοχής ανά μισθωτή για αποστολή παρόχου (#9654): η αιχμή κίνησης ενός μισθωτή δεν προκαλεί πλέον σφάλματα 503 σε άλλον. Η μεταβλητή περιβάλλοντος OMNIROUTE_CHAT_VIRTUAL_LANES υπερισχύει αυτής της παράκαμψης του πίνακα ελέγχου· οι αλλαγές τίθενται σε ισχύ κατά την επανεκκίνηση του διακομιστή.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Σελίδες παρόχων στον πίνακα ελέγχου: εμφάνιση του σήματος «Δωρεάν» μόνο για ενδείξεις που αναγνωρίζει ο πάροχος — καταργεί τη χρήση του εμφανιζόμενου ονόματος ως ευρετικής μεθόδου, τα μη δυαδικά πεδία δωρεάν χρήσης και τις καταλήξεις :free σε καταχωρισμένους παρόχους χωρίς τεκμηριωμένο δωρεάν επίπεδο. Όταν είναι ανενεργό, διατηρείται ο παλαιότερος κανόνας εμφάνισης του σήματος.", "featureFlagProxySkipRecentlyFailedDescription": "Οι ομάδες διακομιστών μεσολάβησης και η εναλλαγή ανά λογαριασμό του opencode παύουν να χρησιμοποιούν ξανά έναν διακομιστή μεσολάβησης που μόλις απέτυχε (απορρίφθηκε η δοκιμή TCP ή λήφθηκε απόκριση 429 μέσω αυτού) για ένα χρονικό διάστημα ανά διεργασία, το οποίο διπλασιάζεται σε κάθε επανάληψη, έως ένα ανώτατο όριο. Δεν καταγράφεται καμία κατάσταση διακομιστή μεσολάβησης· όταν όλοι οι υποψήφιοι παραμερίζονται, η επιλογή παραμένει αμετάβλητη. Ενεργοποιημένο από προεπιλογή· το `false` επαναφέρει την απλή επιλογή.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Για παρόχους των οποίων το quota ομαδοποιείται ανά διεύθυνση εξόδου, ταξινομήστε ένα μέλος του pool που μοιράζεται την παρατηρηθείσα διεύθυνση εξόδου ενός μέλους που απορρίφθηκε πρόσφατα ακριβώς κάτω από τα υγιή μέλη. Μόνο σειρά, ποτέ αποκλεισμός. Απαιτεί το PROXY_SKIP_RECENTLY_FAILED, το οποίο παράγει το σήμα απόρριψης που διαβάζει. Ανενεργό από προεπιλογή: η σειρά επιλογής είναι ακριβώς η απλή κυκλική εναλλαγή.", "featureFlagProxyPoolEgressObservationDescription": "Εμφάνιση, κάτω από μια ομάδα διακομιστών μεσολάβησης στον πίνακα ελέγχου, του αριθμού των παρατηρούμενων IP εξόδου που εξυπηρέτησαν τα μέλη της κατά τις τελευταίες 24 ώρες, του αριθμού των συνδέσεων που τις χρησιμοποίησαν και του μεγαλύτερου αριθμού συνδέσεων που παρατηρήθηκε πίσω από μία IP. Μόνο για ανάγνωση, υπολογίζεται από το αρχείο καταγραφής του διακομιστή μεσολάβησης και δεν χρησιμοποιείται ποτέ για δρομολόγηση. Απενεργοποιημένο από προεπιλογή: το πρόγραμμα επεξεργασίας της ομάδας παραμένει αμετάβλητο και η διαδρομή παρατήρησης επιστρέφει null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Κατά τον έλεγχο εύρυθμης λειτουργίας των διακομιστών μεσολάβησης, να επιτρέπεται σε μια δοκιμή που απορρίφθηκε από τον προορισμό (401/403/429: ο διακομιστής μεσολάβησης προώθησε το αίτημα, αλλά ο προορισμός απέρριψε αυτήν την IP εξόδου) να μηδενίζει το συνεχόμενο σερί αποτυχιών του διακομιστή μεσολάβησης, όπως μια δοκιμή που εξυπηρετήθηκε. Απενεργοποιημένο από προεπιλογή: μια απόρριψη παραμένει ουδέτερη και διατηρεί το σερί. Μια απόκριση 5xx παραμένει ασαφής και στις δύο περιπτώσεις, ενώ μια απόρριψη δεν αφαιρεί, δεν απενεργοποιεί και δεν επανενεργοποιεί ποτέ έναν διακομιστή μεσολάβησης.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Να επιτρέπεται στην αυτόματη εκκαθάριση να διαγράφει οριστικές (ολοκληρωμένες/αποτυχημένες/ακυρωμένες/ληγμένες) εργασίες Batch API παλαιότερες από OMNIROUTE_BATCH_RETENTION_DAYS, μαζί με τα σημεία ελέγχου ανά γραμμή, και να διαγράφει το περιεχόμενο BLOB των μεταφορτωμένων αρχείων μετά το δικό τους expires_at. Απενεργοποιημένο από προεπιλογή: κάθε υπάρχουσα εγκατάσταση διατηρεί αυτά τα δεδομένα ακριβώς όπως πριν, έως ότου ένας διαχειριστής ενεργοποιήσει τη λειτουργία. Η διαδρομή DELETE /api/v1/batches/delete-completed που ενεργοποιείται από τον διαχειριστή παραμένει ανεπηρέαστη σε κάθε περίπτωση — αποτελεί ξεχωριστή, άνευ όρων δημόσια σύμβαση API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Οι διευθύνσεις URL σύνδεσής σας με AI", "apiManager": "Κλειδιά API", "apiManagerSubtitle": "Διαχείριση κλειδιών API και πρόσβασης", + "modelCatalog": "Μοντέλα & Συνδυασμοί", + "modelCatalogSubtitle": "Περιηγηθείτε σε μοντέλα και συνδυασμούς μεταξύ παρόχων", "embeddedServices": "Ενσωματωμένες υπηρεσίες", "embeddedServicesSubtitle": "Προαιρετικές τοπικές υπηρεσίες", "logs": "Αρχεία καταγραφής", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 5aa91eec63c2..fcdbecca8b21 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1030,6 +1030,8 @@ "endpointsSubtitle": "Your AI connection URLs", "apiManager": "API Keys", "apiManagerSubtitle": "Manage API keys and access", + "modelCatalog": "Models & Combos", + "modelCatalogSubtitle": "Browse models and combos across providers", "embeddedServices": "Embedded Services", "embeddedServicesSubtitle": "Optional local services", "logs": "Logs", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index beabe2dc77e6..f9db1e57d523 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activa carriles de admisión virtuales adaptativos por tenant para el envío de proveedores (#9654): el pico de un tenant ya no devuelve 503 a otro. La variable de entorno OMNIROUTE_CHAT_VIRTUAL_LANES tiene prioridad sobre esta opción del panel; los cambios surten efecto al reiniciar el servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de proveedores del panel: muestra la insignia Gratis solo cuando haya indicios de que el proveedor la admite; descarta la heurística basada en el nombre para mostrar, los campos free no booleanos y los sufijos :free en proveedores registrados sin un nivel gratuito documentado. Si está desactivado, se mantiene la regla histórica de la insignia.", "featureFlagProxySkipRecentlyFailedDescription": "Los grupos de proxies y la rotación por cuenta de opencode dejan de reutilizar temporalmente un proxy que acaba de fallar (sondeo TCP rechazado o un 429 recibido a través de él) durante un período por proceso que se duplica con cada repetición, hasta alcanzar un límite. No se registra ningún estado del proxy; si se apartan todos los candidatos, la elección no cambia. Activado de forma predeterminada; `false` restaura la selección normal.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Para los proveedores cuya cuota se agrupa por dirección de salida, sitúa a un miembro del pool que comparta la dirección de salida observada de un miembro recientemente rechazado justo por debajo de los miembros en buen estado. Solo afecta al orden, nunca se excluye. Requiere PROXY_SKIP_RECENTLY_FAILED, que genera la señal de rechazo que lee. Desactivado por defecto: el orden de selección es exactamente la rotación habitual.", "featureFlagProxyPoolEgressObservationDescription": "Mostrar, debajo de un grupo de proxies en el panel, cuántas IP de salida observadas utilizaron sus miembros durante las últimas 24 h, cuántas conexiones las usaron y el máximo observado detrás de una sola IP. Es de solo lectura, se calcula a partir del registro del proxy y nunca se utiliza para el enrutamiento. Desactivado de forma predeterminada: el editor de grupos no cambia y la ruta de observación devuelve null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "En la comprobación periódica del estado de los proxies, permitir que un sondeo rechazado por el destino (401/403/429: el proxy lo retransmitió, pero el destino rechazó esta IP de salida) reinicie la racha de fallos consecutivos del proxy, como un sondeo atendido. Desactivado de forma predeterminada: un rechazo sigue siendo neutral y mantiene la racha. Un 5xx sigue sin ser concluyente en ambos casos, y un rechazo nunca elimina, desactiva ni reactiva un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permitir que la limpieza automática elimine los trabajos de la API de lotes en estado terminal (completados/fallidos/cancelados/caducados) con una antigüedad superior a OMNIROUTE_BATCH_RETENTION_DAYS, junto con sus puntos de control por línea, y borre el contenido BLOB de los archivos subidos que hayan superado su propio expires_at. Desactivado de forma predeterminada: todas las instalaciones existentes conservan estos datos exactamente como antes hasta que un operador active esta opción. La ruta DELETE /api/v1/batches/delete-completed, activada por el operador, no se ve afectada en ningún caso: es un contrato de API pública independiente e incondicional.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Las URL de su conexión de IA", "apiManager": "Gestor de API", "apiManagerSubtitle": "Administrar claves API y acceso", + "modelCatalog": "Modelos y combos", + "modelCatalogSubtitle": "Explora modelos y combos entre proveedores", "embeddedServices": "Servicios Integrados", "embeddedServicesSubtitle": "Gestionar servicios proxy locales", "logs": "Registros", diff --git a/src/i18n/messages/et.json b/src/i18n/messages/et.json index eb53d2928454..5964c99d3a06 100644 --- a/src/i18n/messages/et.json +++ b/src/i18n/messages/et.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Lubage pakkujale edastamiseks rentnikupõhised kohanduvad virtuaalsed vastuvõturajad (#9654): ühe rentniku koormushoog ei põhjusta enam teisele tõrget 503. Keskkonnamuutuja OMNIROUTE_CHAT_VIRTUAL_LANES alistab selle juhtpaneeli sätte; muudatused jõustuvad serveri taaskäivitamisel.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Juhtpaneeli teenusepakkujate lehed: kuva märk „Tasuta” ainult nende tunnuste puhul, mida teenusepakkuja arvestab — loobu kuvatava nime heuristikast, mitte-tõeväärtuslikest tasuta kasutust tähistavatest väljadest ja järelliidetest :free registreeritud teenusepakkujate puhul, kellel puudub dokumenteeritud tasuta pakett. Väljalülitamisel kasutatakse varasemat märgi kuvamise reeglit.", "featureFlagProxySkipRecentlyFailedDescription": "Puhverserverite kogumid ja opencode'i kontopõhine roteerimine väldivad äsja nurjunud puhverserveri (TCP-proovist keelduti või selle kaudu saadi vastus 429) uuesti kasutamist protsessipõhise ajavahemiku jooksul, mis iga korduva tõrke korral kahekordistub kuni ülempiirini. Puhverserveri olekut ei salvestata; kui kõik kandidaadid kõrvale jäetakse, valik ei muutu. Vaikimisi sees; `false` taastab tavalise valiku.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Pakkujate puhul, kelle kvoot on jaotatud väljuva aadressi alusel, reastatakse hiljuti tagasi lükatud liikme tuvastatud väljuvat aadressi jagav kogumi liige vahetult tervete liikmete järele. Ainult järjestus, ei välistata kunagi. Vajab sätet PROXY_SKIP_RECENTLY_FAILED, mis tekitab selle loetava keeldumissignaali. Vaikimisi väljas: valikujärjekord on täpselt tavapärane rotatsioon.", "featureFlagProxyPoolEgressObservationDescription": "Kuva juhtpaneelil puhverserverite kogumi all, mitu vaadeldud väljuvat IP-aadressi teenindas selle liikmeid viimase 24 tunni jooksul, mitu ühendust neid kasutas ja kui palju ühendusi täheldati enim ühe IP-aadressi taga. Kirjutuskaitstud, arvutatakse puhverserveri logist ja seda ei kasutata kunagi marsruutimiseks. Vaikimisi väljas: kogumi redaktor ei muutu ja vaatlusmarsruut tagastab null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Luba puhverserveri seisundi kontrollimisel sihtkoha poolt tagasi lükatud proovil (401/403/429: puhverserver vahendas päringu, sihtkoht keeldus sellest väljuvast IP-aadressist) lähtestada puhverserveri järjestikuste tõrgete jada nagu teenindatud proovi korral. Vaikimisi väljas: tagasilükkamine jääb neutraalseks ja säilitab jada. 5xx jääb mõlemal juhul ebaselgeks ning tagasilükkamine ei eemalda, keela ega taasaktiveeri kunagi puhverserverit.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Luba automaatsel puhastusel kustutada lõplikus olekus (lõpetatud/ebaõnnestunud/tühistatud/aegunud) Batch API tööd, mis on vanemad kui OMNIROUTE_BATCH_RETENTION_DAYS, koos nende reapõhiste kontrollpunktidega, ning kustutada oma expires_at tähtaja ületanud üleslaaditud failide BLOB-sisu. Vaikimisi väljas: kõik olemasolevad paigaldused säilitavad neid andmeid täpselt nagu varem, kuni operaator selle funktsiooni sisse lülitab. Operaatori käivitatavat marsruuti DELETE /api/v1/batches/delete-completed see valik ei mõjuta — tegemist on eraldiseisva ja tingimusteta avaliku API lepinguga.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Teie tehisintellekti ühenduse URL-id", "apiManager": "API-võtmed", "apiManagerSubtitle": "API-võtmete ja juurdepääsu haldamine", + "modelCatalog": "Mudelid ja kombod", + "modelCatalogSubtitle": "Sirvi mudeleid ja kombosid erinevate pakkujate lõikes", "embeddedServices": "Manustatud teenused", "embeddedServicesSubtitle": "Valikulised kohalikud teenused", "logs": "Logid", diff --git a/src/i18n/messages/fa.json b/src/i18n/messages/fa.json index 0e6265610eb3..303a4b0ae186 100644 --- a/src/i18n/messages/fa.json +++ b/src/i18n/messages/fa.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "خط‌های پذیرش مجازی تطبیقی به‌ازای هر مستاجر (tenant) را برای ارسال به ارائه‌دهندگان فعال کنید (#9654): افزایش ناگهانی بار یک مستاجر دیگر خطای 503 را برای مستاجر دیگر ایجاد نمی‌کند. متغیر محیطی OMNIROUTE_CHAT_VIRTUAL_LANES بر این تنظیم داشبورد اولویت دارد؛ تغییرات پس از راه‌اندازی مجدد سرور اعمال می‌شوند.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "صفحههای ارائهدهندگان در داشبورد: نشان «رایگان» را فقط برای سیگنالهایی نمایش دهید که ارائهدهنده آنها را معتبر میداند — روش اکتشافی نام نمایشی، فیلدهای رایگانِ غیربولین و پسوندهای :free برای ارائهدهندگان ثبتشدهای که سطح رایگان مستندی ندارند، کنار گذاشته میشوند. در حالت خاموش، قاعده تاریخی نشان حفظ میشود.", "featureFlagProxySkipRecentlyFailedDescription": "مخزنهای پراکسی و چرخش بهازای هر حساب در opencode، پراکسیای را که بهتازگی ناموفق بوده است (کاوش TCP را رد کرده یا از طریق آن پاسخ 429 دریافت شده است)، برای مدتی مختص هر فرایند دوباره به کار نمیگیرند؛ این مدت با هر تکرار دو برابر میشود تا به سقف تعیینشده برسد. هیچ وضعیتی برای پراکسی ثبت نمیشود؛ اگر همه گزینهها کنار گذاشته شوند، انتخاب بدون تغییر میماند. به‌طور پیش‌فرض فعال است؛ `false` انتخاب ساده را بازمی‌گرداند.", + "featureFlagProxyPoolSharedEgressOrderDescription": "برای ارائه‌دهندگانی که سهمیه آن‌ها بر اساس آدرس خروجی دسته‌بندی می‌شود، عضوی از استخر که آدرس خروجی مشاهده‌شده آن با عضوی که اخیراً رد شده مشترک است، دقیقاً پس از اعضای سالم رتبه‌بندی می‌شود. فقط در اولویت‌بندی است و هرگز مستثنی نمی‌شود. نیازمند PROXY_SKIP_RECENTLY_FAILED است که سیگنال رد شدن را برای خواندن تولید می‌کند. به‌طور پیش‌فرض غیرفعال است: ترتیب انتخاب دقیقاً همان چرخش عادی است.", "featureFlagProxyPoolEgressObservationDescription": "در داشبورد، زیر هر مخزن پراکسی نشان دهید که طی ۲۴ ساعت گذشته چه تعداد IP خروجی مشاهدهشده به اعضای آن سرویس دادهاند، چه تعداد اتصال از آنها استفاده کردهاند و بیشترین تعداد اتصال مشاهدهشده پشت یک IP چقدر بوده است. این اطلاعات فقط خواندنی است، از گزارش پراکسی محاسبه میشود و هرگز برای مسیریابی استفاده نمیشود. بهطور پیشفرض غیرفعال است: ویرایشگر مخزن بدون تغییر میماند و مسیر مشاهده مقدار null را برمیگرداند.", "featureFlagProxyHealthBlockedResetsStreakDescription": "در پیمایش سلامت پراکسی، اجازه دهید کاوشی که هدف آن را رد کرده است (401/403/429: پراکسی درخواست را عبور داده، اما مقصد این IP خروجی را رد کرده است)، مانند یک کاوش پاسخدادهشده، شمارنده شکستهای متوالی پراکسی را بازنشانی کند. بهطور پیشفرض غیرفعال است: رد شدن همچنان خنثی باقی میماند و شمارنده را حفظ میکند. پاسخ 5xx در هر دو حالت نامشخص باقی میماند و رد شدن هرگز باعث حذف، غیرفعالسازی یا فعالسازی مجدد پراکسی نمیشود.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "به فرایند پاکسازی خودکار اجازه دهید کارهای نهاییشده Batch API (تکمیلشده/ناموفق/لغوشده/منقضیشده) را که بیش از OMNIROUTE_BATCH_RETENTION_DAYS از عمرشان گذشته است، بههمراه نقاط بررسی هر خط آنها حذف کند و محتوای BLOB فایلهای بارگذاریشدهای را که از expires_at خود گذشتهاند پاک کند. بهطور پیشفرض خاموش است: تا زمانی که اپراتور آن را فعال نکند، هر نصب موجود این دادهها را دقیقاً مانند قبل نگه میدارد. مسیر DELETE /api/v1/batches/delete-completed که توسط اپراتور فعال میشود، در هر دو حالت بدون تغییر باقی میماند — این مسیر یک قرارداد API عمومی، مستقل و بدون شرط است.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL های اتصال هوش مصنوعی شما", "apiManager": "کلیدهای API", "apiManagerSubtitle": "کلیدهای API و دسترسی را مدیریت کنید", + "modelCatalog": "مدل‌ها و ترکیب‌ها", + "modelCatalogSubtitle": "مرور مدل‌ها و ترکیب‌ها در میان ارائه‌دهندگان", "embeddedServices": "سرویس‌های جاسازی‌شده", "embeddedServicesSubtitle": "مدیریت سرویس‌های پروکسی محلی", "logs": "گزارشها", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index da3568cc1575..398ed241980f 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ota käyttöön mukautuvat virtuaaliset sisäänottokaistat vuokraajaa (tenant) kohti palveluntarjoajien välitystä varten (#9654): yhden vuokraajan kuormapiikki ei enää aiheuta 503-virhettä toiselle. Ympäristömuuttuja OMNIROUTE_CHAT_VIRTUAL_LANES ohittaa tämän hallintapaneelin asetuksen; muutokset tulevat voimaan palvelimen uudelleenkäynnistyksessä.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Palveluntarjoajien koontinäyttösivut: näytä Free-merkki vain niiden signaalien perusteella, joita palveluntarjoaja noudattaa — tämä poistaa näyttönimeen perustuvan heuristiikan, muut kuin totuusarvoiset free-kentät sekä :free-päätteet rekisteröidyiltä palveluntarjoajilta, joilla ei ole dokumentoitua ilmaistasoa. Pois käytöstä aiempi merkkisääntö säilyy.", "featureFlagProxySkipRecentlyFailedDescription": "Välityspalvelinpoolit ja opencoden tilikohtainen kierto estävät juuri epäonnistuneen välityspalvelimen (hylätty TCP-tarkistus tai sen kautta saatu 429-vastaus) tarjoamisen uudelleen prosessikohtaisen ajanjakson ajan. Ajanjakso kaksinkertaistuu jokaisen toistuvan epäonnistumisen myötä enimmäisrajaan asti. Välityspalvelimen tilaa ei kirjata; jos kaikki ehdokkaat on siirretty sivuun, valinta pysyy ennallaan. Oletusarvoisesti käytössä; `false` palauttaa tavallisen valinnan.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Palveluntarjoajille, joiden kiintiö jaotellaan egress-osoitteen perusteella: aseta poolin jäsen, jolla on äskettäin hylätyn jäsenen havaittu egress-osoite, juuri terveiden jäsenten alapuolelle. Vain järjestys, ei koskaan poissuljettu. Vaatii asetuksen PROXY_SKIP_RECENTLY_FAILED, joka tuottaa sen lukeman hylkäyssignaalin. Oletuksena pois päältä: valintajärjestys on täsmälleen tavallinen kierto.", "featureFlagProxyPoolEgressObservationDescription": "Näytä hallintapaneelissa välityspalvelinpoolin kohdalla, kuinka monta havaittua lähtevän liikenteen IP-osoitetta sen jäsenet käyttivät viimeisten 24 tunnin aikana, kuinka monta yhteyttä käytti niitä ja kuinka monta yhteyttä enimmillään havaittiin yhden IP-osoitteen takana. Vain luku -tieto, joka lasketaan välityspalvelinlokista ja jota ei koskaan käytetä reititykseen. Oletusarvoisesti poissa käytöstä: poolieditori säilyy ennallaan ja havaintoreitti palauttaa arvon null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Salli välityspalvelinten kuntotarkistuksessa sellaisen tarkistuksen, jonka kohde hylkäsi (401/403/429: välityspalvelin välitti pyynnön, mutta kohde hylkäsi tämän lähtevän liikenteen IP-osoitteen), nollata välityspalvelimen peräkkäisten epäonnistumisten sarja onnistuneesti palvellun tarkistuksen tavoin. Oletusarvoisesti poissa käytöstä: hylkäys pysyy neutraalina eikä katkaise sarjaa. 5xx-vastaus pysyy kummassakin tapauksessa tuloksettomana, eikä hylkäys koskaan poista välityspalvelinta, poista sitä käytöstä tai aktivoi sitä uudelleen.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Anna automaattisen puhdistuksen poistaa OMNIROUTE_BATCH_RETENTION_DAYS-arvoa vanhemmat päättyneet (valmistuneet/epäonnistuneet/peruutetut/vanhentuneet) Batch API -työt sekä niiden rivikohtaiset tarkistuspisteet ja tyhjentää niiden ladattujen tiedostojen BLOB-sisältö, joiden oma expires_at-ajankohta on ohitettu. Oletusarvoisesti poissa käytöstä: jokainen nykyinen asennus säilyttää nämä tiedot täsmälleen kuten ennenkin, kunnes ylläpitäjä ottaa toiminnon käyttöön. Ylläpitäjän käynnistämään DELETE /api/v1/batches/delete-completed -reittiin tällä ei ole vaikutusta — se on erillinen, ehdoton julkinen API-sopimus.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AI-yhteytesi URL-osoitteet", "apiManager": "API-avaimet", "apiManagerSubtitle": "Hallinnoi API-avaimia ja käyttöoikeuksia", + "modelCatalog": "Mallit ja yhdistelmät", + "modelCatalogSubtitle": "Selaa malleja ja yhdistelmiä eri palveluntarjoajilta", "embeddedServices": "Upotetut palvelut", "embeddedServicesSubtitle": "Hallitse paikallisia välityspalvelimia", "logs": "Lokit", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 355fd1beb193..e20d3bba94c4 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activez des voies d'admission virtuelles adaptatives par tenant pour la répartition des fournisseurs (#9654) : le pic d'un tenant ne renvoie plus 503 à un autre. La variable d'environnement OMNIROUTE_CHAT_VIRTUAL_LANES prime sur ce réglage du tableau de bord ; les modifications prennent effet au redémarrage du serveur.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pages des fournisseurs du tableau de bord : affiche le badge Gratuit uniquement pour les indicateurs reconnus par le fournisseur — abandonne l’heuristique basée sur le nom d’affichage, les champs free non booléens et les suffixes :free pour les fournisseurs enregistrés ne disposant pas d’une offre gratuite documentée. Lorsque cette option est désactivée, la règle historique du badge est conservée.", "featureFlagProxySkipRecentlyFailedDescription": "Les pools de proxys et la rotation par compte d’opencode cessent de réutiliser un proxy qui vient d’échouer (sonde TCP refusée ou réponse 429 reçue par son intermédiaire) pendant une durée propre au processus qui double à chaque nouvel échec, jusqu’à une limite maximale. Aucun état de proxy n’est enregistré ; lorsque tous les candidats sont écartés, le choix reste inchangé. Activé par défaut ; `false` rétablit la sélection simple.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Pour les fournisseurs dont le quota est compartimenté par adresse de sortie, classe un membre du pool partageant l'adresse de sortie observée d'un membre récemment refusé juste en dessous des membres sains. Changement d'ordre uniquement, jamais exclu. Nécessite PROXY_SKIP_RECENTLY_FAILED, qui produit le signal de refus qu'il lit. Désactivé par défaut : l'ordre de sélection correspond exactement à la rotation standard.", "featureFlagProxyPoolEgressObservationDescription": "Afficher, sous un pool de proxys dans le tableau de bord, combien d’adresses IP de sortie observées ont servi ses membres au cours des dernières 24 h, combien de connexions les ont utilisées et le nombre maximal observé derrière une même adresse IP. En lecture seule, calculé à partir du journal du proxy, jamais utilisé pour le routage. Désactivé par défaut : l’éditeur de pool reste inchangé et la route d’observation renvoie null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Lors du contrôle d’intégrité des proxys, permettez à une sonde refusée par la cible (401/403/429 : le proxy a relayé la requête, mais la destination a refusé cette adresse IP de sortie) de réinitialiser la série d’échecs consécutifs du proxy, comme une sonde traitée. Désactivé par défaut : un refus reste neutre et maintient la série. Une réponse 5xx reste non concluante dans les deux cas, et un refus ne supprime, ne désactive ni ne réactive jamais un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Autoriser le nettoyage automatique à supprimer les tâches Batch API dans un état terminal (terminées/échouées/annulées/expirées) datant de plus de OMNIROUTE_BATCH_RETENTION_DAYS, ainsi que leurs points de contrôle par ligne, et à effacer le contenu BLOB des fichiers téléversés dont la valeur expires_at est dépassée. Désactivé par défaut : chaque installation existante conserve ces données exactement comme auparavant jusqu’à ce qu’un opérateur active cette option. La route DELETE /api/v1/batches/delete-completed déclenchée par l’opérateur n’est affectée dans aucun des cas : il s’agit d’un contrat d’API publique distinct et inconditionnel.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Vos URL de connexion IA", "apiManager": "Gestionnaire d'API", "apiManagerSubtitle": "Gérer les clés API et l'accès", + "modelCatalog": "Modèles & combinaisons", + "modelCatalogSubtitle": "Parcourir les modèles et les combinaisons de tous les fournisseurs", "embeddedServices": "Services Intégrés", "embeddedServicesSubtitle": "Gérer les services proxy locaux", "logs": "Journaux", diff --git a/src/i18n/messages/ga.json b/src/i18n/messages/ga.json index 8b500f39ba50..f0fce35a437d 100644 --- a/src/i18n/messages/ga.json +++ b/src/i18n/messages/ga.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Cumasaigh lánaí iontrála oiriúnaitheacha fíorúla in aghaidh an tionónta le haghaidh seolta soláthraí (#9654): ní chruthaíonn pléascadh tionónta amháin 503 do thionónta eile a thuilleadh. Tá an athróg timpeallachta OMNIROUTE_CHAT_VIRTUAL_LANES níos cumhachtaí ná an sárú deais seo; tagann athruithe i bhfeidhm ag atosú freastalaí.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leathanaigh soláthraithe na deaise: ná taispeáin an suaitheantas Saor in aisce ach amháin i gcás comharthaí a n-aithníonn an soláthraí iad — fágtar ar lár heorastach an ainm taispeána, réimsí free nach réimsí Boole iad agus iarmhíreanna :free ar sholáthraithe cláraithe nach bhfuil sraith shaor in aisce dhoiciméadaithe acu. Nuair atá sé múchta, coinnítear riail stairiúil an tsuaitheantais.", "featureFlagProxySkipRecentlyFailedDescription": "Cuireann linnte seachfhreastalaí agus rothlú opencode in aghaidh an chuntais cosc ar sheachfhreastalaí ar theip air díreach (diúltaíodh don tóireadóir TCP, nó fuarthas 429 tríd) a sheirbheáil arís ar feadh tréimhse in aghaidh an phróisis a dhúblaíonn le gach teip eile, suas le huasteorainn. Ní scríobhtar aon stádas seachfhreastalaí; má chuirtear gach iarrthóir ar leataobh, fanann an rogha gan athrú. Ar siúl de réir réamhshocraithe; athbhunaíonn `false` an gnáthroghnú.", + "featureFlagProxyPoolSharedEgressOrderDescription": "I gcás soláthraithe a bhfuil a gcóta grúpáilte de réir seoladh eislise, déan comhalta linne a roinneann seoladh eislise breathnaithe comhalta a diúltaíodh le déanaí a rangú díreach faoi bhun comhaltaí sláintiúla. Ord amháin, gan a bheith eisiata riamh. Teastaíonn PROXY_SKIP_RECENTLY_FAILED uaidh, a ghineann an comhartha diúltaithe a léann sé. Múchta de réir réamhshocraithe: is é an gnáthrothlú go díreach an t-ord roghnaithe.", "featureFlagProxyPoolEgressObservationDescription": "Taispeáin, faoi linn seachfhreastalaí sa deais, cé mhéad seoladh IP amach a breathnaíodh a d’fhreastail ar a bhaill le 24 h anuas, cé mhéad nasc a d’úsáid iad agus an líon is mó a chonacthas taobh thiar d’aon IP amháin. Inléite amháin, ríofa ón loga seachfhreastalaí, agus ní úsáidtear riamh é le haghaidh ródúcháin. As de réir réamhshocraithe: fanann eagarthóir na linne gan athrú agus freagraíonn bealach na breathnóireachta le null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "I scuabadh sláinte an tseachfhreastalaí, lig do thóraíocht ar dhiúltaigh an sprioc di (401/403/429: rinne an seachfhreastalaí athsheoladh, ach dhiúltaigh an ceann scríbe don seoladh IP amach seo) stríoc teipeanna comhleanúnacha an tseachfhreastalaí a athshocrú, amhail tóraíocht a seirbheáladh. As de réir réamhshocraithe: fanann diúltú neodrach agus coinníonn sé an stríoc. Fanann 5xx neamhchinntitheach sa dá chás, agus ní bhaineann diúltú seachfhreastalaí choíche, ní dhíchumasaíonn sé é ná ní athghníomhachtaíonn sé é.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Lig don ghlanadh uathoibríoch jabanna teirminéil (críochnaithe/teipthe/curtha ar ceal/éagtha) Batch API atá níos sine ná OMNIROUTE_BATCH_RETENTION_DAYS a scriosadh, mar aon lena seicphointí in aghaidh na líne, agus inneachar BLOB na gcomhad uaslódáilte atá thar a expires_at féin a ghlanadh. Díchumasaithe de réir réamhshocraithe: coimeádann gach suiteáil atá ann cheana na sonraí seo díreach mar a rinneadh roimhe seo go dtí go roghnaíonn oibreoir é seo a chumasú. Ní dhéantar aon difear don bhealach DELETE /api/v1/batches/delete-completed a spreagann oibreoir i gceachtar cás — is conradh API poiblí ar leith agus neamhchoinníollach é.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Do URLanna naisc AI", "apiManager": "Eochracha API", "apiManagerSubtitle": "Bainistigh eochracha API agus rochtain", + "modelCatalog": "Múnlaí & Teaglamaí", + "modelCatalogSubtitle": "Brabhsáil múnlaí agus teaglamaí trasna soláthraithe", "embeddedServices": "Seirbhísí Leabaithe", "embeddedServicesSubtitle": "Seirbhísí áitiúla roghnacha", "logs": "Logaí", diff --git a/src/i18n/messages/gu.json b/src/i18n/messages/gu.json index fd1e59db2acf..486cf8ca0427 100644 --- a/src/i18n/messages/gu.json +++ b/src/i18n/messages/gu.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "પ્રોવાઇડર ડિસ્પેચ માટે પ્રતિ-ટેનન્ટ અનુકૂલનશીલ વર્ચ્યુઅલ એડમિશન લેન સક્ષમ કરો (#9654): એક ટેનન્ટનો બર્સ્ટ હવે બીજા ટેનન્ટને 503 આપતો નથી. OMNIROUTE_CHAT_VIRTUAL_LANES એન્વાયર્નમેન્ટ વેરિયેબલ આ ડેશબોર્ડ સેટિંગ કરતાં વધુ પ્રાધાન્ય ધરાવે છે; ફેરફારો સર્વર પુનઃપ્રારંભ પર અસરકારક થાય છે.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ડૅશબોર્ડના પ્રદાતા પૃષ્ઠો: ફક્ત પ્રદાતા માન્ય રાખે તેવા સંકેતો પર જ મફત બૅજ બતાવો — દસ્તાવેજીકૃત મફત સ્તર વિનાના નોંધાયેલા પ્રદાતાઓ માટે ડિસ્પ્લે-નામનું હ્યુરિસ્ટિક, બિન-બૂલિયન મફત ફીલ્ડ્સ અને :free પ્રત્યયો દૂર કરે છે. બંધ રાખવાથી ઐતિહાસિક બૅજ નિયમ જળવાઈ રહે છે.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pools અને opencodeનું પ્રતિ-એકાઉન્ટ રોટેશન, હમણાં જ નિષ્ફળ ગયેલા પ્રોક્સીને (TCP પ્રોબ નકારાયો હોય અથવા તેના મારફતે 429 મળ્યો હોય) દરેક પુનરાવર્તન સાથે બમણા થતા, મહત્તમ મર્યાદા સુધીના પ્રતિ-પ્રોસેસ સમયગાળા માટે ફરીથી સર્વ કરવાનું બંધ કરે છે. પ્રોક્સીની કોઈ સ્થિતિ લખવામાં આવતી નથી; દરેક ઉમેદવારને બાજુ પર રાખવામાં આવે તો પસંદગી યથાવત્ રહે છે. ડિફૉલ્ટ રૂપે ચાલુ; `false` સાદી પસંદગી પાછી લાવે છે.", + "featureFlagProxyPoolSharedEgressOrderDescription": "જે પ્રદાતાઓનો ક્વોટા ઇગ્રેસ એડ્રેસ દ્વારા બકેટ કરેલ છે, તેમના માટે તાજેતરમાં નકારેલા સભ્યના અવલોકિત ઇગ્રેસ એડ્રેસને શેર કરતા પૂલ સભ્યને સ્વસ્થ સભ્યોની બરાબર નીચે ક્રમ આપો. ફક્ત ક્રમ બદલાશે, ક્યારેય બાકાત રાખવામાં આવશે નહીં. PROXY_SKIP_RECENTLY_FAILED જરૂરી છે, જે તે વાંચે છે તે રિફ્યુઝલ સિગ્નલ ઉત્પન્ન કરે છે. ડિફૉલ્ટ રૂપે બંધ: પસંદગીનો ક્રમ સામાન્ય રોટેશન મુજબ જ રહે છે.", "featureFlagProxyPoolEgressObservationDescription": "ડૅશબોર્ડમાં પ્રોક્સી પૂલ હેઠળ બતાવો કે છેલ્લા 24 કલાકમાં કેટલા નિરીક્ષિત એગ્રેસ IPએ તેના સભ્યોને સેવા આપી, કેટલાં કનેક્શનોએ તેમનો ઉપયોગ કર્યો અને એક IP પાછળ સૌથી વધુ કેટલાં કનેક્શન જોવા મળ્યાં. આ માહિતી ફક્ત વાંચવા માટે છે, પ્રોક્સી લૉગમાંથી ગણવામાં આવે છે અને રૂટિંગ માટે ક્યારેય ઉપયોગમાં લેવાતી નથી. ડિફૉલ્ટ રૂપે બંધ: પૂલ એડિટર યથાવત્ રહે છે અને નિરીક્ષણ રૂટ null પરત કરે છે.", "featureFlagProxyHealthBlockedResetsStreakDescription": "પ્રોક્સી હેલ્થ સ્વીપમાં, લક્ષ્ય દ્વારા નકારવામાં આવેલા પ્રોબને (401/403/429: પ્રોક્સીએ રિલે કર્યું, ગંતવ્યે આ એગ્રેસ IPને નકાર્યો) સર્વ કરાયેલા પ્રોબની જેમ પ્રોક્સીની સળંગ નિષ્ફળતાઓની શ્રેણી રીસેટ કરવાની મંજૂરી આપો. ડિફૉલ્ટ રૂપે બંધ: નકાર તટસ્થ રહે છે અને શ્રેણી જાળવી રાખે છે. બંને સ્થિતિમાં 5xx અનિર્ણાયક રહે છે, અને નકાર ક્યારેય પ્રોક્સીને દૂર, અક્ષમ અથવા ફરી સક્રિય કરતો નથી.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "સ્વચાલિત ક્લીનઅપ સ્વીપને OMNIROUTE_BATCH_RETENTION_DAYS કરતાં જૂની, અંતિમ સ્થિતિમાં રહેલી (પૂર્ણ/નિષ્ફળ/રદ કરેલી/સમાપ્ત) Batch API jobs ને તેમના પ્રત્યેક-લાઇન checkpoints સાથે કાઢી નાખવા દો અને તેમની પોતાની expires_at વીતી ગયેલી અપલોડ કરેલી ફાઇલોની BLOB સામગ્રી સાફ કરવા દો. ડિફૉલ્ટ રૂપે બંધ: ઑપરેટર તેને સક્રિય ન કરે ત્યાં સુધી દરેક હાલનું ઇન્સ્ટોલેશન આ ડેટાને પહેલાંની જેમ જ રાખે છે. ઑપરેટર દ્વારા ટ્રિગર થતો DELETE /api/v1/batches/delete-completed રૂટ કોઈપણ સ્થિતિમાં અપ્રભાવિત રહે છે — તે એક અલગ, બિનશરતી જાહેર API કરાર છે.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "તમારા AI કનેક્શન URL", "apiManager": "API કીઝ", "apiManagerSubtitle": "API કી અને એક્સેસ મેનેજ કરો", + "modelCatalog": "મોડલ્સ અને કૉમ્બોઝ", + "modelCatalogSubtitle": "પ્રદાતાઓ વચ્ચે મોડલ્સ અને કૉમ્બોઝ બ્રાઉઝ કરો", "embeddedServices": "એમ્બેડ સેવાઓ", "embeddedServicesSubtitle": "સ્થાનિક પ્રોક્સી સેવાઓ મેનેજ કરો", "logs": "લૉગ્સ", diff --git a/src/i18n/messages/ha.json b/src/i18n/messages/ha.json index 8f61498d2c10..85946d49ae4f 100644 --- a/src/i18n/messages/ha.json +++ b/src/i18n/messages/ha.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Kunna layukan karɓa na kama-da-wane masu daidaitawa ga kowane tenant domin aika buƙatu zuwa provider (#9654): yawaitar buƙatun tenant ɗaya ba za ta sake jawo wa wani kuskuren 503 ba. Env var na OMNIROUTE_CHAT_VIRTUAL_LANES yana da fifiko kan wannan sauyin dashboard; sauye-sauye za su fara aiki bayan sake kunna server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Shafukan masu samarwa na Dashboard: nuna alamar Kyauta kawai bisa alamomin da mai samarwar ya tabbatar — wannan yana watsi da dabarar hasashen sunan nuni, filayen kyauta marasa ƙimar boolean, da kari na :free a kan masu samarwa da aka yi wa rajista waɗanda ba su da matakin kyauta da aka rubuta. Idan an Kashe, ana ci gaba da amfani da tsohuwar ƙa’idar alamar.", "featureFlagProxySkipRecentlyFailedDescription": "Rukunin proxy da juyawar opencode ta kowane asusu suna daina sake amfani da proxy da ya gaza kwanan nan (ya ƙi gwajin TCP, ko aka karɓi 429 ta cikinsa) na wani lokaci na kowane tsari wanda ke ninkuwa a duk lokacin da gazawar ta sake faruwa, har zuwa iyaka. Ba a rubuta matsayin proxy; idan aka ware dukkan waɗanda za a iya zaɓa, zaɓin ba ya canzawa. A kunne yake ta tsohuwa; `false` yana dawo da zaɓi na yau da kullum.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Ga masu ba da sabis waɗanda aka tsara kasonsu ta adireshin egress, sanya memban pool mai raba adireshin egress ɗin da aka lura da shi na memban da aka ƙi kwanan nan a ƙasa kaɗan da membobi masu lafiya. Tsarin jeri kawai, ba a taɓa cirewa ba. Yana buƙatar PROXY_SKIP_RECENTLY_FAILED, wanda ke samar da siginar ƙin yarda da yake karantawa. A kashe yake a matsayin asali: tsarin zaɓi yana bin juyawa ta asali ce kawai.", "featureFlagProxyPoolEgressObservationDescription": "A ƙarƙashin rukunin proxy a dashboard, nuna adadin IPs na fita da aka lura sun yi wa membobinsa hidima a cikin awanni 24 da suka gabata, adadin haɗin da suka yi amfani da su, da mafi yawan adadin da aka gani a bayan IP guda. Na karantawa kawai ne, ana lissafa shi daga kundin proxy, kuma ba a taɓa amfani da shi wajen routing. A kashe yake ta tsohuwa: editan rukuni ba ya canzawa kuma hanyar lura tana amsa null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "A yayin binciken lafiyar proxy, bari gwajin da manufa ta ƙi (401/403/429: proxy ya isar, amma wurin da ake nufi ya ƙi wannan IP na fita) ya sake saita jerin gazawar proxy masu jere, kamar gwajin da aka yi wa hidima. A kashe yake ta tsohuwa: ƙin amincewa yana kasancewa tsaka-tsaki kuma yana riƙe da jerin gazawar. 5xx yana kasancewa mara tabbas a kowane hali, kuma ƙin amincewa ba ya taɓa cirewa, kashewa ko sake kunna proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Bari aikin sharewa ta atomatik ya goge ayyukan Batch API da suka ƙare (an kammala/an gaza/an soke/lokaci ya ƙare) waɗanda suka girmi OMNIROUTE_BATCH_RETENTION_DAYS, tare da wuraren ci-gaban kowane layinsu, sannan ya share abun cikin BLOB na fayilolin da aka ɗora waɗanda lokacinsu na expires_at ya wuce. A kashe yake ta tsohuwa: duk shigarwar da ake da ita za ta ci gaba da riƙe wannan bayanin daidai kamar da har sai mai gudanarwa ya kunna shi. Hanyar DELETE /api/v1/batches/delete-completed da mai gudanarwa ke jawowa ba ta canzawa a kowane hali — wata yarjejeniyar API ta jama'a ce daban wadda ba ta da sharaɗi.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URLs na haɗin AI ɗinka", "apiManager": "Maɓallan API", "apiManagerSubtitle": "Sarrafa maɓallan API da samun dama", + "modelCatalog": "Samfura & Haɗe-haɗe", + "modelCatalogSubtitle": "Bincika samfura da haɗe-haɗe a duk faɗin masu ba da sabis", "embeddedServices": "Ayyukan da aka haɗa ciki", "embeddedServicesSubtitle": "Ayyukan gida na zaɓi", "logs": "Rajistoci", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index 74451064dd30..8b47487cccb5 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "הפעל נתיבי קבלה וירטואליים אדפטיביים לכל דייר (tenant) עבור שליחת ספקים (#9654): פרץ עומס של דייר אחד כבר לא מחזיר 503 לדייר אחר. משתנה הסביבה OMNIROUTE_CHAT_VIRTUAL_LANES גובר על הגדרה זו בלוח הבקרה; השינויים נכנסים לתוקף לאחר הפעלת השרת מחדש.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "דפי הספקים בלוח הבקרה: הצגת תג החינם רק על סמך סימנים שהספק מכיר בהם — ללא היוריסטיקת שם התצוגה, שדות חינמיים שאינם בוליאניים וסיומות :free אצל ספקים רשומים שאין להם שכבה חינמית מתועדת. במצב כבוי, כלל התג ההיסטורי נשמר.", "featureFlagProxySkipRecentlyFailedDescription": "מאגרי פרוקסי והתחלופה לפי חשבון של opencode מפסיקים להשתמש מחדש בפרוקסי שזה עתה נכשל (בדיקת TCP נדחתה, או שהתקבלה דרכו תגובת 429) למשך פרק זמן נפרד לכל תהליך, שמוכפל בכל הישנות עד לתקרה. לא נכתב סטטוס לפרוקסי; כאשר כל המועמדים מושהים, הבחירה נשארת ללא שינוי. מופעל כברירת מחדל; `false` מחזיר את הבחירה הרגילה.", + "featureFlagProxyPoolSharedEgressOrderDescription": "עבור ספקים שהמכסה שלהם מחולקת לפי כתובת יציאה (egress), דרג חבר pool שחולק את כתובת היציאה שנצפתה עבור חבר שנדחה לאחרונה ממש מתחת לחברים תקינים. קביעת סדר בלבד, ללא החרגה. דורש את PROXY_SKIP_RECENTLY_FAILED, המפיק את אות הסירוב שהוא קורא. מושבת כברירת מחדל: סדר הבחירה הוא בדיוק הרוטציה הרגילה.", "featureFlagProxyPoolEgressObservationDescription": "הצגת מספר כתובות ה-IP ליציאה שנצפו בקרב חברי מאגר הפרוקסי במהלך 24 השעות האחרונות, מספר החיבורים שהשתמשו בהן ומספר החיבורים המרבי שנצפה מאחורי כתובת IP אחת, מתחת למאגר בלוח הבקרה. לקריאה בלבד, מחושב מיומן הפרוקסי ולעולם אינו משמש לניתוב. מושבת כברירת מחדל: עורך המאגר נשאר ללא שינוי ונתיב התצפית מחזיר null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "בסריקת תקינות הפרוקסי, יש לאפשר לבדיקה שהיעד דחה (401/403/429: הפרוקסי העביר את הבקשה, והיעד דחה את כתובת ה-IP הזו ליציאה) לאפס את רצף הכשלים העוקבים של הפרוקסי, כמו בדיקה שנענתה. מושבת כברירת מחדל: דחייה נשארת ניטרלית ושומרת על הרצף. תגובת 5xx נשארת בלתי מכרעת בכל מקרה, ודחייה לעולם אינה מסירה, משביתה או מפעילה מחדש פרוקסי.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "לאפשר לסריקת הניקוי האוטומטית למחוק משימות Batch API במצב סופי (שהושלמו/נכשלו/בוטלו/פג תוקפן) שגילן עולה על OMNIROUTE_BATCH_RETENTION_DAYS, יחד עם נקודות הביקורת שלהן לכל שורה, ולנקות את תוכן ה-BLOB של קבצים שהועלו לאחר שעבר מועד ה-expires_at שלהם. האפשרות מושבתת כברירת מחדל: כל התקנה קיימת ממשיכה לשמור את הנתונים האלה בדיוק כמו קודם, עד שמפעיל המערכת בוחר להפעיל אותה. הנתיב DELETE /api/v1/batches/delete-completed, שמופעל על ידי מפעיל המערכת, אינו מושפע בכל מקרה — זהו חוזה API ציבורי נפרד ובלתי מותנה.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "כתובות ה-URL של חיבור הבינה המלאכותית שלך", "apiManager": "מנהל API", "apiManagerSubtitle": "נהל מפתחות API וגישה", + "modelCatalog": "מודלים ושילובים", + "modelCatalogSubtitle": "עיון במודלים ובשילובים בין ספקים שונים", "embeddedServices": "שירותים מוטמעים", "embeddedServicesSubtitle": "ניהול שירותי פרוקסי מקומיים", "logs": "יומנים", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index 5b3b8d68c870..d79c8d5d1705 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदाता डिस्पैच के लिए प्रति-टेनेंट अनुकूली वर्चुअल एडमिशन लेन सक्षम करें (#9654): एक टेनेंट का बर्स्ट अब दूसरे टेनेंट को 503 नहीं देता। OMNIROUTE_CHAT_VIRTUAL_LANES पर्यावरण चर इस डैशबोर्ड सेटिंग पर प्राथमिकता रखता है; परिवर्तन सर्वर पुनः आरंभ पर प्रभावी होते हैं।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "डैशबोर्ड प्रदाता पेज: Free बैज केवल उन संकेतों के आधार पर दिखाएँ जिन्हें प्रदाता मान्यता देता है — यह डिस्प्ले-नाम अनुमान, गैर-बूलियन free फ़ील्ड और बिना दस्तावेज़ीकृत मुफ़्त टियर वाले पंजीकृत प्रदाताओं पर :free प्रत्ययों को हटा देता है। बंद होने पर ऐतिहासिक बैज नियम लागू रहता है।", "featureFlagProxySkipRecentlyFailedDescription": "Proxy पूल और opencode का प्रति-अकाउंट रोटेशन, हाल ही में विफल हुए Proxy (अस्वीकृत TCP प्रोब या उसके माध्यम से प्राप्त 429) को प्रति-प्रोसेस अवधि तक दोबारा उपयोग नहीं करता है। यह अवधि हर बार विफलता दोहराए जाने पर दोगुनी होती है, एक अधिकतम सीमा तक। Proxy की कोई स्थिति लिखी नहीं जाती; प्रत्येक उम्मीदवार को अलग रखे जाने पर चयन अपरिवर्तित रहता है। डिफ़ॉल्ट रूप से चालू; `false` सामान्य चयन बहाल करता है।", + "featureFlagProxyPoolSharedEgressOrderDescription": "उन प्रदाताओं के लिए जिनका कोटा egress address के अनुसार बकेट किया जाता है, हाल ही में अस्वीकृत सदस्य के देखे गए egress address को साझा करने वाले पूल सदस्य को स्वस्थ सदस्यों के ठीक नीचे रैंक करें। केवल क्रमबद्ध किया जाता है, कभी बाहर नहीं किया जाता। इसके लिए PROXY_SKIP_RECENTLY_FAILED की आवश्यकता होती है, जो अस्वीकृति सिग्नल उत्पन्न करता है जिसे यह पढ़ता है। डिफ़ॉल्ट रूप से बंद: चयन क्रम पूरी तरह से सामान्य रोटेशन ही रहता है।", "featureFlagProxyPoolEgressObservationDescription": "डैशबोर्ड में किसी Proxy पूल के अंतर्गत दिखाएँ कि पिछले 24 घंटों में कितने देखे गए एग्रेस IP ने उसके सदस्यों को सेवा दी, कितने कनेक्शनों ने उनका उपयोग किया और एक IP के पीछे सबसे अधिक कितने कनेक्शन देखे गए। केवल पढ़ने योग्य, Proxy लॉग से परिकलित और रूटिंग के लिए कभी उपयोग नहीं किया जाता। डिफ़ॉल्ट रूप से बंद: पूल एडिटर अपरिवर्तित रहता है और ऑब्ज़र्वेशन रूट null लौटाता है।", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy हेल्थ स्वीप में, लक्ष्य द्वारा अस्वीकृत प्रोब (401/403/429: Proxy ने इसे रिले किया, लेकिन गंतव्य ने इस एग्रेस IP को अस्वीकार किया) को, सेवा दिए गए प्रोब की तरह, Proxy की लगातार-विफलता शृंखला रीसेट करने दें। डिफ़ॉल्ट रूप से बंद: अस्वीकृति तटस्थ रहती है और शृंखला को बनाए रखती है। 5xx दोनों ही स्थितियों में अनिर्णायक रहता है, और कोई अस्वीकृति कभी भी Proxy को हटाती, अक्षम या फिर से सक्रिय नहीं करती।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वचालित क्लीनअप स्वीप को OMNIROUTE_BATCH_RETENTION_DAYS से पुराने टर्मिनल (पूर्ण/विफल/रद्द/समय-सीमा समाप्त) Batch API जॉब्स को उनके प्रति-पंक्ति चेकपॉइंट्स सहित हटाने दें, और जिन अपलोड की गई फ़ाइलों का expires_at बीत चुका है उनकी BLOB सामग्री साफ़ करने दें। डिफ़ॉल्ट रूप से बंद: ऑपरेटर के इसे चालू करने तक प्रत्येक मौजूदा इंस्टॉलेशन इस डेटा को बिल्कुल पहले की तरह बनाए रखता है। ऑपरेटर द्वारा ट्रिगर किया गया DELETE /api/v1/batches/delete-completed रूट किसी भी स्थिति में अप्रभावित रहता है—यह एक अलग, बिना शर्त सार्वजनिक API अनुबंध है।", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "आपका AI कनेक्शन URL", "apiManager": "एपीआई प्रबंधक", "apiManagerSubtitle": "एपीआई कुंजी और पहुंच प्रबंधित करें", + "modelCatalog": "मॉडल और कॉम्बो", + "modelCatalogSubtitle": "सभी प्रदाताओं में मॉडल और कॉम्बो ब्राउज़ करें", "embeddedServices": "एम्बेडेड सेवाएं", "embeddedServicesSubtitle": "स्थानीय प्रॉक्सी सेवाओं का प्रबंधन करें", "logs": "लॉग", diff --git a/src/i18n/messages/hr.json b/src/i18n/messages/hr.json index aea4915b882e..6bae47fb458f 100644 --- a/src/i18n/messages/hr.json +++ b/src/i18n/messages/hr.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogući adaptivne virtualne trake za prihvat po klijentu za slanje zahtjeva pružateljima (#9654): nagli porast zahtjeva jednog klijenta više neće uzrokovati pogrešku 503 drugom klijentu. Varijabla okruženja OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost nad ovom postavkom na nadzornoj ploči; promjene stupaju na snagu pri ponovnom pokretanju poslužitelja.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stranice pružatelja na nadzornoj ploči: prikazuj oznaku Besplatno samo na temelju signala koje pružatelj podržava — zanemaruju se heuristika naziva za prikaz, polja za besplatnu razinu koja nisu Booleove vrijednosti i sufiksi :free registriranih pružatelja bez dokumentirane besplatne razine. Kada je isključeno, zadržava se dosadašnje pravilo za oznaku.", "featureFlagProxySkipRecentlyFailedDescription": "Skupovi proxy poslužitelja i rotacija po računu za opencode privremeno prestaju ponovno posluživati proxy poslužitelj koji je upravo zakazao (odbijena TCP provjera ili odgovor 429 primljen preko njega) tijekom razdoblja po procesu koje se udvostručuje pri svakom ponavljanju, do zadanog maksimuma. Status proxy poslužitelja ne zapisuje se; kada se svi kandidati izuzmu, odabir ostaje nepromijenjen. Prema zadanim postavkama uključeno; `false` vraća običan odabir.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Za pružatelje čija je kvota grupirana prema izlaznoj adresi, rangira člana skupa koji dijeli zabilježenu izlaznu adresu nedavno odbijenog člana odmah ispod zdravih članova. Samo redoslijed, nikada se ne isključuje. Zahtijeva PROXY_SKIP_RECENTLY_FAILED, koji stvara signal odbijanja koji se očitava. Zadano isključeno: redoslijed odabira odgovara običnoj rotaciji.", "featureFlagProxyPoolEgressObservationDescription": "Na nadzornoj ploči, ispod skupa proxy poslužitelja, prikažite koliko je opaženih izlaznih IP adresa opsluživalo njegove članove tijekom posljednja 24 h, koliko ih je veza upotrebljavalo i najveći broj veza zabilježen iza jedne IP adrese. Samo za čitanje, izračunava se iz zapisnika proxy poslužitelja i nikada se ne upotrebljava za usmjeravanje. Prema zadanim postavkama isključeno: uređivač skupa ostaje nepromijenjen, a ruta za opažanja vraća null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Tijekom provjere stanja proxy poslužitelja omogućite da provjera koju je cilj odbio (401/403/429: proxy poslužitelj proslijedio je zahtjev, a odredište je odbilo ovu izlaznu IP adresu) poništi niz uzastopnih neuspjeha proxy poslužitelja, kao i uspješno poslužena provjera. Prema zadanim postavkama isključeno: odbijanje ostaje neutralno i zadržava niz. Odgovor 5xx u oba slučaja ostaje neodređen, a odbijanje nikada ne uklanja, onemogućuje niti ponovno aktivira proxy poslužitelj.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dopusti automatskom čišćenju brisanje završnih (dovršenih/neuspjelih/otkazanih/isteklih) Batch API zadataka starijih od OMNIROUTE_BATCH_RETENTION_DAYS, zajedno s njihovim kontrolnim točkama za svaki redak, te brisanje BLOB sadržaja prenesenih datoteka nakon njihova vlastitog expires_at. Prema zadanim postavkama isključeno: svaka postojeća instalacija zadržava te podatke kao i prije sve dok operater ne uključi ovu mogućnost. Ruta DELETE /api/v1/batches/delete-completed koju pokreće operater nije obuhvaćena ovom postavkom — ona je zaseban, bezuvjetan ugovor javnog API-ja.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Vaši URL-ovi za povezivanje s AI-jem", "apiManager": "API ključevi", "apiManagerSubtitle": "Upravljanje API ključevima i pristupom", + "modelCatalog": "Modeli i kombinacije", + "modelCatalogSubtitle": "Pregledajte modele i kombinacije među pružateljima", "embeddedServices": "Ugrađene usluge", "embeddedServicesSubtitle": "Neobavezne lokalne usluge", "logs": "Zapisnici", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index 70ed9a3fab5c..9bdc88dccf27 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Tegye lehetővé a bérlőnkénti adaptív virtuális beléptetősávokat a szolgáltatók felé történő továbbításhoz (#9654): az egyik bérlő kiugró terhelése már nem okoz 503-as hibát egy másiknál. Az OMNIROUTE_CHAT_VIRTUAL_LANES környezeti változó felülírja ezt a vezérlőpult-beállítást; a változtatások a szerver újraindításakor lépnek életbe.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Irányítópult szolgáltatói oldalai: az Ingyenes jelvény csak a szolgáltató által támogatott jelzések alapján jelenjen meg — figyelmen kívül hagyja a megjelenítési néven alapuló heurisztikát, a nem logikai típusú ingyenességi mezőket és a dokumentált ingyenes szinttel nem rendelkező regisztrált szolgáltatók :free utótagjait. Kikapcsolt állapotban a korábbi jelvényszabály marad érvényben.", "featureFlagProxySkipRecentlyFailedDescription": "A proxykészletek és az opencode fiókonkénti rotációja egy folyamatonként meghatározott időszakig nem választja újra az éppen meghibásodott proxyt (elutasított TCP-próba vagy rajta keresztül kapott 429-es válasz); ez az időszak minden ismétlődéskor megduplázódik egy felső korlátig. A proxy állapota nem kerül rögzítésre; ha minden jelölt félre van téve, a választás változatlan marad. Alapértelmezés szerint bekapcsolva; a `false` visszaállítja az egyszerű kiválasztást.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Olyan szolgáltatók esetén, amelyek kvótája kimenő cím szerint van csoportosítva, a nemrég elutasított tag észlelt kimenő címén osztozó pool-tagokat közvetlenül az egészséges tagok mögé rangsorolja. Csak a sorrendet módosítja, soha nem zárja ki. Szükséges hozzá a PROXY_SKIP_RECENTLY_FAILED, amely előállítja az általa beolvasott elutasítási jelet. Alapértelmezés szerint ki van kapcsolva: a kiválasztási sorrend pontosan megegyezik az egyszerű rotációval.", "featureFlagProxyPoolEgressObservationDescription": "A vezérlőpulton jelenjen meg egy proxykészlet alatt, hogy az elmúlt 24 órában hány megfigyelt kimenő IP-cím szolgálta ki a tagjait, hány kapcsolat használta ezeket, és legfeljebb hány kapcsolat volt megfigyelhető egyetlen IP-cím mögött. Csak olvasható, a proxynaplóból számított adat, amelyet a rendszer soha nem használ útválasztásra. Alapértelmezés szerint kikapcsolva: a készletszerkesztő változatlan, a megfigyelési útvonal pedig null értékkel válaszol.", "featureFlagProxyHealthBlockedResetsStreakDescription": "A proxyk állapotellenőrzése során a cél által elutasított próba (401/403/429: a proxy továbbította a kérést, a cél pedig elutasította ezt a kimenő IP-címet) a kiszolgált próbához hasonlóan nullázza a proxy egymást követő hibáinak számlálóját. Alapértelmezés szerint kikapcsolva: az elutasítás semleges marad, és nem változtatja meg a sorozatot. Az 5xx válasz mindkét esetben eldönthetetlen marad, és egy elutasítás soha nem távolít el, nem tilt le és nem aktivál újra proxyt.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Az automatikus tisztítás törölje az OMNIROUTE_BATCH_RETENTION_DAYS napnál régebbi, végleges állapotú (befejezett/sikertelen/megszakított/lejárt) Batch API-feladatokat a soronkénti ellenőrzőpontjaikkal együtt, valamint törölje a saját expires_at időpontjukon túli feltöltött fájlok BLOB-tartalmát. Alapértelmezés szerint kikapcsolva: minden meglévő telepítés pontosan ugyanúgy őrzi meg ezeket az adatokat, amíg egy üzemeltető be nem kapcsolja ezt a funkciót. Az üzemeltető által indított DELETE /api/v1/batches/delete-completed útvonal egyik esetben sem változik – ez egy különálló, feltétel nélküli nyilvános API-szerződés.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Az Ön AI-kapcsolati URL-jei", "apiManager": "API-kezelő", "apiManagerSubtitle": "API-kulcsok és hozzáférés kezelése", + "modelCatalog": "Modellek és kombinációk", + "modelCatalogSubtitle": "Böngésszen a modellek és kombinációk között a szolgáltatóknál", "embeddedServices": "Beágyazott Szolgáltatások", "embeddedServicesSubtitle": "Helyi proxyszolgáltatások kezelése", "logs": "Naplók", diff --git a/src/i18n/messages/hy.json b/src/i18n/messages/hy.json index 879d2faba135..1a90948987de 100644 --- a/src/i18n/messages/hy.json +++ b/src/i18n/messages/hy.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Միացնել ըստ վարձակալի հարմարվողական վիրտուալ ընդունման ուղիները մատակարարին ուղարկելու համար (#9654)․ մեկ վարձակալի հարցումների կտրուկ աճն այլևս չի առաջացնում 503 մեկ այլ վարձակալի համար։ OMNIROUTE_CHAT_VIRTUAL_LANES միջավայրի փոփոխականը գերակայում է կառավարման վահանակի այս վերասահմանմանը․ փոփոխություններն ուժի մեջ են մտնում սերվերը վերագործարկելիս։", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Վահանակի մատակարարների էջերում «Անվճար» նշանը ցուցադրել միայն մատակարարի կողմից հաստատված ազդանշանների դեպքում․ այլևս չօգտագործել ցուցադրվող անվան վրա հիմնված մոտավոր որոշումը, ոչ բուլյան free դաշտերը և փաստաթղթավորված անվճար մակարդակ չունեցող գրանցված մատակարարների :free վերջածանցները։ Անջատված լինելու դեպքում պահպանվում է նշանի ցուցադրման նախկին կանոնը։", "featureFlagProxySkipRecentlyFailedDescription": "Պրոքսի խմբերը և opencode-ի՝ ըստ հաշվի ռոտացիան դադարում են կրկին տրամադրել հենց նոր ձախողված պրոքսին (մերժված TCP ստուգում կամ դրա միջոցով ստացված 429)՝ յուրաքանչյուր գործընթացի համար սահմանված ժամանակահատվածով, որը յուրաքանչյուր կրկնության դեպքում կրկնապատկվում է՝ մինչև առավելագույն սահմանաչափը։ Պրոքսիի որևէ կարգավիճակ չի գրանցվում․ երբ բոլոր թեկնածուները մի կողմ են դրված, ընտրությունը մնում է անփոփոխ։ Լռելյայն միացված է․ `false`-ը վերականգնում է սովորական ընտրությունը։", + "featureFlagProxyPoolSharedEgressOrderDescription": "Այն մատակարարների համար, որոնց քվոտան բաշխվում է ըստ ելքային հասցեի, պուլի այն անդամին, որը կիսում է վերջերս մերժված անդամի նկատված ելքային հասցեն, դասակարգել անմիջապես առողջ անդամներից հետո: Միայն հերթականության փոփոխություն, երբեք չի բացառվում: Պահանջում է PROXY_SKIP_RECENTLY_FAILED, որն արտադրում է իր կողմից ընթերցվող մերժման ազդանշանը: Լռելյայն անջատված է. ընտրության հերթականությունը ճշգրտորեն համընկնում է սովորական ռոտացիայի հետ:", "featureFlagProxyPoolEgressObservationDescription": "Վահանակում՝ պրոքսի խմբի տակ, ցույց տալ, թե վերջին 24 ժ-ի ընթացքում քանի դիտարկված ելքային IP է սպասարկել դրա անդամներին, քանի միացում է օգտագործել դրանք, և մեկ IP-ի հետևում դիտված միացումների առավելագույն քանակը։ Միայն կարդալու համար է, հաշվարկվում է պրոքսիի մատյանից և երբեք չի օգտագործվում երթուղավորման համար։ Լռելյայն անջատված է․ խմբի խմբագրիչը մնում է անփոփոխ, իսկ դիտարկման երթուղին վերադարձնում է null։", "featureFlagProxyHealthBlockedResetsStreakDescription": "Պրոքսիի առողջական վիճակի ստուգման ընթացքում թույլ տալ, որ թիրախի կողմից մերժված ստուգումը (401/403/429․ պրոքսին փոխանցել է հարցումը, իսկ նպատակակետը մերժել է այս ելքային IP-ն) զրոյացնի պրոքսիի հաջորդական ձախողումների շարքը՝ ինչպես սպասարկված ստուգման դեպքում։ Լռելյայն անջատված է․ մերժումը մնում է չեզոք և պահպանում է շարքը։ 5xx-ը երկու դեպքում էլ մնում է անորոշ, իսկ մերժումը երբեք չի հեռացնում, անջատում կամ վերաակտիվացնում պրոքսին։", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Թույլատրել, որ ավտոմատ մաքրման գործընթացը ջնջի OMNIROUTE_BATCH_RETENTION_DAYS-ից ավելի հին վերջնական կարգավիճակով (completed/failed/cancelled/expired) Batch API առաջադրանքները՝ դրանց յուրաքանչյուր տողի ստուգակետերի հետ միասին, և մաքրի այն վերբեռնված ֆայլերի BLOB բովանդակությունը, որոնց expires_at-ն անցել է։ Լռելյայն անջատված է․ բոլոր առկա տեղադրումները շարունակում են պահպանել այս տվյալները ճիշտ այնպես, ինչպես նախկինում, մինչև օպերատորը միացնի այս գործառույթը։ Օպերատորի կողմից գործարկվող DELETE /api/v1/batches/delete-completed երթուղին որևէ դեպքում չի ազդվում․ այն առանձին, անվերապահ հանրային API պայմանագիր է։", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Ձեր AI կապի URL-ները", "apiManager": "API բանալիներ", "apiManagerSubtitle": "Կառավարեք API բանալիներն ու հասանելիությունը", + "modelCatalog": "Մոդելներ և կոմբոներ", + "modelCatalogSubtitle": "Զննեք մոդելներն ու կոմբոները բոլոր մատակարարների շրջանում", "embeddedServices": "Ներկառուցված ծառայություններ", "embeddedServicesSubtitle": "Ընտրովի տեղային ծառայություններ", "logs": "Մատյաններ", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index d077908b47ba..4b3c74a35028 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktifkan jalur penerimaan virtual adaptif per-tenant untuk pengiriman penyedia (#9654): lonjakan satu tenant tidak lagi mengembalikan 503 ke tenant lain. Variabel lingkungan OMNIROUTE_CHAT_VIRTUAL_LANES menang atas pengaturan dasbor ini; perubahan berlaku setelah server dimulai ulang.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Halaman penyedia di dasbor: tampilkan lencana Gratis hanya berdasarkan sinyal yang dipenuhi oleh penyedia — abaikan heuristik nama tampilan, kolom gratis non-boolean, dan akhiran :free pada penyedia terdaftar tanpa tingkat gratis yang terdokumentasi. Jika dinonaktifkan, aturan lencana lama tetap digunakan.", "featureFlagProxySkipRecentlyFailedDescription": "Pool proxy dan rotasi per akun opencode berhenti menyajikan kembali proxy yang baru saja gagal (probe TCP ditolak atau respons 429 diterima melaluinya) selama periode per proses yang berlipat ganda setiap kali kegagalan berulang, hingga batas maksimum. Status proxy tidak ditulis; jika setiap kandidat disisihkan, pilihannya tetap tidak berubah. Aktif secara default; `false` memulihkan pemilihan biasa.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Untuk penyedia yang kuotanya dikelompokkan berdasarkan alamat egress, posisikan anggota pool yang memiliki alamat egress teramati yang sama dengan anggota yang baru saja ditolak tepat di bawah anggota yang sehat. Hanya urutan, tidak pernah dikecualikan. Memerlukan PROXY_SKIP_RECENTLY_FAILED, yang menghasilkan sinyal penolakan yang dibacanya. Nonaktif secara default: urutan pemilihan persis seperti rotasi biasa.", "featureFlagProxyPoolEgressObservationDescription": "Tampilkan, di bawah pool proxy pada dasbor, jumlah IP keluar yang teramati melayani anggotanya selama 24 jam terakhir, jumlah koneksi yang menggunakannya, dan jumlah koneksi terbanyak yang terlihat di balik satu IP. Hanya-baca, dihitung dari log proxy, dan tidak pernah digunakan untuk perutean. Nonaktif secara default: editor pool tidak berubah dan rute observasi memberikan jawaban null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Dalam pemeriksaan kesehatan proxy, izinkan probe yang ditolak oleh target (401/403/429: proxy meneruskan, tetapi tujuan menolak IP keluar ini) mereset rentetan kegagalan berturut-turut proxy, seperti probe yang berhasil dilayani. Nonaktif secara default: penolakan tetap netral dan mempertahankan rentetan tersebut. Respons 5xx tetap tidak meyakinkan dalam kedua kasus, dan penolakan tidak pernah menghapus, menonaktifkan, atau mengaktifkan kembali proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Izinkan pembersihan otomatis menghapus tugas Batch API berstatus akhir (selesai/gagal/dibatalkan/kedaluwarsa) yang lebih lama dari OMNIROUTE_BATCH_RETENTION_DAYS, beserta titik pemeriksaan per barisnya, serta menghapus konten BLOB dari file yang diunggah setelah melewati expires_at masing-masing. Nonaktif secara default: setiap instalasi yang ada tetap menyimpan data ini persis seperti sebelumnya hingga operator mengaktifkannya. Rute DELETE /api/v1/batches/delete-completed yang dipicu operator tidak terpengaruh dalam kondisi apa pun — rute tersebut merupakan kontrak API publik terpisah yang berlaku tanpa syarat.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL koneksi AI Anda", "apiManager": "Manajer API", "apiManagerSubtitle": "Kelola kunci dan akses API", + "modelCatalog": "Model & Kombo", + "modelCatalogSubtitle": "Jelajahi model dan kombo di berbagai penyedia", "embeddedServices": "Layanan Tertanam", "embeddedServicesSubtitle": "Kelola layanan proxy lokal", "logs": "Log", diff --git a/src/i18n/messages/ig.json b/src/i18n/messages/ig.json index 0fa73629ecce..20705afd9226 100644 --- a/src/i18n/messages/ig.json +++ b/src/i18n/messages/ig.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Gbanye lane nnabata virtual na-agbanwe onwe ya maka tenant ọ bụla maka iziga na provider (#9654): mgbawa arịrịọ nke otu tenant agaghịzi eme ka nke tenant ọzọ nweta 503. Env var OMNIROUTE_CHAT_VIRTUAL_LANES na-akarị mgbanwe dashboard a; mgbanwe ga-amalite ịrụ ọrụ mgbe e bidogharịrị server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Ibe ndị na-enye ọrụ na dashboard: gosi akara Free naanị na signal ndị onye na-enye ọrụ na-akwado — nke a na-ewepụ usoro ntule dabere n’aha ngosi, oghere free ndị na-abụghị boolean, na mgbakwunye :free n’aha ndị na-enye ọrụ e debanyere aha nke na-enweghị ọkwa efu edepụtara. Mgbe agbanyụrụ ya, a ga-edobe iwu akara e ji eme ihe kemgbe.", "featureFlagProxySkipRecentlyFailedDescription": "Ọdọ proxy na ntụgharị opencode nke akaụntụ ọ bụla na-akwụsị iji proxy dara ugbu a ọzọ (nnyocha TCP a jụrụ, ma ọ bụ nzaghachi 429 e nwetara site na ya) ruo oge nke usoro ọ bụla nke na-amụba okpukpu abụọ mgbe ọdịda ahụ megharịrị, ruo n'ókè kachasị. A naghị ede ọkwa proxy ọ bụla; mgbe e wepụrụ ndị niile a ga-ahọrọ n'akụkụ, nhọrọ ahụ anaghị agbanwe. A gbanyere ya na ndabara; `false` na-eweghachi nhọrọ nkịtị.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Maka ndị na-eweta ọrụ ndị e ji adreesị egress kee quota ha, dọba onye otu pool nke na-ekerịta adreesị egress a hụrụ nke onye otu a jụrụ na nso nso a n'okpuru ndị otu dị mma. Naanị usoro, a dịghị ewepụ ya ma ọlị. Chọrọ PROXY_SKIP_RECENTLY_FAILED, nke na-ewepụta akara ọjụjụ ọ na-agụ. Agbanyụrụ na ndabara: usoro nhọrọ bụ kpọmkwem ntụgharị nkịtị.", "featureFlagProxyPoolEgressObservationDescription": "Gosi, n'okpuru ọdọ proxy na dashboard, IP ọpụpụ ole a hụrụ jere ndị otu ya ozi n'ime awa 24 gara aga, njikọ ole jiri ha, na ọnụ ọgụgụ kachasị a hụrụ n'azụ otu IP. Ọ bụ naanị maka ọgụgụ, a na-agbakọ ya site na ndekọ proxy, a naghị eji ya eme routing. A gbanyụrụ ya na ndabara: editọ ọdọ ahụ anaghị agbanwe, route nlele ahụ na-azaghachi null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "N'oge nyocha ahụike proxy, kwe ka nyocha ebumnuche jụrụ (401/403/429: proxy ahụ zigara ya, ebe njedebe ahụ jụrụ IP ọpụpụ a) tọgharịa usoro ọdịda na-aga n'ihu nke proxy ahụ, dịka nyocha e jere ozi. A gbanyụrụ ya na ndabara: ọjụjụ na-anọpụ iche ma na-edobe usoro ahụ. 5xx ka na-enweghị nkwubi okwu n'ọnọdụ ọ bụla, ọjụjụ anaghị ewepụ, gbanyụọ, ma ọ bụ mee ka proxy rụọ ọrụ ọzọ.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Kwe ka nhichapụ akpaka hichapụ ọrụ Batch API ndị nọ n’ọnọdụ njedebe (completed/failed/cancelled/expired) ma gafee OMNIROUTE_BATCH_RETENTION_DAYS, tinyere checkpoints nke ahịrị nke ọ bụla, ma kpochapụ ọdịnaya BLOB nke faịlụ ebugoro nke gafere expires_at nke ha. Agbanyụrụ ya na ndabara: nrụnye niile dị ugbu a ga-edobe data a kpọmkwem dịka ọ dị na mbụ ruo mgbe onye njikwa họrọ ịgbanye ya. Ụzọ DELETE /api/v1/batches/delete-completed nke onye njikwa na-akpalite agaghị emetụta n’ụzọ ọ bụla -- ọ bụ nkwekọrịta API ọha dị iche nke na-arụ ọrụ mgbe niile.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL njikọ AI gị", "apiManager": "Igodo API", "apiManagerSubtitle": "Jikwaa igodo API na ohere nnweta", + "modelCatalog": "Ụdị & Ngwakọta", + "modelCatalogSubtitle": "Chọgharịa ụdị na ngwakọta n'ofe ndị na-eweta ọrụ", "embeddedServices": "Ọrụ agbakwunyere", "embeddedServicesSubtitle": "Ọrụ mpaghara nhọrọ", "logs": "Ndekọ", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 87894e8ff372..2143c6976c0f 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Attiva corsie di ammissione virtuali adattive per tenant per l'invio ai provider (#9654): il picco di un tenant non restituisce più 503 a un altro. La variabile d'ambiente OMNIROUTE_CHAT_VIRTUAL_LANES ha la precedenza su questa impostazione della dashboard; le modifiche hanno effetto al riavvio del server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pagine dei provider nella dashboard: mostra il badge Gratis solo in base agli indicatori riconosciuti dal provider — elimina l'euristica del nome visualizzato, i campi relativi alla gratuità non booleani e i suffissi :free per i provider registrati senza un piano gratuito documentato. Se disattivato, mantiene la regola storica del badge.", "featureFlagProxySkipRecentlyFailedDescription": "I pool di proxy e la rotazione per account di opencode smettono temporaneamente di riproporre un proxy che ha appena avuto un errore (sonda TCP rifiutata o risposta 429 ricevuta tramite il proxy) per un periodo per processo che raddoppia a ogni ripetizione, fino a un limite massimo. Non viene registrato alcuno stato del proxy; se tutti i candidati vengono messi da parte, la scelta rimane invariata. Attivato per impostazione predefinita; `false` ripristina la selezione normale.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Per i provider la cui quota è suddivisa per indirizzo di egress, posiziona un membro del pool che condivide l'indirizzo di egress rilevato di un membro rifiutato di recente subito sotto i membri integri. Solo ordinamento, mai escluso. Richiede PROXY_SKIP_RECENTLY_FAILED, che genera il segnale di rifiuto da esso letto. Disattivato per impostazione predefinita: l'ordine di selezione segue esattamente la semplice rotazione.", "featureFlagProxyPoolEgressObservationDescription": "Mostra, sotto un pool di proxy nella dashboard, quanti IP di uscita osservati hanno servito i suoi membri nelle ultime 24 ore, quante connessioni li hanno utilizzati e il numero massimo di connessioni osservate dietro un singolo IP. In sola lettura, calcolato dal log dei proxy e mai utilizzato per l'instradamento. Disattivato per impostazione predefinita: l'editor dei pool rimane invariato e la route di osservazione restituisce null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Durante la scansione dello stato dei proxy, consente a una sonda rifiutata dalla destinazione (401/403/429: il proxy ha inoltrato la richiesta, ma la destinazione ha rifiutato questo IP di uscita) di azzerare la serie di errori consecutivi del proxy, come una sonda completata con successo. Disattivato per impostazione predefinita: un rifiuto rimane neutro e mantiene la serie. Una risposta 5xx rimane inconcludente in entrambi i casi e un rifiuto non rimuove, disabilita o riattiva mai un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Consenti alla pulizia automatica di eliminare i processi Batch API terminati (completati/non riusciti/annullati/scaduti) più vecchi di OMNIROUTE_BATCH_RETENTION_DAYS, insieme ai relativi checkpoint per riga, e di cancellare il contenuto BLOB dei file caricati che hanno superato il proprio expires_at. Disattivata per impostazione predefinita: ogni installazione esistente conserva questi dati esattamente come prima finché un operatore non abilita l'opzione. La route DELETE /api/v1/batches/delete-completed attivata dall'operatore non è interessata in alcun caso: è un contratto API pubblico distinto e incondizionato.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "I tuoi URL di connessione AI", "apiManager": "Gestore API", "apiManagerSubtitle": "Gestisci le chiavi API e l'accesso", + "modelCatalog": "Modelli e combo", + "modelCatalogSubtitle": "Sfoglia modelli e combo tra i vari provider", "embeddedServices": "Servizi Integrati", "embeddedServicesSubtitle": "Gestisci i servizi proxy locali", "logs": "Registri", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 7871c6c38ca3..1209466c8034 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "プロバイダーへのディスパッチ用に、テナントごとの適応型仮想受付レーンを有効にします(#9654):あるテナントのバーストが他のテナントに503を返さなくなります。OMNIROUTE_CHAT_VIRTUAL_LANES環境変数はこのダッシュボード設定より優先されます。変更はサーバー再起動時に反映されます。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ダッシュボードのプロバイダーページ:プロバイダーが正式に対応していることを示すシグナルに対してのみ「Free」バッジを表示します。表示名による推測、ブール値ではない無料フィールド、および無料枠が文書化されていない登録済みプロバイダーの「:free」サフィックスは使用しません。オフにすると、従来のバッジ判定ルールが適用されます。", "featureFlagProxySkipRecentlyFailedDescription": "プロキシプールと、アカウントごとのopencodeローテーションで、直前に失敗したプロキシ(TCPプローブが拒否された、またはそのプロキシ経由で429を受信したもの)の再使用を、同一プロセス内で一定期間停止します。この期間は失敗を繰り返すたびに倍増し、上限があります。プロキシのステータスは書き込まれません。すべての候補が除外された場合、選択は変更されません。デフォルトではオンです。`false` にすると通常の選択に戻ります。", + "featureFlagProxyPoolSharedEgressOrderDescription": "イグレスアドレス単位でクォータが管理されているプロバイダーにおいて、最近拒否されたメンバーと観測されたイグレスアドレスを共有するプールメンバーの優先度を、正常なメンバーの直下に下げます。順序の変更のみで、除外されることはありません。判定対象となる拒否シグナルを生成する PROXY_SKIP_RECENTLY_FAILED が必要です。デフォルトはオフ(選択順序は通常のローテーション通り)です。", "featureFlagProxyPoolEgressObservationDescription": "ダッシュボードのプロキシプールの下に、過去24時間にそのメンバーに使用されたことが観測された送信元IPの数、それらを使用した接続数、および1つのIPの背後で観測された最多のメンバー数を表示します。読み取り専用で、プロキシログから算出され、ルーティングには使用されません。デフォルトではオフです。プールエディターは変更されず、観測ルートはnullを返します。", "featureFlagProxyHealthBlockedResetsStreakDescription": "プロキシのヘルススイープで、ターゲットに拒否されたプローブ(401/403/429:プロキシは中継したが、宛先がこの送信元IPを拒否したもの)が、正常に処理されたプローブと同様に、プロキシの連続失敗回数をリセットできるようにします。デフォルトではオフです。拒否は中立のままで、連続失敗回数は維持されます。どちらの場合も5xxは判定不能のままであり、拒否によってプロキシが削除、無効化、または再有効化されることはありません。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "自動クリーンアップ処理で、OMNIROUTE_BATCH_RETENTION_DAYS より古い終了済み(完了/失敗/キャンセル/期限切れ)の Batch API ジョブを行ごとのチェックポイントとともに削除し、それぞれの expires_at を過ぎたアップロード済みファイルの BLOB コンテンツを消去します。デフォルトではオフです。オペレーターが明示的に有効化するまで、既存のすべてのインストール環境では従来どおりデータが保持されます。オペレーターが実行する DELETE /api/v1/batches/delete-completed ルートは、設定の有効/無効にかかわらず影響を受けません。これは独立した無条件の公開 API 契約です。", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AI 接続 URL", "apiManager": "APIマネージャー", "apiManagerSubtitle": "API キーとアクセスを管理する", + "modelCatalog": "モデル & コンボ", + "modelCatalogSubtitle": "各プロバイダーのモデルとコンボを閲覧", "embeddedServices": "組み込みサービス", "embeddedServicesSubtitle": "ローカルプロキシサービスを管理する", "logs": "ログ", diff --git a/src/i18n/messages/ka.json b/src/i18n/messages/ka.json index 256d206c1003..e91be8c0a410 100644 --- a/src/i18n/messages/ka.json +++ b/src/i18n/messages/ka.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ჩართეთ თითოეული ტენანტისთვის ადაპტიური ვირტუალური დაშვების არხები პროვაიდერთან გადაგზავნისთვის (#9654): ერთი ტენანტის მოთხოვნების უეცარი მატება სხვას აღარ დაუბრუნებს 503 შეცდომას. OMNIROUTE_CHAT_VIRTUAL_LANES გარემოს ცვლადს უპირატესობა აქვს მართვის პანელის ამ პარამეტრთან შედარებით; ცვლილებები ძალაში შევა სერვერის გადატვირთვის შემდეგ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "პროვაიდერის გვერდები მართვის პანელში: „უფასო“ ნიშანი გამოჩნდეს მხოლოდ იმ სიგნალების საფუძველზე, რომლებსაც პროვაიდერი ითვალისწინებს — აღარ გამოიყენება საჩვენებელი სახელის ევრისტიკა, არაბულური free ველები და :free სუფიქსები რეგისტრირებული პროვაიდერებისთვის, რომლებსაც დოკუმენტირებული უფასო დონე არ აქვთ. გამორთვის შემთხვევაში შენარჩუნდება ნიშნის ჩვენების ისტორიული წესი.", "featureFlagProxySkipRecentlyFailedDescription": "პროქსი-პულები და opencode-ის თითოეულ ანგარიშზე როტაცია აღარ იყენებს ახლახან ჩავარდნილ პროქსის (უარყოფილი TCP შემოწმება ან მისი მეშვეობით მიღებული 429) თითოეული პროცესისთვის განსაზღვრული პერიოდით, რომელიც ყოველი განმეორებისას ორმაგდება მაქსიმალურ ზღვრამდე. პროქსის სტატუსი არ იწერება; ყველა კანდიდატის გვერდზე გადადების შემთხვევაში არჩევანი უცვლელი რჩება. ნაგულისხმევად ჩართულია; `false` აღადგენს ჩვეულებრივ არჩევას.", + "featureFlagProxyPoolSharedEgressOrderDescription": "პროვაიდერებისთვის, რომელთა ქვოტაც ჯგუფდება egress მისამართის მიხედვით, დაალაგეთ პულის ის წევრი, რომელიც იზიარებს ცოტა ხნის წინ უარყოფილი წევრის დაფიქსირებულ egress მისამართს, უშუალოდ ჯანსაღი წევრების შემდეგ. მხოლოდ რიგითობა, არასდროს გამოირიცხება. საჭიროებს PROXY_SKIP_RECENTLY_FAILED-ს, რომელიც წარმოქმნის მის მიერ წაკითხულ უარყოფის სიგნალს. ნაგულისხმევად გამორთულია: შერჩევის რიგითობა ზუსტად ემთხვევა ჩვეულებრივ როტაციას.", "featureFlagProxyPoolEgressObservationDescription": "დეშბორდზე, პროქსი-პულის ქვეშ, აჩვენეთ ბოლო 24 საათში რამდენი დაფიქსირებული გამავალი IP ემსახურებოდა მის წევრებს, რამდენმა კავშირმა გამოიყენა ისინი და ყველაზე მეტი რამდენი კავშირი დაფიქსირდა ერთი IP-ის უკან. მხოლოდ წაკითხვისთვისაა, გამოითვლება პროქსის ჟურნალიდან და არასოდეს გამოიყენება მარშრუტიზაციისთვის. ნაგულისხმევად გამორთულია: პულის რედაქტორი უცვლელია, ხოლო დაკვირვების მარშრუტი აბრუნებს null-ს.", "featureFlagProxyHealthBlockedResetsStreakDescription": "პროქსის მდგომარეობის შემოწმებისას, სამიზნის მიერ უარყოფილმა მოთხოვნამ (401/403/429: პროქსიმ გადააგზავნა მოთხოვნა, ხოლო დანიშნულების მხარემ უარყო ეს გამავალი IP) გაანულოს პროქსის ზედიზედ წარუმატებლობათა სერია, როგორც წარმატებით შესრულებული შემოწმებისას. ნაგულისხმევად გამორთულია: უარყოფა ნეიტრალური რჩება და სერიას ინარჩუნებს. 5xx ნებისმიერ შემთხვევაში გაურკვეველ შედეგად რჩება, ხოლო უარყოფა არასოდეს შლის, თიშავს ან ხელახლა ააქტიურებს პროქსის.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ავტომატურ გასუფთავებას მიეცით უფლება, წაშალოს OMNIROUTE_BATCH_RETENTION_DAYS-ზე ძველი, საბოლოო მდგომარეობაში მყოფი (დასრულებული/წარუმატებელი/გაუქმებული/ვადაგასული) Batch API დავალებები მათ თითოეულ სტრიქონთან დაკავშირებულ საკონტროლო წერტილებთან ერთად და გაასუფთაოს ატვირთული ფაილების BLOB-შიგთავსი მათი expires_at ვადის გასვლის შემდეგ. ნაგულისხმევად გამორთულია: ყველა არსებულ ინსტალაციაში ეს მონაცემები ზუსტად ისე დარჩება, როგორც აქამდე, სანამ ოპერატორი ფუნქციას არ ჩართავს. ოპერატორის მიერ გამოძახებულ DELETE /api/v1/batches/delete-completed მარშრუტზე ეს პარამეტრი გავლენას არ ახდენს — ის ცალკე, უპირობო საჯარო API-კონტრაქტია.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "თქვენი AI კავშირის URL-ები", "apiManager": "API გასაღებები", "apiManagerSubtitle": "API გასაღებებისა და წვდომის მართვა", + "modelCatalog": "მოდელები და კომბოები", + "modelCatalogSubtitle": "დაათვალიერეთ მოდელები და კომბოები პროვაიდერებს შორის", "embeddedServices": "ჩაშენებული სერვისები", "embeddedServicesSubtitle": "არასავალდებულო ლოკალური სერვისები", "logs": "ჟურნალები", diff --git a/src/i18n/messages/km.json b/src/i18n/messages/km.json index 0c5f2cf8784c..38fbd4ec06da 100644 --- a/src/i18n/messages/km.json +++ b/src/i18n/messages/km.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "បើកផ្លូវចូលនិម្មិតដែលសម្របខ្លួនតាម tenant នីមួយៗ សម្រាប់ការបញ្ជូនទៅ provider (#9654)៖ ការកើនឡើងខ្លាំងភ្លាមៗរបស់ tenant មួយ នឹងលែងបណ្ដាលឱ្យ tenant មួយទៀតទទួល 503។ env var OMNIROUTE_CHAT_VIRTUAL_LANES មានអាទិភាពលើការកំណត់ជំនួសពី dashboard នេះ ហើយការផ្លាស់ប្ដូរនឹងមានប្រសិទ្ធភាពនៅពេលចាប់ផ្ដើម server ឡើងវិញ។", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ទំព័រអ្នកផ្តល់សេវានៅលើផ្ទាំងគ្រប់គ្រង៖ បង្ហាញស្លាក ឥតគិតថ្លៃ តែលើសញ្ញាដែលអ្នកផ្តល់សេវាទទួលស្គាល់ប៉ុណ្ណោះ — លុបចោលការសន្និដ្ឋានតាមឈ្មោះបង្ហាញ វាលឥតគិតថ្លៃដែលមិនមែនជាតម្លៃប៊ូលីន និងបច្ច័យ :free លើអ្នកផ្តល់សេវាដែលបានចុះបញ្ជី ប៉ុន្តែមិនមានកម្រិតសេវាឥតគិតថ្លៃដែលបានចងក្រងជាឯកសារ។ ការបិទនឹងរក្សាច្បាប់ស្លាកចាស់ដដែល។", "featureFlagProxySkipRecentlyFailedDescription": "ក្រុមប្រូកស៊ី និងការបង្វិលតាមគណនីនីមួយៗរបស់ opencode នឹងផ្អាកការប្រើប្រូកស៊ីដែលទើបតែបរាជ័យឡើងវិញ (ការស្ទង់ TCP ត្រូវបានបដិសេធ ឬទទួលបាន 429 តាមរយៈវា) ក្នុងរយៈពេលមួយសម្រាប់ដំណើរការនីមួយៗ ដែលកើនទ្វេដងរាល់ពេលកើតឡើងម្តងទៀត រហូតដល់កម្រិតអតិបរមា។ គ្មានស្ថានភាពប្រូកស៊ីត្រូវបានកត់ត្រាទេ ហើយនៅពេលបេក្ខភាពទាំងអស់ត្រូវបានទុកមួយឡែក ជម្រើសនៅតែមិនផ្លាស់ប្តូរ។ បើកតាមលំនាំដើម៖ `false` ស្ដារការជ្រើសរើសធម្មតាវិញ។", + "featureFlagProxyPoolSharedEgressOrderDescription": "សម្រាប់អ្នកផ្តល់សេវាដែលកូតាត្រូវបានបែងចែកតាមអាសយដ្ឋាន egress ចាត់ចំណាត់ថ្នាក់សមាជិក pool ដែលចែករំលែកអាសយដ្ឋាន egress របស់សមាជិកដែលទើបត្រូវបានបដិសេធឱ្យនៅខាងក្រោមសមាជិកល្អ (healthy) បន្តិច។ កែប្រែតែលំដាប់ប៉ុណ្ណោះ មិនដែលត្រូវបានដកចេញឡើយ។ ត្រូវការ PROXY_SKIP_RECENTLY_FAILED ដែលបង្កើតសញ្ញាបដិសេធដែលវាអាន។ បិទតាមលំនាំដើម៖ លំដាប់នៃការជ្រើសរើសគឺដូចគ្នាបេះបិទនឹងការបង្វិលធម្មតា។", "featureFlagProxyPoolEgressObservationDescription": "បង្ហាញនៅក្រោមក្រុមប្រូកស៊ីក្នុងផ្ទាំងគ្រប់គ្រងថា ក្នុងរយៈពេល 24 ម៉ោងចុងក្រោយ មាន IP ចេញក្រៅដែលបានសង្កេតឃើញចំនួនប៉ុន្មានបានបម្រើសមាជិករបស់ក្រុម មានការតភ្ជាប់ចំនួនប៉ុន្មានបានប្រើពួកវា និងចំនួនអតិបរមាដែលបានឃើញនៅពីក្រោយ IP តែមួយ។ សម្រាប់តែអានប៉ុណ្ណោះ គណនាពីកំណត់ហេតុប្រូកស៊ី និងមិនដែលប្រើសម្រាប់ការកំណត់ផ្លូវទេ។ បិទតាមលំនាំដើម៖ កម្មវិធីកែសម្រួលក្រុមមិនផ្លាស់ប្តូរ ហើយផ្លូវសង្កេតឆ្លើយតបជា null។", "featureFlagProxyHealthBlockedResetsStreakDescription": "ក្នុងការត្រួតពិនិត្យសុខភាពប្រូកស៊ី អនុញ្ញាតឱ្យការស្ទង់ដែលគោលដៅបានបដិសេធ (401/403/429៖ ប្រូកស៊ីបានបញ្ជូនបន្ត ប៉ុន្តែគោលដៅបានបដិសេធ IP ចេញក្រៅនេះ) កំណត់ចំនួនបរាជ័យជាប់ៗគ្នារបស់ប្រូកស៊ីឡើងវិញ ដូចការស្ទង់ដែលត្រូវបានបម្រើ។ បិទតាមលំនាំដើម៖ ការបដិសេធនៅតែអព្យាក្រឹត និងរក្សាចំនួនបរាជ័យជាប់ៗគ្នា។ 5xx នៅតែមិនអាចសន្និដ្ឋានបានក្នុងករណីទាំងពីរ ហើយការបដិសេធមិនដែលលុប បិទ ឬធ្វើឱ្យប្រូកស៊ីសកម្មឡើងវិញទេ។", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "អនុញ្ញាតឱ្យការសម្អាតដោយស្វ័យប្រវត្តិលុបកិច្ចការ Batch API ដែលស្ថិតក្នុងស្ថានភាពបញ្ចប់ (បានបញ្ចប់/បរាជ័យ/បានបោះបង់/ផុតកំណត់) និងចាស់ជាង OMNIROUTE_BATCH_RETENTION_DAYS រួមទាំងចំណុចត្រួតពិនិត្យតាមបន្ទាត់របស់កិច្ចការទាំងនោះ ព្រមទាំងសម្អាតខ្លឹមសារ BLOB របស់ឯកសារដែលបានផ្ទុកឡើង និងហួស expires_at របស់វា។ តាមលំនាំដើម មុខងារនេះត្រូវបានបិទ៖ ការដំឡើងដែលមានស្រាប់ទាំងអស់នឹងរក្សាទិន្នន័យនេះដូចមុនទាំងស្រុង រហូតដល់ប្រតិបត្តិករជ្រើសរើសបើកប្រើ។ Route DELETE /api/v1/batches/delete-completed ដែលប្រតិបត្តិករបើកដំណើរការ មិនរងផលប៉ះពាល់ទោះជាករណីណាក៏ដោយ — វាជាកិច្ចសន្យា public API ដាច់ដោយឡែក និងគ្មានលក្ខខណ្ឌ។", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL សម្រាប់ការតភ្ជាប់ AI របស់អ្នក", "apiManager": "សោ API", "apiManagerSubtitle": "គ្រប់គ្រងសោ API និងសិទ្ធិចូលប្រើ", + "modelCatalog": "ម៉ូឌែល និងបន្សំ", + "modelCatalogSubtitle": "រកមើលម៉ូឌែល និងបន្សំនៅតាមអ្នកផ្តល់សេវាផ្សេងៗ", "embeddedServices": "សេវាកម្មដែលបានបង្កប់", "embeddedServicesSubtitle": "សេវាកម្មមូលដ្ឋានជាជម្រើស", "logs": "កំណត់ហេតុ", diff --git a/src/i18n/messages/kn.json b/src/i18n/messages/kn.json index 9b622a2050c3..15a7f11da421 100644 --- a/src/i18n/messages/kn.json +++ b/src/i18n/messages/kn.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ಪ್ರೊವೈಡರ್ ಡಿಸ್ಪ್ಯಾಚ್ಗಾಗಿ ಪ್ರತಿ-ಟೆನಂಟ್ ಅಡಾಪ್ಟಿವ್ ವರ್ಚುವಲ್ ಅಡ್ಮಿಷನ್ ಲೇನ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ (#9654): ಒಂದು ಟೆನಂಟ್ನ ಬರ್ಸ್ಟ್ನಿಂದ ಇನ್ನು ಮುಂದೆ ಮತ್ತೊಂದು ಟೆನಂಟ್ಗೆ 503 ದೋಷ ಉಂಟಾಗುವುದಿಲ್ಲ. ಈ ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಓವರ್ರೈಡ್ಗಿಂತ OMNIROUTE_CHAT_VIRTUAL_LANES env var ಗೆ ಆದ್ಯತೆ ಇರುತ್ತದೆ; ಸರ್ವರ್ ಮರುಪ್ರಾರಂಭವಾದಾಗ ಬದಲಾವಣೆಗಳು ಜಾರಿಗೆ ಬರುತ್ತವೆ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಪ್ರೊವೈಡರ್ ಪುಟಗಳು: ಪ್ರೊವೈಡರ್ ಮಾನ್ಯಗೊಳಿಸುವ ಸಂಕೇತಗಳ ಆಧಾರದ ಮೇಲೆ ಮಾತ್ರ Free ಬ್ಯಾಡ್ಜ್ ಅನ್ನು ತೋರಿಸಿ — ದಾಖಲಿತ ಉಚಿತ ಹಂತವಿಲ್ಲದ ನೋಂದಾಯಿತ ಪ್ರೊವೈಡರ್ಗಳಿಗೆ ಪ್ರದರ್ಶನ-ಹೆಸರು ಹ್ಯೂರಿಸ್ಟಿಕ್, ಬೂಲಿಯನ್ ಅಲ್ಲದ ಉಚಿತ ಕ್ಷೇತ್ರಗಳು ಮತ್ತು :free ಪ್ರತ್ಯಯಗಳನ್ನು ಪರಿಗಣಿಸುವುದಿಲ್ಲ. ಆಫ್ ಮಾಡಿದಾಗ ಹಿಂದಿನ ಬ್ಯಾಡ್ಜ್ ನಿಯಮವು ಉಳಿಯುತ್ತದೆ.", "featureFlagProxySkipRecentlyFailedDescription": "ಪ್ರಾಕ್ಸಿ ಪೂಲ್ಗಳು ಮತ್ತು opencode ನ ಪ್ರತಿ-ಖಾತೆ ರೊಟೇಶನ್, ಇತ್ತೀಚೆಗೆ ವಿಫಲವಾದ ಪ್ರಾಕ್ಸಿಯನ್ನು (TCP ಪ್ರೋಬ್ ನಿರಾಕರಿಸಲ್ಪಟ್ಟಿದ್ದರೆ ಅಥವಾ ಅದರ ಮೂಲಕ 429 ಬಂದಿದ್ದರೆ) ಪ್ರತಿ ಪ್ರಕ್ರಿಯೆಗೆ ಅನ್ವಯಿಸುವ ಅವಧಿಯವರೆಗೆ ಮತ್ತೆ ಬಳಸುವುದಿಲ್ಲ. ಪ್ರತಿ ಪುನರಾವರ್ತನೆಯಲ್ಲೂ ಈ ಅವಧಿ ದ್ವಿಗುಣಗೊಳ್ಳುತ್ತದೆ, ನಿಗದಿತ ಗರಿಷ್ಠ ಮಿತಿಯವರೆಗೆ. ಯಾವುದೇ ಪ್ರಾಕ್ಸಿ ಸ್ಥಿತಿಯನ್ನು ಬರೆಯಲಾಗುವುದಿಲ್ಲ; ಪ್ರತಿಯೊಂದು ಅಭ್ಯರ್ಥಿಯನ್ನೂ ಬದಿಗಿರಿಸಿದಾಗ ಆಯ್ಕೆಯು ಬದಲಾಗುವುದಿಲ್ಲ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆನ್; `false` ಸರಳ ಆಯ್ಕೆಯನ್ನು ಮರುಸ್ಥಾಪಿಸುತ್ತದೆ.", + "featureFlagProxyPoolSharedEgressOrderDescription": "ಯಾವ ಪೂರೈಕೆದಾರರ ಕೋಟಾವನ್ನು egress ವಿಳಾಸದ ಮೂಲಕ ನಿಗದಿಪಡಿಸಲಾಗಿದೆಯೋ, ಅವರಿಗೆ ಇತ್ತೀಚೆಗೆ ನಿರಾಕರಿಸಲಾದ ಸದಸ್ಯರ ಗಮನಿಸಲಾದ egress ವಿಳಾಸವನ್ನು ಹಂಚಿಕೊಳ್ಳುವ ಪೂಲ್ ಸದಸ್ಯರನ್ನು ಆರೋಗ್ಯಕರ ಸದಸ್ಯರ ಕೆಳಗೆ ಶ್ರೇಣೀಕರಿಸಿ. ಕೇವಲ ಆದ್ಯತಾ ಕ್ರಮ ಮಾತ್ರ, ಎಂದಿಗೂ ಹೊರಗಿಡಲಾಗುವುದಿಲ್ಲ. ಇದು ಓದುವ ನಿರಾಕರಣೆಯ ಸಿಗ್ನಲ್ ಅನ್ನು ಉತ್ಪಾದಿಸುವ PROXY_SKIP_RECENTLY_FAILED ನ ಅಗತ್ಯವಿದೆ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿರುತ್ತದೆ: ಆಯ್ಕೆಯ ಕ್ರಮವು ನಿಖರವಾಗಿ ಸಾಮಾನ್ಯ ರೊಟೇಶನ್ ಆಗಿದೆ.", "featureFlagProxyPoolEgressObservationDescription": "ಡ್ಯಾಶ್ಬೋರ್ಡ್ನಲ್ಲಿ ಪ್ರಾಕ್ಸಿ ಪೂಲ್ನ ಅಡಿಯಲ್ಲಿ, ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿ ಅದರ ಸದಸ್ಯರಿಗೆ ಸೇವೆ ನೀಡಿದ ಗಮನಿಸಲಾದ ಎಗ್ರೆಸ್ IPಗಳ ಸಂಖ್ಯೆ, ಅವುಗಳನ್ನು ಬಳಸಿದ ಸಂಪರ್ಕಗಳ ಸಂಖ್ಯೆ ಮತ್ತು ಒಂದೇ IPಯ ಹಿಂದೆ ಕಂಡುಬಂದ ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯನ್ನು ತೋರಿಸಿ. ಇದು ಓದಲು ಮಾತ್ರ; ಪ್ರಾಕ್ಸಿ ಲಾಗ್ನಿಂದ ಲೆಕ್ಕ ಹಾಕಲಾಗುತ್ತದೆ ಮತ್ತು ರೂಟಿಂಗ್ಗಾಗಿ ಎಂದಿಗೂ ಬಳಸಲಾಗುವುದಿಲ್ಲ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆಫ್: ಪೂಲ್ ಎಡಿಟರ್ ಬದಲಾಗುವುದಿಲ್ಲ ಮತ್ತು ವೀಕ್ಷಣಾ ರೂಟ್ null ಎಂದು ಉತ್ತರಿಸುತ್ತದೆ.", "featureFlagProxyHealthBlockedResetsStreakDescription": "ಪ್ರಾಕ್ಸಿ ಆರೋಗ್ಯ ಪರಿಶೀಲನೆಯಲ್ಲಿ, ಗುರಿಯು ನಿರಾಕರಿಸಿದ ಪ್ರೋಬ್ (401/403/429: ಪ್ರಾಕ್ಸಿಯು ರಿಲೇ ಮಾಡಿದೆ, ಆದರೆ ಗಮ್ಯಸ್ಥಾನವು ಈ ಎಗ್ರೆಸ್ IPಯನ್ನು ನಿರಾಕರಿಸಿದೆ) ಸೇವೆ ಸಲ್ಲಿಸಿದ ಪ್ರೋಬ್ನಂತೆಯೇ ಪ್ರಾಕ್ಸಿಯ ಸತತ-ವೈಫಲ್ಯ ಸರಣಿಯನ್ನು ಮರುಹೊಂದಿಸಲು ಅನುಮತಿಸಿ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆಫ್: ನಿರಾಕರಣೆಯು ತಟಸ್ಥವಾಗಿಯೇ ಉಳಿದು ಸರಣಿಯನ್ನು ಹಾಗೆಯೇ ಇಡುತ್ತದೆ. ಎರಡೂ ಸಂದರ್ಭಗಳಲ್ಲಿ 5xx ಅನಿರ್ಣಾಯಕವಾಗಿಯೇ ಉಳಿಯುತ್ತದೆ ಮತ್ತು ನಿರಾಕರಣೆಯು ಪ್ರಾಕ್ಸಿಯನ್ನು ಎಂದಿಗೂ ತೆಗೆದುಹಾಕುವುದಿಲ್ಲ, ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುವುದಿಲ್ಲ ಅಥವಾ ಮರುಸಕ್ರಿಯಗೊಳಿಸುವುದಿಲ್ಲ.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ಸ್ವಯಂಚಾಲಿತ ಸ್ವಚ್ಛತಾ ಪ್ರಕ್ರಿಯೆಯು OMNIROUTE_BATCH_RETENTION_DAYS ಗಿಂತ ಹಳೆಯದಾದ ಅಂತಿಮ ಸ್ಥಿತಿಯ (ಪೂರ್ಣಗೊಂಡ/ವಿಫಲಗೊಂಡ/ರದ್ದುಗೊಂಡ/ಅವಧಿ ಮೀರಿದ) Batch API ಕೆಲಸಗಳನ್ನು, ಅವುಗಳ ಪ್ರತಿ-ಸಾಲಿನ ಚೆಕ್ಪಾಯಿಂಟ್ಗಳೊಂದಿಗೆ ಅಳಿಸಲು ಮತ್ತು ತಮ್ಮದೇ expires_at ಮೀರಿರುವ ಅಪ್ಲೋಡ್ ಮಾಡಿದ ಫೈಲ್ಗಳ BLOB ವಿಷಯವನ್ನು ತೆರವುಗೊಳಿಸಲು ಅನುಮತಿಸಿ. ಡೀಫಾಲ್ಟ್ ಆಗಿ ಆಫ್ ಆಗಿರುತ್ತದೆ: ನಿರ್ವಾಹಕರು ಆಯ್ಕೆಮಾಡಿ ಸಕ್ರಿಯಗೊಳಿಸುವವರೆಗೆ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ರತಿಯೊಂದು ಸ್ಥಾಪನೆಯೂ ಈ ಡೇಟಾವನ್ನು ಮೊದಲಿನಂತೆಯೇ ಉಳಿಸಿಕೊಳ್ಳುತ್ತದೆ. ನಿರ್ವಾಹಕರು ಪ್ರಚೋದಿಸುವ DELETE /api/v1/batches/delete-completed ಮಾರ್ಗವು ಯಾವುದೇ ಸಂದರ್ಭದಲ್ಲೂ ಪರಿಣಾಮಗೊಳ್ಳುವುದಿಲ್ಲ — ಅದು ಪ್ರತ್ಯೇಕವಾದ, ಷರತ್ತುರಹಿತ ಸಾರ್ವಜನಿಕ API ಒಪ್ಪಂದವಾಗಿದೆ.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "ನಿಮ್ಮ AI ಸಂಪರ್ಕ URLs", "apiManager": "API ಕೀಗಳು", "apiManagerSubtitle": "API ಕೀಗಳು ಮತ್ತು ಪ್ರವೇಶವನ್ನು ನಿರ್ವಹಿಸಿ", + "modelCatalog": "ಮಾಡೆಲ್‌ಗಳು & ಕಾಂಬೋಗಳು", + "modelCatalogSubtitle": "ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾಡೆಲ್‌ಗಳು ಮತ್ತು ಕಾಂಬೋಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ", "embeddedServices": "ಅಂತರ್ನಿರ್ಮಿತ ಸೇವೆಗಳು", "embeddedServicesSubtitle": "ಐಚ್ಛಿಕ ಸ್ಥಳೀಯ ಸೇವೆಗಳು", "logs": "ಲಾಗ್ಗಳು", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index 82d28b2b6493..15f1fb421fa4 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "공급자 디스패치를 위해 테넌트별 적응형 가상 승인 레인을 활성화합니다(#9654): 한 테넌트의 폭증이 더 이상 다른 테넌트에 503을 반환하지 않습니다. OMNIROUTE_CHAT_VIRTUAL_LANES 환경 변수가 이 대시보드 설정보다 우선하며, 변경 사항은 서버 재시작 시 적용됩니다.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "대시보드 제공업체 페이지: 제공업체가 인정하는 신호에만 무료 배지를 표시합니다. 문서화된 무료 등급이 없는 등록된 제공업체의 표시 이름 추정 방식, 불리언이 아닌 무료 필드 및 :free 접미사는 사용하지 않습니다. 끄면 기존 배지 규칙이 유지됩니다.", "featureFlagProxySkipRecentlyFailedDescription": "프록시 풀과 opencode의 계정별 로테이션은 방금 실패한 프록시(TCP 프로브 거부 또는 해당 프록시를 통해 429 응답 수신)를 프로세스별 유예 기간 동안 다시 제공하지 않습니다. 이 기간은 실패가 반복될 때마다 두 배로 늘어나며 상한이 있습니다. 프록시 상태는 기록되지 않으며, 모든 후보가 제외되면 선택 결과는 변경되지 않습니다. 기본적으로 켜져 있으며, `false`로 설정하면 일반 선택으로 돌아갑니다.", + "featureFlagProxyPoolSharedEgressOrderDescription": "이그레스 주소 기준으로 쿼터가 분할되는 제공자의 경우, 최근 요청이 거부된 멤버와 동일한 이그레스 주소로 확인된 풀 멤버의 우선순위를 정상 멤버 바로 뒤로 배치합니다. 순서만 변경되며 풀에서 제외되지는 않습니다. 거부 신호를 감지하려면 해당 신호를 생성하는 PROXY_SKIP_RECENTLY_FAILED가 활성화되어 있어야 합니다. 기본값은 비활성화이며, 선택 순서는 일반 로테이션과 동일합니다.", "featureFlagProxyPoolEgressObservationDescription": "대시보드의 프록시 풀 아래에 지난 24시간 동안 해당 풀의 구성원에 사용된 것으로 관찰된 송신 IP 수, 해당 IP를 사용한 연결 수, 단일 IP에서 관찰된 최대 연결 수를 표시합니다. 읽기 전용이며 프록시 로그에서 계산되고 라우팅에는 절대 사용되지 않습니다. 기본적으로 꺼져 있으며, 풀 편집기는 변경되지 않고 관찰 라우트는 null을 반환합니다.", "featureFlagProxyHealthBlockedResetsStreakDescription": "프록시 상태 점검에서 대상이 거부한 프로브(401/403/429: 프록시는 전달했지만 대상이 이 송신 IP를 거부함)가 정상 처리된 프로브처럼 프록시의 연속 실패 횟수를 초기화하도록 합니다. 기본적으로 꺼져 있으며, 거부는 중립으로 유지되어 연속 실패 횟수에 영향을 주지 않습니다. 어느 경우든 5xx는 판단 불가로 유지되며, 거부로 인해 프록시가 제거, 비활성화 또는 재활성화되는 일은 없습니다.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "자동 정리 작업이 OMNIROUTE_BATCH_RETENTION_DAYS보다 오래된 종료 상태(완료/실패/취소/만료)의 Batch API 작업과 해당 작업의 줄별 체크포인트를 삭제하고, 자체 expires_at이 지난 업로드 파일의 BLOB 콘텐츠를 지우도록 합니다. 기본적으로 꺼져 있습니다. 운영자가 사용 설정하기 전까지 모든 기존 설치는 이 데이터를 이전과 정확히 동일하게 유지합니다. 운영자가 실행하는 DELETE /api/v1/batches/delete-completed 경로는 설정 여부와 관계없이 영향을 받지 않습니다. 이는 별도의 무조건적인 공개 API 계약입니다.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "귀하의 AI 연결 URL", "apiManager": "API 키", "apiManagerSubtitle": "API 키 및 액세스 관리", + "modelCatalog": "모델 및 콤보", + "modelCatalogSubtitle": "여러 제공자의 모델 및 콤보 둘러보기", "embeddedServices": "내장 서비스", "embeddedServicesSubtitle": "로컬 프록시 서비스 관리", "logs": "로그", diff --git a/src/i18n/messages/lt.json b/src/i18n/messages/lt.json index 43bbf1c4054e..e02495b320a5 100644 --- a/src/i18n/messages/lt.json +++ b/src/i18n/messages/lt.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Įjungti kiekvienam nuomotojui pritaikomas adaptyvias virtualias priėmimo juostas teikėjų siuntimui (#9654): vieno nuomotojo srautas nebesukelia 503 klaidos kitam. Aplinkos kintamasis OMNIROUTE_CHAT_VIRTUAL_LANES turi pirmenybę prieš šį skydelio nustatymą; pakeitimai įsigalioja po serverio paleidimo iš naujo.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Teikėjų puslapiuose valdymo skydelyje ženklelį „Nemokama“ rodyti tik pagal tuos požymius, kuriuos teikėjas palaiko — nebenaudojama rodomo pavadinimo euristika, ne loginio tipo nemokamumo laukai ir :free priesagos registruotiems teikėjams, neturintiems dokumentuoto nemokamo plano. Išjungus taikoma ankstesnė ženklelio taisyklė.", "featureFlagProxySkipRecentlyFailedDescription": "Tarpinių serverių telkiniai ir kiekvienai paskyrai taikoma opencode rotacija pakartotinai nebenaudoja ką tik nesuveikusio tarpinio serverio (atmestas TCP patikrinimas arba per jį gautas 429 atsakymas) konkrečiam procesui taikomą laikotarpį, kuris po kiekvieno pasikartojimo padvigubėja iki nustatytos ribos. Tarpinio serverio būsena neįrašoma; atidėjus visus kandidatus, pasirinkimas nesikeičia. Pagal numatytąsias nuostatas įjungta; `false` atkuria įprastą pasirinkimą.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Teikėjams, kurių kvota skirstoma pagal egress adresą, telkinio narį, turintį tą patį stebėtą egress adresą kaip ir neseniai atmestas narys, reitinguoti iškart žemiau sveikų narių. Tik rikiavimas, niekada neišskiriama. Reikalingas PROXY_SKIP_RECENTLY_FAILED, kuris sugeneruoja nuskaitomą atmetimo signalą. Pagal numatytuosius nustatymus išjungta: pasirinkimo tvarka yra tiesiog įprasta rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Valdymo skydelyje po tarpinių serverių telkiniu rodyti, kiek stebėtų išeinančių IP adresų per pastarąsias 24 val. aptarnavo jo narius, kiek ryšių juos naudojo ir didžiausią ryšių skaičių, stebėtą už vieno IP adreso. Tik skaitymui, apskaičiuojama pagal tarpinių serverių žurnalą ir niekada nenaudojama maršrutizavimui. Pagal numatytąsias nuostatas išjungta: telkinio redagavimo priemonė nesikeičia, o stebėjimo maršrutas grąžina null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Atliekant tarpinių serverių būklės patikrą leisti paskirties vietos atmestam patikrinimui (401/403/429: tarpinis serveris persiuntė užklausą, o paskirties vieta atmetė šį išeinantį IP adresą) iš naujo nustatyti tarpinio serverio nuoseklių nesėkmių seką, kaip ir aptarnauto patikrinimo atveju. Pagal numatytąsias nuostatas išjungta: atmetimas lieka neutralus ir išsaugo seką. 5xx atsakymas abiem atvejais lieka neapibrėžtas, o atmetimas niekada nepašalina, neišjungia ir iš naujo nesuaktyvina tarpinio serverio.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Leisti automatiniam valymui pašalinti galutines būsenas pasiekusias (užbaigtas / nepavykusias / atšauktas / nebegaliojančias) Batch API užduotis, senesnes nei OMNIROUTE_BATCH_RETENTION_DAYS, kartu su kiekvienos jų eilutės kontroliniais taškais ir išvalyti įkeltų failų, kurių expires_at jau praėjo, BLOB turinį. Pagal numatytąsias nuostatas išjungta: visuose esamuose diegimuose šie duomenys išsaugomi lygiai taip pat kaip anksčiau, kol operatorius šios funkcijos neįjungia. Operatoriaus iškviečiamam maršrutui DELETE /api/v1/batches/delete-completed ši nuostata jokios įtakos neturi – tai atskira, besąlyginė viešosios API sutartis.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Jūsų DI ryšio URL adresai", "apiManager": "API raktai", "apiManagerSubtitle": "Tvarkyti API raktus ir prieigą", + "modelCatalog": "Modeliai ir deriniai", + "modelCatalogSubtitle": "Naršykite modelius ir derinius iš įvairių teikėjų", "embeddedServices": "Įterptosios paslaugos", "embeddedServicesSubtitle": "Pasirenkamos vietinės paslaugos", "logs": "Žurnalai", diff --git a/src/i18n/messages/lv.json b/src/i18n/messages/lv.json index b8b63da431b7..808daec18abc 100644 --- a/src/i18n/messages/lv.json +++ b/src/i18n/messages/lv.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Iespējot katra nomnieka adaptīvas virtuālās uzņemšanas joslas nodrošinātāju izsūtīšanai (#9654): viena nomnieka slodzes lēciens vairs neizraisa 503 kļūdu citam. OMNIROUTE_CHAT_VIRTUAL_LANES vides mainīgais ir prioritārāks par šo paneļa iestatījumu; izmaiņas stājas spēkā pēc servera pārstartēšanas.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pakalpojumu sniedzēju lapas informācijas panelī: rādīt emblēmu “Bezmaksas” tikai tad, ja to apliecina pakalpojumu sniedzēja atbalstītie signāli — netiek izmantota parādāmā nosaukuma heiristika, lauki par bezmaksas pieejamību, kuru vērtības nav Būla vērtības, un reģistrētu pakalpojumu sniedzēju sufiksi :free, ja tiem nav dokumentēta bezmaksas līmeņa. Izslēdzot šo opciju, tiek saglabāts iepriekšējais emblēmas rādīšanas noteikums.", "featureFlagProxySkipRecentlyFailedDescription": "Starpniekserveru pūli un opencode konta līmeņa rotācija uz katru procesu uz noteiktu laiku pārtrauc atkārtoti izmantot starpniekserveri, kas tikko cieta kļūmi (noraidīta TCP pārbaude vai caur to saņemts 429); šis laiks pēc katras atkārtotas kļūmes dubultojas līdz noteiktajam maksimumam. Starpniekservera statuss netiek ierakstīts; ja visi kandidāti ir atlikti malā, izvēle paliek nemainīga. Pēc noklusējuma ieslēgts; `false` atjauno parasto atlasi.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Pakalpojumu sniedzējiem, kuru kvota tiek grupēta pēc izejošās adreses, ierindot pūla dalībnieku, kuram ir tāda pati novērotā izejošā adrese kā nesen noraidītajam dalībniekam, tieši aiz veselajiem dalībniekiem. Tikai secība, nekad netiek izslēgts. Nepieciešams PROXY_SKIP_RECENTLY_FAILED, kas ģenerē noraidījuma signālu, ko tas nolasa. Pēc noklusējuma izslēgts: atlases secība precīzi atbilst parastajai rotācijai.", "featureFlagProxyPoolEgressObservationDescription": "Informācijas panelī zem starpniekserveru pūla rādīt, cik novēroto izejošo IP adrešu pēdējo 24 h laikā apkalpoja tā dalībniekus, cik savienojumu tās izmantoja un kāds bija lielākais aiz vienas IP adreses novērotais savienojumu skaits. Tikai lasāms, aprēķināts no starpniekserveru žurnāla un nekad netiek izmantots maršrutēšanai. Pēc noklusējuma izslēgts: pūla redaktors paliek nemainīgs, un novērojumu maršruts atgriež null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Starpniekserveru darbspējas pārbaudē ļaut mērķa noraidītai pārbaudei (401/403/429: starpniekserveris pārsūtīja pieprasījumu, bet galamērķis noraidīja šo izejošo IP adresi) atiestatīt starpniekservera secīgo kļūmju sēriju tāpat kā apkalpotai pārbaudei. Pēc noklusējuma izslēgts: noraidījums paliek neitrāls un saglabā kļūmju sēriju. 5xx jebkurā gadījumā paliek nepārliecinošs, un noraidījums nekad neizraisa starpniekservera noņemšanu, atspējošanu vai atkārtotu aktivizēšanu.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ļaut automātiskajai tīrīšanai dzēst pabeigtus, neizdevušos, atceltus vai beigušos Batch API uzdevumus, kas ir vecāki par OMNIROUTE_BATCH_RETENTION_DAYS, kopā ar to kontrolpunktiem katrai rindai, kā arī notīrīt BLOB saturu augšupielādētajiem failiem, kuru pašu expires_at termiņš ir beidzies. Pēc noklusējuma izslēgts: katra esošā instalācija turpina glabāt šos datus tieši tāpat kā iepriekš, līdz operators izvēlas šo funkciju ieslēgt. Operatora aktivizētais maršruts DELETE /api/v1/batches/delete-completed abos gadījumos netiek ietekmēts — tas ir atsevišķs, beznosacījumu publiskās API līgums.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Jūsu AI savienojuma URL", "apiManager": "API atslēgas", "apiManagerSubtitle": "Pārvaldīt API atslēgas un piekļuvi", + "modelCatalog": "Modeļi un kombinācijas", + "modelCatalogSubtitle": "Pārlūkot modeļus un kombinācijas visos pakalpojumu sniedzējos", "embeddedServices": "Iegultie pakalpojumi", "embeddedServicesSubtitle": "Neobligāti lokālie pakalpojumi", "logs": "Žurnāli", diff --git a/src/i18n/messages/ml.json b/src/i18n/messages/ml.json index 886df9b77df9..8209d02e6786 100644 --- a/src/i18n/messages/ml.json +++ b/src/i18n/messages/ml.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "പ്രൊവൈഡർ ഡിസ്പാച്ചിനായി ഓരോ ടെനന്റിനും അനുയോജ്യമായി മാറുന്ന വെർച്വൽ അഡ്മിഷൻ ലെയിനുകൾ പ്രവർത്തനക്ഷമമാക്കുക (#9654): ഇനി ഒരു ടെനന്റിന്റെ പെട്ടെന്നുള്ള അഭ്യർത്ഥന വർധന മറ്റൊരാൾക്ക് 503 പിശക് സൃഷ്ടിക്കില്ല. ഈ ഡാഷ്ബോർഡ് ഓവർറൈഡിനേക്കാൾ OMNIROUTE_CHAT_VIRTUAL_LANES env var-ന് മുൻഗണനയുണ്ട്; സെർവർ പുനരാരംഭിക്കുമ്പോൾ മാറ്റങ്ങൾ പ്രാബല്യത്തിൽ വരും.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ഡാഷ്ബോർഡ് പ്രൊവൈഡർ പേജുകൾ: പ്രൊവൈഡർ അംഗീകരിക്കുന്ന സൂചനകളിൽ മാത്രം Free ബാഡ്ജ് കാണിക്കുക — രേഖപ്പെടുത്തിയ സൗജന്യ ടയർ ഇല്ലാത്ത രജിസ്റ്റർ ചെയ്ത പ്രൊവൈഡറുകളിൽ ഡിസ്പ്ലേ-നെയിം ഹ്യൂറിസ്റ്റിക്, ബൂളിയൻ അല്ലാത്ത free ഫീൽഡുകൾ, :free സഫിക്സുകൾ എന്നിവ ഒഴിവാക്കുന്നു. ഓഫാക്കിയാൽ പഴയ ബാഡ്ജ് നിയമം നിലനിർത്തും.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy പൂളുകളും opencode-ന്റെ ഓരോ അക്കൗണ്ടിലുമുള്ള റൊട്ടേഷനും, ഇപ്പോൾ പരാജയപ്പെട്ട ഒരു Proxy-യെ (നിരസിക്കപ്പെട്ട TCP പ്രോബ്, അല്ലെങ്കിൽ അതിലൂടെ ലഭിച്ച 429) ഓരോ ആവർത്തനത്തിലും ഇരട്ടിയാകുന്ന, ഒരു പരമാവധി പരിധിവരെയുള്ള ഓരോ പ്രോസസിനുമുള്ള കാലയളവിൽ വീണ്ടും ഉപയോഗിക്കുന്നത് നിർത്തുന്നു. Proxy നിലയൊന്നും രേഖപ്പെടുത്തില്ല; എല്ലാ സ്ഥാനാർഥികളെയും മാറ്റിവെച്ചാൽ തിരഞ്ഞെടുപ്പ് മാറ്റമില്ലാതെ തുടരും. ഡിഫോൾട്ടായി ഓണാണ്; `false` സാധാരണ തിരഞ്ഞെടുപ്പ് പുനഃസ്ഥാപിക്കുന്നു.", + "featureFlagProxyPoolSharedEgressOrderDescription": "egress address അനുസരിച്ച് ക്വാട്ട നിശ്ചയിച്ചിട്ടുള്ള പ്രൊവൈഡർമാർക്കായി, അടുത്തിടെ നിരസിക്കപ്പെട്ട ഒരു അംഗത്തിന്റെ egress address പങ്കിടുന്ന പൂൾ അംഗത്തെ ഹെൽത്തി ആയ അംഗങ്ങൾക്ക് തൊട്ടുതാഴെയായി റാങ്ക് ചെയ്യുക. ക്രമത്തിൽ മാറ്റം വരുത്താൻ മാത്രം, ഒരിക്കലും ഒഴിവാക്കപ്പെടില്ല. ഇത് വായിക്കുന്ന നിരസിക്കൽ സിഗ്നൽ നൽകുന്ന PROXY_SKIP_RECENTLY_FAILED ഇതിന് ആവശ്യമാണ്. ഡിഫോൾട്ടായി ഓഫാണ്: തിരഞ്ഞെടുക്കൽ ക്രമം കൃത്യമായി സാധാരണ റൊട്ടേഷൻ തന്നെയായിരിക്കും.", "featureFlagProxyPoolEgressObservationDescription": "ഡാഷ്ബോർഡിലെ ഒരു Proxy പൂളിന് കീഴിൽ, കഴിഞ്ഞ 24 മണിക്കൂറിനിടെ അതിലെ അംഗങ്ങൾക്ക് സേവനം നൽകിയതായി നിരീക്ഷിച്ച എത്ര എഗ്രസ് IP-കൾ ഉണ്ടായിരുന്നു, എത്ര കണക്ഷനുകൾ അവ ഉപയോഗിച്ചു, ഒരു IP-ക്ക് പിന്നിൽ കണ്ട ഏറ്റവും ഉയർന്ന എണ്ണം എത്ര എന്നിവ കാണിക്കുക. വായനയ്ക്ക് മാത്രം; Proxy ലോഗിൽനിന്ന് കണക്കാക്കുന്നതും റൂട്ടിംഗിനായി ഒരിക്കലും ഉപയോഗിക്കാത്തതുമാണ്. ഡിഫോൾട്ടായി ഓഫാണ്: പൂൾ എഡിറ്ററിൽ മാറ്റമില്ല, നിരീക്ഷണ റൂട്ട് null എന്ന് മറുപടി നൽകും.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ആരോഗ്യ പരിശോധനയിൽ, ലക്ഷ്യം നിരസിച്ച ഒരു പ്രോബ് (401/403/429: Proxy റിലേ ചെയ്തു, ലക്ഷ്യസ്ഥാനം ഈ എഗ്രസ് IP നിരസിച്ചു) സേവനം നൽകിയ പ്രോബിനെപ്പോലെ Proxy-യുടെ തുടർച്ചയായ പരാജയങ്ങളുടെ എണ്ണം പുനഃസജ്ജമാക്കാൻ അനുവദിക്കുക. ഡിഫോൾട്ടായി ഓഫാണ്: ഒരു നിരസിക്കൽ നിഷ്പക്ഷമായി തുടരുകയും പരാജയങ്ങളുടെ എണ്ണം നിലനിർത്തുകയും ചെയ്യും. ഏതുവിധമായാലും 5xx അനിശ്ചിതമായി തുടരും; ഒരു നിരസിക്കൽ ഒരിക്കലും Proxy-യെ നീക്കം ചെയ്യുകയോ പ്രവർത്തനരഹിതമാക്കുകയോ വീണ്ടും സജീവമാക്കുകയോ ചെയ്യില്ല.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS-നേക്കാൾ പഴക്കമുള്ള ടെർമിനൽ (പൂർത്തിയായ/പരാജയപ്പെട്ട/റദ്ദാക്കിയ/കാലഹരണപ്പെട്ട) Batch API ജോലികളും അവയുടെ ഓരോ വരിയിലുമുള്ള ചെക്ക്പോയിന്റുകളും സ്വയമേവയുള്ള ക്ലീനപ്പ് സ്വീപ്പിലൂടെ ഇല്ലാതാക്കാനും, സ്വന്തം expires_at കഴിഞ്ഞ അപ്ലോഡ് ചെയ്ത ഫയലുകളുടെ BLOB ഉള്ളടക്കം മായ്ക്കാനും അനുവദിക്കുക. ഡിഫോൾട്ടായി ഓഫാണ്: ഒരു ഓപ്പറേറ്റർ ഇത് പ്രവർത്തനക്ഷമമാക്കുന്നതുവരെ നിലവിലുള്ള എല്ലാ ഇൻസ്റ്റാളേഷനുകളും ഈ ഡാറ്റ മുമ്പത്തേതുപോലെ തന്നെ നിലനിർത്തും. ഓപ്പറേറ്റർ ട്രിഗർ ചെയ്യുന്ന DELETE /api/v1/batches/delete-completed റൂട്ടിനെ ഇത് ഒരു തരത്തിലും ബാധിക്കില്ല — അത് വേറിട്ടതും നിബന്ധനകളില്ലാത്തതുമായ ഒരു പൊതു API കരാറാണ്.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "നിങ്ങളുടെ AI കണക്ഷൻ URL-കൾ", "apiManager": "API കീകൾ", "apiManagerSubtitle": "API കീകളും ആക്സസും നിയന്ത്രിക്കുക", + "modelCatalog": "മോഡലുകളും കോമ്പോകളും", + "modelCatalogSubtitle": "വിവിധ പ്രൊവൈഡർമാരിലുടനീളമുള്ള മോഡലുകളും കോമ്പോകളും ബ്രൗസ് ചെയ്യുക", "embeddedServices": "എംബെഡഡ് സേവനങ്ങൾ", "embeddedServicesSubtitle": "ഐച്ഛിക ലോക്കൽ സേവനങ്ങൾ", "logs": "ലോഗുകൾ", diff --git a/src/i18n/messages/mr.json b/src/i18n/messages/mr.json index 5919fae6224c..98fa7a5ebd75 100644 --- a/src/i18n/messages/mr.json +++ b/src/i18n/messages/mr.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदाता डिस्पॅचसाठी प्रति-टेनंट अनुकूली व्हर्च्युअल अॅडमिशन लेन सक्षम करा (#9654): एका टेनंटचा बर्स्ट यापुढे दुसऱ्या टेनंटला 503 देत नाही. OMNIROUTE_CHAT_VIRTUAL_LANES पर्यावरण चल या डॅशबोर्ड सेटिंगपेक्षा वरचढ आहे; बदल सर्व्हर रीस्टार्ट केल्यावर प्रभावी होतात.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "डॅशबोर्डवरील प्रदाता पृष्ठे: प्रदाता मान्य करतो अशाच संकेतांवर मोफत बॅज दाखवा — दस्तऐवजीकृत मोफत स्तर नसलेल्या नोंदणीकृत प्रदात्यांसाठी प्रदर्शन-नाव अनुमान, नॉन-बूलियन मोफत फील्ड आणि :free प्रत्यय वगळले जातात. बंद केल्यास ऐतिहासिक बॅज नियम कायम राहतो.", "featureFlagProxySkipRecentlyFailedDescription": "प्रॉक्सी पूल आणि opencode चे प्रति-खाते रोटेशन नुकताच अयशस्वी झालेला प्रॉक्सी (TCP प्रोब नाकारला गेला किंवा त्याद्वारे 429 प्राप्त झाला) प्रत्येक प्रक्रियेसाठी ठरावीक कालावधीपर्यंत पुन्हा वापरत नाहीत; प्रत्येक पुनरावृत्तीनंतर हा कालावधी दुप्पट होतो, कमाल मर्यादेपर्यंत. प्रॉक्सीची कोणतीही स्थिती लिहिली जात नाही; प्रत्येक उमेदवार बाजूला ठेवल्यास निवड अपरिवर्तित राहते. डीफॉल्टनुसार चालू; `false` साधी निवड पुनर्संचयित करते.", + "featureFlagProxyPoolSharedEgressOrderDescription": "ज्या प्रदात्यांसाठी कोटा egress पत्त्यानुसार विभागला गेला आहे, त्यांच्यासाठी नुकत्याच नाकारलेल्या सदस्याचा नोंदवलेला egress पत्ता शेअर करणाऱ्या पूल सदस्याला निरोगी सदस्यांच्या अगदी खाली क्रमवारी द्या. केवळ क्रमवारी, कधीही वगळले जात नाही. यासाठी PROXY_SKIP_RECENTLY_FAILED आवश्यक आहे, जे ते वाचत असलेला नकार सिग्नल तयार करते. बाय डीफॉल्ट बंद: निवड क्रम अगदी सामान्य रोटेशनप्रमाणे असतो.", "featureFlagProxyPoolEgressObservationDescription": "डॅशबोर्डमध्ये प्रॉक्सी पूलखाली, मागील 24 तासांत त्याच्या सदस्यांना सेवा देणारे किती निरीक्षित इग्रेस IP होते, किती कनेक्शन्सनी त्यांचा वापर केला आणि एका IP मागून सर्वाधिक किती कनेक्शन्स दिसली हे दाखवा. हे केवळ-वाचनीय असून प्रॉक्सी लॉगवरून मोजले जाते आणि रूटिंगसाठी कधीही वापरले जात नाही. डीफॉल्टनुसार बंद: पूल एडिटर अपरिवर्तित राहतो आणि निरीक्षण रूट null असे उत्तर देतो.", "featureFlagProxyHealthBlockedResetsStreakDescription": "प्रॉक्सी आरोग्य तपासणीमध्ये, लक्ष्याने नाकारलेल्या प्रोबला (401/403/429: प्रॉक्सीने पुढे पाठवले, पण गंतव्याने हा इग्रेस IP नाकारला) सेवा दिलेल्या प्रोबप्रमाणे प्रॉक्सीच्या सलग अपयशांची मालिका रीसेट करू द्या. डीफॉल्टनुसार बंद: नकार तटस्थ राहतो आणि मालिका कायम ठेवतो. 5xx दोन्ही बाबतींत अनिर्णीत राहतो आणि नकारामुळे प्रॉक्सी कधीही काढला, अक्षम किंवा पुन्हा सक्रिय केला जात नाही.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वयंचलित क्लीनअप स्वीपला OMNIROUTE_BATCH_RETENTION_DAYS पेक्षा जुनी टर्मिनल (पूर्ण/अयशस्वी/रद्द केलेली/कालबाह्य) Batch API कार्ये, त्यांच्या प्रत्येक ओळीच्या चेकपॉइंटसह हटवू द्या आणि स्वतःची expires_at वेळ उलटून गेलेल्या अपलोड केलेल्या फाइल्समधील BLOB सामग्री साफ करू द्या. डीफॉल्टनुसार बंद: ऑपरेटरने हे सुरू करेपर्यंत प्रत्येक विद्यमान इंस्टॉलेशन हा डेटा पूर्वीप्रमाणेच ठेवते. ऑपरेटरने ट्रिगर केलेला DELETE /api/v1/batches/delete-completed मार्ग कोणत्याही परिस्थितीत अप्रभावित राहतो — तो स्वतंत्र, बिनशर्त सार्वजनिक API करार आहे.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "तुमचे AI कनेक्शन URL", "apiManager": "API कीज", "apiManagerSubtitle": "API की आणि प्रवेश व्यवस्थापित करा", + "modelCatalog": "मॉडेल्स आणि कॉम्बो", + "modelCatalogSubtitle": "विविध प्रदात्यांमधील मॉडेल्स आणि कॉम्बो ब्राउझ करा", "embeddedServices": "एम्बेडेड सेवा", "embeddedServicesSubtitle": "स्थानिक प्रॉक्सी सेवा व्यवस्थापित करा", "logs": "लॉग्स", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index 974551e756b6..c5c417f12b01 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktifkan lorong kemasukan maya adaptif setiap-tenant untuk penghantaran pembekal (#9654): lonjakan satu tenant tidak lagi memberikan 503 kepada tenant lain. Pemboleh ubah persekitaran OMNIROUTE_CHAT_VIRTUAL_LANES mengatasi tetapan papan pemuka ini; perubahan berkuat kuasa apabila pelayan dimulakan semula.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Halaman penyedia papan pemuka: tunjukkan lencana Percuma hanya pada isyarat yang disokong oleh penyedia — menggugurkan heuristik nama paparan, medan percuma bukan boolean dan akhiran :free pada penyedia berdaftar tanpa peringkat percuma yang didokumenkan. Mati mengekalkan peraturan lencana terdahulu.", "featureFlagProxySkipRecentlyFailedDescription": "Kumpulan proksi dan penggiliran opencode bagi setiap akaun akan berhenti menyediakan semula proksi yang baru sahaja gagal (probe TCP ditolak atau 429 diterima melaluinya) untuk tempoh bagi setiap proses yang berganda pada setiap kegagalan berulang, sehingga had maksimum. Tiada status proksi direkodkan; apabila setiap calon diketepikan, pilihan tidak berubah. Dihidupkan secara lalai; `false` memulihkan pemilihan biasa.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Untuk penyedia yang kuotanya dikelompokkan mengikut alamat egress, letakkan kedudukan ahli kolam yang berkongsi alamat egress diperhatikan bagi ahli yang baru ditolak tepat di bawah ahli yang sihat. Tertib sahaja, tidak pernah dikecualikan. Memerlukan PROXY_SKIP_RECENTLY_FAILED, yang menghasilkan isyarat penolakan yang dibacanya. Dimatikan secara lalai: susunan pemilihan adalah tepat mengikut putaran biasa.", "featureFlagProxyPoolEgressObservationDescription": "Tunjukkan, di bawah kumpulan proksi dalam papan pemuka, bilangan IP keluar yang diperhatikan telah digunakan oleh ahlinya sepanjang 24 jam yang lalu, bilangan sambungan yang menggunakannya dan bilangan terbanyak yang dilihat di sebalik satu IP. Baca sahaja, dikira daripada log proksi dan tidak pernah digunakan untuk penghalaan. Dimatikan secara lalai: editor kumpulan tidak berubah dan laluan pemerhatian memberikan null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Dalam imbasan kesihatan proksi, benarkan probe yang ditolak oleh sasaran (401/403/429: proksi telah menyampaikan permintaan, tetapi destinasi menolak IP keluar ini) menetapkan semula rentetan kegagalan berturut-turut proksi, seperti probe yang berjaya dilayan. Dimatikan secara lalai: penolakan kekal neutral dan mengekalkan rentetan tersebut. 5xx kekal tidak muktamad dalam kedua-dua keadaan dan penolakan tidak akan mengalih keluar, menyahdayakan atau mengaktifkan semula proksi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Benarkan proses pembersihan automatik memadam tugas API Batch berstatus terminal (completed/failed/cancelled/expired) yang lebih lama daripada OMNIROUTE_BATCH_RETENTION_DAYS, berserta titik semak setiap barisnya, dan mengosongkan kandungan BLOB bagi fail yang dimuat naik selepas expires_at masing-masing. Dimatikan secara lalai: setiap pemasangan sedia ada mengekalkan data ini tepat seperti sebelumnya sehingga pengendali memilih untuk mengaktifkannya. Laluan DELETE /api/v1/batches/delete-completed yang dicetuskan oleh pengendali tidak terjejas dalam mana-mana keadaan — laluan itu ialah kontrak API awam berasingan yang tidak bersyarat.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL sambungan AI anda", "apiManager": "Pengurus API", "apiManagerSubtitle": "Urus kunci dan akses API", + "modelCatalog": "Model & Kombo", + "modelCatalogSubtitle": "Semak imbas model dan kombo merentas penyedia", "embeddedServices": "Perkhidmatan Terbenam", "embeddedServicesSubtitle": "Urus perkhidmatan proksi tempatan", "logs": "Log", diff --git a/src/i18n/messages/mt.json b/src/i18n/messages/mt.json index bb2f56e01e45..7dcc98e34212 100644 --- a/src/i18n/messages/mt.json +++ b/src/i18n/messages/mt.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ippermetti korsiji virtwali adattivi tad-dħul għal kull tenant għad-dispaċċ tal-fornituri (#9654): żieda f'daqqa fit-traffiku ta' tenant wieħed ma tibqax tikkawża żball 503 għal ieħor. Il-varjabbli tal-ambjent OMNIROUTE_CHAT_VIRTUAL_LANES tieħu preċedenza fuq din is-sovraskrittura tad-dashboard; il-bidliet jidħlu fis-seħħ meta jerġa' jinbeda s-server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Paġni tal-fornituri fid-dashboard: uri l-badge B’Xejn biss abbażi ta’ indikazzjonijiet li l-fornitur jirrikonoxxi — ineħħi l-ewristika tal-isem muri, il-kampijiet mhux Boolejani dwar l-użu bla ħlas u s-suffissi :free fuq fornituri rreġistrati mingħajr livell bla ħlas dokumentat. Meta jkun Mitfi, tinżamm ir-regola storika tal-badge.", "featureFlagProxySkipRecentlyFailedDescription": "Il-pools tal-proxy u r-rotazzjoni għal kull kont ta’ opencode jieqfu jerġgħu jservu proxy li jkun għadu kemm falla (sonda TCP miċħuda, jew 429 riċevut permezz tiegħu) għal perjodu għal kull proċess li jirdoppja ma’ kull ripetizzjoni, sa limitu massimu. Ma jinkiteb ebda status tal-proxy; meta kull kandidat jitwarrab, l-għażla tibqa’ l-istess. Mixgħul b’mod awtomatiku; `false` jerġa’ jġib l-għażla sempliċi.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Għal fornituri li l-kwota tagħhom hija miġbura skont l-indirizz tal-egress, ikklassifika membru tal-pool li jaqsam l-indirizz tal-egress osservat ta' membru li ġie rrifjutat reċentement eżatt taħt il-membri b'saħħithom. Ordni biss, qatt eskluż. Jeħtieġ PROXY_SKIP_RECENTLY_FAILED, li jipproduċi s-sinjal ta' rifjut li jaqra. Mitfi b'mod awtomatiku: l-ordni tal-għażla hija eżattament ir-rotazzjoni sempliċi.", "featureFlagProxyPoolEgressObservationDescription": "Uri, taħt pool tal-proxy fid-dashboard, kemm-il IP ta’ ħruġ osservat serva lill-membri tiegħu matul l-aħħar 24 siegħa, kemm-il konnessjoni użathom u l-ogħla għadd osservat wara IP wieħed. Għall-qari biss, ikkalkulat mil-log tal-proxy, u qatt ma jintuża għar-routing. Mitfi b’mod awtomatiku: l-editur tal-pool ma jinbidilx u r-rotta tal-osservazzjoni twieġeb null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Fl-iskennjar tas-saħħa tal-proxy, ħalli sonda li l-mira tkun irrifjutat (401/403/429: il-proxy għadda t-talba, iżda d-destinazzjoni rrifjutat dan l-IP ta’ ħruġ) tirrisettja s-sensiela ta’ fallimenti konsekuttivi tal-proxy, bħal sonda moqdija. Mitfi b’mod awtomatiku: rifjut jibqa’ newtrali u jżomm is-sensiela. 5xx jibqa’ inkonklussiv fiż-żewġ każijiet, u rifjut qatt ma jneħħi, jiddiżattiva jew jerġa’ jattiva proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ħalli t-tindif awtomatiku jħassar il-kompiti terminali (ikkompletati/falluti/ikkanċellati/skaduti) tal-Batch API li jkunu eqdem minn OMNIROUTE_BATCH_RETENTION_DAYS, flimkien mal-punti ta’ kontroll tagħhom għal kull linja, u jneħħi l-kontenut BLOB tal-fajls imtellgħin li jkunu qabżu l-expires_at tagħhom. Diżattivat b’mod awtomatiku: kull installazzjoni eżistenti żżomm din id-data eżattament bħal qabel sakemm operatur jagħżel li jattivah. Ir-rotta DELETE /api/v1/batches/delete-completed attivata mill-operatur ma tiġix affettwata fiż-żewġ każijiet — dan huwa kuntratt separat u inkundizzjonat tal-API pubblika.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Il-URLs tal-konnessjoni tiegħek mal-IA", "apiManager": "Ċwievet tal-API", "apiManagerSubtitle": "Immaniġġja ċ-ċwievet tal-API u l-aċċess", + "modelCatalog": "Mudelli u Combos", + "modelCatalogSubtitle": "Esplora mudelli u combos fost il-fornituri", "embeddedServices": "Servizzi Inkorporati", "embeddedServicesSubtitle": "Servizzi lokali fakultattivi", "logs": "Reġistri", diff --git a/src/i18n/messages/my.json b/src/i18n/messages/my.json index 6680226a184f..0359ac0101a4 100644 --- a/src/i18n/messages/my.json +++ b/src/i18n/messages/my.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "provider dispatch (#9654) အတွက် tenant တစ်ခုချင်းစီအလိုက် အလိုက်သင့်ပြောင်းလဲနိုင်သော virtual admission lanes များကို ဖွင့်ပါ။ tenant တစ်ခု၏ ရုတ်တရက်မြင့်တက်လာသော အသုံးပြုမှုကြောင့် အခြား tenant တွင် 503 ဖြစ်ပေါ်တော့မည်မဟုတ်ပါ။ OMNIROUTE_CHAT_VIRTUAL_LANES env var သည် ဤ dashboard override ထက် ဦးစားပေးသက်ရောက်ပြီး ပြောင်းလဲမှုများသည် server ပြန်လည်စတင်ချိန်တွင် အသက်ဝင်မည်ဖြစ်သည်။", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ဒက်ရှ်ဘုတ် ဝန်ဆောင်မှုပေးသူ စာမျက်နှာများတွင် ဝန်ဆောင်မှုပေးသူက အသိအမှတ်ပြုသည့် အချက်ပြမှုများအပေါ် အခြေခံ၍သာ Free တံဆိပ်ကို ပြပါ — မှတ်တမ်းတင်ထားသော အခမဲ့အဆင့် မရှိသည့် မှတ်ပုံတင်ထားသော ဝန်ဆောင်မှုပေးသူများအတွက် ဖော်ပြအမည်အခြေပြု ခန့်မှန်းနည်း၊ boolean မဟုတ်သော free အကွက်များနှင့် :free နောက်ဆက်များကို မသုံးတော့ပါ။ ပိတ်ထားပါက ယခင်တံဆိပ်စည်းမျဉ်းကို ဆက်သုံးပါမည်။", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pool များနှင့် opencode ၏ အကောင့်တစ်ခုချင်းစီအလိုက် အလှည့်ကျရွေးချယ်မှုသည် ပျက်ကွက်ခဲ့သည့် proxy (TCP probe ကို ငြင်းပယ်ခဲ့ခြင်း သို့မဟုတ် ၎င်းမှတစ်ဆင့် 429 တုံ့ပြန်မှုရရှိခြင်း) ကို process တစ်ခုချင်းစီအလိုက် သတ်မှတ်ကာလအတွင်း ပြန်လည်အသုံးမပြုတော့ပါ။ ထပ်မံဖြစ်ပွားတိုင်း ထိုကာလသည် နှစ်ဆတိုးလာပြီး သတ်မှတ်အများဆုံးပမာဏအထိသာ တိုးပါမည်။ Proxy အခြေအနေကို မှတ်တမ်းတင်မည်မဟုတ်ပါ။ Candidate အားလုံးကို ဘေးဖယ်ထားရသည့်အခါ ရွေးချယ်မှုသည် မပြောင်းလဲပါ။ မူလအားဖြင့် ဖွင့်ထားသည်။ `false` သည် ရိုးရိုးရွေးချယ်မှုကို ပြန်လည်ထားရှိပေးသည်။", + "featureFlagProxyPoolSharedEgressOrderDescription": "Egress address ဖြင့် quota သတ်မှတ်ထားသော provider များအတွက် မကြာသေးမီက ငြင်းပယ်ခံခဲ့ရသော member ၏ တွေ့ရှိရသည့် egress address အား မျှဝေသုံးစွဲထားသော pool member ကို ကောင်းမွန်သည့် member များ၏နောက်တွင်သာ အဆင့်သတ်မှတ်ပါ။ အစီအစဉ်အတွက်သာဖြစ်ပြီး လုံးဝဖယ်ထုတ်မည်မဟုတ်ပါ။ ၎င်းဖတ်ရှုသည့် ငြင်းပယ်မှုအချက်ပြမှုကို ထုတ်ပေးသော PROXY_SKIP_RECENTLY_FAILED လိုအပ်ပါသည်။ ပုံသေအားဖြင့် ပိတ်ထားသည်- ရွေးချယ်မှုအစီအစဉ်သည် သာမန်အလှည့်ကျစနစ် အတိအကျအတိုင်း ဖြစ်သည်။", "featureFlagProxyPoolEgressObservationDescription": "Dashboard ရှိ proxy pool တစ်ခု၏အောက်တွင် လွန်ခဲ့သော 24 နာရီအတွင်း ၎င်း၏ member များအတွက် အသုံးပြုခဲ့သည့် စောင့်ကြည့်တွေ့ရှိထားသော egress IP အရေအတွက်၊ ထို IP များကို အသုံးပြုခဲ့သည့် connection အရေအတွက်နှင့် IP တစ်ခုတည်း၏နောက်ကွယ်တွင် အများဆုံးတွေ့ရှိရသည့် အရေအတွက်တို့ကို ပြသပါ။ ၎င်းသည် ဖတ်ရှုရန်သာဖြစ်ပြီး proxy log မှ တွက်ချက်ထားကာ routing အတွက် မည်သည့်အခါမျှ အသုံးမပြုပါ။ မူလအားဖြင့် ပိတ်ထားသည်။ Pool editor သည် မပြောင်းလဲဘဲ observation route က null ကို ပြန်ပေးသည်။", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy health sweep တွင် target က ငြင်းပယ်ခဲ့သော probe (401/403/429—proxy က လက်ဆင့်ကမ်းပေးခဲ့သော်လည်း destination က ဤ egress IP ကို ငြင်းပယ်ခြင်း) ကို အောင်မြင်စွာ ဆောင်ရွက်ခဲ့သည့် probe ကဲ့သို့ proxy ၏ ဆက်တိုက်ပျက်ကွက်မှုအရေအတွက်ကို ပြန်လည်သတ်မှတ်ခွင့်ပြုပါ။ မူလအားဖြင့် ပိတ်ထားသည်။ ငြင်းပယ်မှုသည် သက်ရောက်မှုမရှိဘဲ streak ကို ဆက်လက်ထိန်းထားသည်။ မည်သည့်အခြေအနေတွင်မဆို 5xx သည် အတည်မပြုနိုင်သည့်အခြေအနေအဖြစ် ဆက်ရှိနေပြီး ငြင်းပယ်မှုတစ်ခုကြောင့် proxy ကို ဖယ်ရှားခြင်း၊ ပိတ်ခြင်း သို့မဟုတ် ပြန်လည်အသက်သွင်းခြင်း မည်သည့်အခါမျှ မပြုလုပ်ပါ။", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "အလိုအလျောက် ရှင်းလင်းရေးလုပ်ငန်းစဉ်ကို OMNIROUTE_BATCH_RETENTION_DAYS ထက် ပိုဟောင်းသော အဆုံးသတ်အခြေအနေ (ပြီးဆုံး/မအောင်မြင်/ပယ်ဖျက်/သက်တမ်းကုန်) ရှိသည့် Batch API အလုပ်များနှင့် ၎င်းတို့၏ စာကြောင်းတစ်ကြောင်းချင်းဆိုင်ရာ checkpoint များကို ဖျက်ခွင့်ပြုပြီး၊ ၎င်းတို့၏ ကိုယ်ပိုင် expires_at ကျော်လွန်သွားသော အပ်လုဒ်ဖိုင်များ၏ BLOB အကြောင်းအရာကိုလည်း ရှင်းလင်းပါ။ ပုံသေအားဖြင့် ပိတ်ထားသည်။ အော်ပရေတာက ဖွင့်ရန် ရွေးချယ်သည့်အချိန်အထိ လက်ရှိထည့်သွင်းမှုတိုင်းသည် ဤဒေတာကို ယခင်အတိုင်း အတိအကျ ဆက်လက်ထိန်းသိမ်းထားမည်။ မည်သို့ဖွင့်ပိတ်ထားသည်ဖြစ်စေ အော်ပရေတာက စတင်လုပ်ဆောင်သည့် DELETE /api/v1/batches/delete-completed route အပေါ် သက်ရောက်မှုမရှိပါ — ၎င်းသည် သီးခြားဖြစ်ပြီး ခြွင်းချက်မရှိသော အများသုံး API စာချုပ်ဖြစ်သည်။", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "သင့် AI ချိတ်ဆက်မှု URL များ", "apiManager": "API သော့များ", "apiManagerSubtitle": "API သော့များနှင့် အသုံးပြုခွင့်ကို စီမံရန်", + "modelCatalog": "မော်ဒယ်များနှင့် Combos", + "modelCatalogSubtitle": "Provider များတစ်လျှောက် မော်ဒယ်များနှင့် combos များကို ရှာဖွေကြည့်ရှုပါ", "embeddedServices": "ပေါင်းစပ်ထည့်သွင်းထားသော ဝန်ဆောင်မှုများ", "embeddedServicesSubtitle": "ရွေးချယ်အသုံးပြုနိုင်သော စက်တွင်းဝန်ဆောင်မှုများ", "logs": "မှတ်တမ်းများ", diff --git a/src/i18n/messages/ne.json b/src/i18n/messages/ne.json index 12313627248a..b2a4923765c9 100644 --- a/src/i18n/messages/ne.json +++ b/src/i18n/messages/ne.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदायक डिस्प्याच (#9654) का लागि प्रत्येक टेनेन्टअनुसार अनुकूल हुने भर्चुअल एडमिसन लेनहरू सक्षम गर्नुहोस्: अब एउटा टेनेन्टको अचानक बढेको ट्राफिकले अर्कोलाई 503 गराउँदैन। OMNIROUTE_CHAT_VIRTUAL_LANES env var ले यस ड्यासबोर्ड ओभरराइडभन्दा प्राथमिकता पाउँछ; परिवर्तनहरू सर्भर पुनः सुरु भएपछि लागू हुन्छन्।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ड्यासबोर्डका प्रदायक पृष्ठहरू: प्रदायकले स्वीकार गर्ने सङ्केतहरूमा मात्र निःशुल्क ब्याज देखाउनुहोस् — दस्तावेजीकृत निःशुल्क तह नभएका दर्ता गरिएका प्रदायकहरूका प्रदर्शन-नाममा आधारित अनुमान, गैर-बुलियन निःशुल्क फिल्डहरू र :free प्रत्ययहरू हटाउँछ। बन्द गर्दा ऐतिहासिक ब्याज नियम कायम रहन्छ।", "featureFlagProxySkipRecentlyFailedDescription": "प्रोक्सी पूलहरू र opencode को प्रति-खाता रोटेसनले भर्खरै असफल भएको प्रोक्सी (TCP प्रोब अस्वीकार भएको वा त्यसमार्फत 429 प्राप्त भएको) लाई प्रत्येक पटक दोब्बर हुँदै अधिकतम सीमासम्म पुग्ने प्रति-प्रक्रिया अवधिका लागि पुनः प्रयोग गर्न रोक्छ। कुनै प्रोक्सी स्थिति लेखिँदैन; सबै उम्मेदवार अलग राखिएमा छनोट अपरिवर्तित रहन्छ। पूर्वनिर्धारित रूपमा सक्रिय; `false` ले साधारण छनोट पुनर्स्थापित गर्छ।", + "featureFlagProxyPoolSharedEgressOrderDescription": "egress ठेगाना अनुसार कोटा समूहबद्ध गरिएका प्रदायकहरूका लागि, भर्खरै अस्वीकार गरिएको सदस्यको देखिएको egress ठेगाना साझा गर्ने पूल सदस्यलाई स्वस्थ सदस्यहरूभन्दा ठीक तल क्रमबद्ध गर्नुहोस्। क्रम मात्र, कहिल्यै हटाइँदैन। PROXY_SKIP_RECENTLY_FAILED आवश्यक पर्दछ, जसले यसले पढ्ने अस्वीकृति संकेत उत्पादन गर्छ। पूर्वनिर्धारित रूपमा बन्द: चयन क्रम ठ्याक्कै सामान्य रोटेसन हो।", "featureFlagProxyPoolEgressObservationDescription": "ड्यासबोर्डमा प्रोक्सी पूलअन्तर्गत, पछिल्लो २४ घण्टामा त्यसका सदस्यहरूलाई सेवा दिने कति वटा अवलोकित इग्रेस IP थिए, कति जडानले तिनलाई प्रयोग गरे र एउटै IP पछाडि सबैभन्दा धेरै कति सदस्य देखिए भन्ने देखाउनुहोस्। पढ्नका लागि मात्र, प्रोक्सी लगबाट गणना गरिएको र राउटिङका लागि कहिल्यै प्रयोग नगरिने। पूर्वनिर्धारित रूपमा बन्द: पूल सम्पादक अपरिवर्तित रहन्छ र अवलोकन रुटले null फर्काउँछ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "प्रोक्सी स्वास्थ्य स्वीपमा, लक्ष्यले अस्वीकार गरेको प्रोब (401/403/429: प्रोक्सीले रिले गर्यो, गन्तव्यले यो इग्रेस IP अस्वीकार गर्यो) लाई सेवा दिइएको प्रोबजस्तै प्रोक्सीको लगातार-असफलता क्रम रिसेट गर्न दिनुहोस्। पूर्वनिर्धारित रूपमा बन्द: अस्वीकृति तटस्थ रहन्छ र क्रम कायम राख्छ। दुवै अवस्थामा 5xx अनिर्णायक नै रहन्छ, र अस्वीकृतिले प्रोक्सीलाई कहिल्यै हटाउँदैन, निष्क्रिय पार्दैन वा पुनः सक्रिय गर्दैन।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वचालित सफाइ प्रक्रियालाई OMNIROUTE_BATCH_RETENTION_DAYS भन्दा पुराना अन्तिम अवस्थामा रहेका (पूरा भएका/असफल/रद्द गरिएका/म्याद सकिएका) Batch API कार्यहरू तिनका प्रति-पङ्क्ति चेकपोइन्टसहित मेटाउन र आफ्नै expires_at नाघेका अपलोड गरिएका फाइलहरूको BLOB सामग्री खाली गर्न दिनुहोस्। पूर्वनिर्धारित रूपमा बन्द: अपरेटरले यसलाई सक्रिय नगरेसम्म हरेक विद्यमान इन्स्टलेसनले यो डेटा पहिले जस्तै राख्छ। अपरेटरद्वारा ट्रिगर गरिने DELETE /api/v1/batches/delete-completed रुटमा कुनै पनि अवस्थामा असर पर्दैन — यो छुट्टै, सर्तरहित सार्वजनिक API सम्झौता हो।", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "तपाईंका AI जडान URL हरू", "apiManager": "API कुञ्जीहरू", "apiManagerSubtitle": "API कुञ्जीहरू र पहुँच व्यवस्थापन गर्नुहोस्", + "modelCatalog": "मोडेल र कम्बोहरू", + "modelCatalogSubtitle": "विभिन्न प्रदायकहरूका मोडेल र कम्बोहरू ब्राउज गर्नुहोस्", "embeddedServices": "एम्बेडेड सेवाहरू", "embeddedServicesSubtitle": "वैकल्पिक स्थानीय सेवाहरू", "logs": "लगहरू", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 991093c56656..2535d77e3642 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Schakel adaptieve virtuele toegangsbanen per tenant in voor provider-dispatch (#9654): een piek van de ene tenant geeft de andere niet langer een 503. De omgevingsvariabele OMNIROUTE_CHAT_VIRTUAL_LANES wint het van deze dashboard-instelling; wijzigingen gaan in bij een serverherstart.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Providerpagina's in het dashboard: toon de badge Gratis alleen bij signalen die de provider ondersteunt — de heuristiek voor weergavenamen, niet-booleaanse gratisvelden en :free-achtervoegsels bij geregistreerde providers zonder een gedocumenteerde gratis laag worden niet meer gebruikt. Uit behoudt de historische badgeregel.", "featureFlagProxySkipRecentlyFailedDescription": "Proxypools en de rotatie per account van opencode zorgen ervoor dat een proxy die zojuist is mislukt (geweigerde TCP-probe of een 429 die via de proxy is ontvangen) gedurende een periode per proces niet opnieuw wordt aangeboden. Deze periode verdubbelt bij elke herhaling, tot een maximum. Er wordt geen proxystatus opgeslagen; wanneer elke kandidaat terzijde is geschoven, blijft de keuze ongewijzigd. Standaard ingeschakeld; `false` herstelt de gewone selectie.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Voor providers waarvan het quotum is gegroepeerd per egress-adres: rangschik een pool-lid dat het waargenomen egress-adres deelt met een recent geweigerd lid net onder gezonde leden. Alleen volgorde, nooit uitgesloten. Vereist PROXY_SKIP_RECENTLY_FAILED, wat het weigeringssignaal produceert dat het uitleest. Standaard uitgeschakeld: selectievolgorde is exact de standaardrotatie.", "featureFlagProxyPoolEgressObservationDescription": "Toon onder een proxypool in het dashboard hoeveel waargenomen uitgaande IP-adressen de leden ervan in de afgelopen 24 uur hebben gebruikt, hoeveel verbindingen daarvan gebruikmaakten en hoeveel verbindingen maximaal achter één IP zijn waargenomen. Alleen-lezen, berekend op basis van het proxylogboek en nooit gebruikt voor routering. Standaard uitgeschakeld: de pooleditor blijft ongewijzigd en de observatieroute antwoordt met null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Laat bij de proxygezondheidscontrole een probe die door het doel is geweigerd (401/403/429: de proxy heeft doorgestuurd, maar de bestemming heeft dit uitgaande IP-adres geweigerd) de reeks opeenvolgende fouten van de proxy resetten, net als een geslaagde probe. Standaard uitgeschakeld: een weigering blijft neutraal en behoudt de reeks. Een 5xx blijft in beide gevallen onbeslist, en een weigering verwijdert, deactiveert of heractiveert een proxy nooit.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Laat de automatische opschoonactie definitieve (voltooide/mislukte/geannuleerde/verlopen) Batch API-taken verwijderen die ouder zijn dan OMNIROUTE_BATCH_RETENTION_DAYS, samen met hun controlepunten per regel, en laat de BLOB-inhoud wissen van geüploade bestanden waarvan de eigen expires_at is verstreken. Standaard uitgeschakeld: elke bestaande installatie bewaart deze gegevens precies zoals voorheen, totdat een beheerder dit inschakelt. De door de beheerder geactiveerde route DELETE /api/v1/batches/delete-completed wordt in beide gevallen niet beïnvloed; dit is een afzonderlijk, onvoorwaardelijk openbaar API-contract.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Uw AI-verbindings-URL's", "apiManager": "API-beheerder", "apiManagerSubtitle": "Beheer API-sleutels en toegang", + "modelCatalog": "Modellen & combo's", + "modelCatalogSubtitle": "Blader door modellen en combo's van verschillende providers", "embeddedServices": "Ingebedde Diensten", "embeddedServicesSubtitle": "Beheer lokale proxydiensten", "logs": "Logboeken", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index 85f4e7838b38..8ddaafcfb757 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktiver adaptive virtuelle tilgangsfelt per tenant for leverandørdistribusjon (#9654): et utbrudd fra én tenant gir ikke lenger en annen 503. Miljøvariabelen OMNIROUTE_CHAT_VIRTUAL_LANES overstyrer denne innstillingen i dashbordet; endringer trer i kraft ved omstart av serveren.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leverandørsider i kontrollpanelet: Vis Gratis-merket bare basert på signaler som leverandøren respekterer — bruker ikke lenger heuristikken for visningsnavn, ikke-boolske gratisfelt eller :free-suffikser for registrerte leverandører uten et dokumentert gratisnivå. Når dette er slått av, brukes den tidligere merkeregelen.", "featureFlagProxySkipRecentlyFailedDescription": "Proxygrupper og rotasjonen per konto for opencode slutter midlertidig å bruke en proxy som nettopp sviktet (avvist TCP-sonde eller en 429 mottatt gjennom den), i en prosesspesifikk periode som dobles for hver gjentakelse, opptil en øvre grense. Ingen proxystatus lagres. Hvis alle kandidater settes til side, forblir valget uendret. På som standard; `false` gjenoppretter vanlig valg.", + "featureFlagProxyPoolSharedEgressOrderDescription": "For leverandører der kvoten er inndelt etter egress-adresse, ranger et pool-medlem som deler et nylig avvist medlems observerte egress-adresse like under friske medlemmer. Kun rekkefølge, aldri ekskludert. Krever PROXY_SKIP_RECENTLY_FAILED, som produserer avvisningssignalet den leser. Av som standard: utvalgsrekkefølgen er nøyaktig den vanlige rotasjonen.", "featureFlagProxyPoolEgressObservationDescription": "Vis under en proxygruppe i kontrollpanelet hvor mange observerte utgående IP-adresser som betjente medlemmene i løpet av de siste 24 timene, hvor mange tilkoblinger som brukte dem, og det høyeste antallet som ble observert bak én IP-adresse. Skrivebeskyttet, beregnet fra proxyloggen og aldri brukt til ruting. Av som standard: Redigeringen av proxygruppen er uendret, og observasjonsruten returnerer null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "La en sonde som målet avviste (401/403/429: proxyen videresendte forespørselen, men destinasjonen avviste denne utgående IP-adressen), nullstille proxyens rekke av påfølgende feil under helsesjekken av proxyer, på samme måte som en besvart sonde. Av som standard: En avvisning forblir nøytral og beholder rekken. En 5xx forblir ikke-konkluderende i begge tilfeller, og en avvisning fjerner, deaktiverer eller reaktiverer aldri en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "La den automatiske oppryddingen slette avsluttede (fullførte/mislykkede/avbrutte/utløpte) Batch API-jobber som er eldre enn OMNIROUTE_BATCH_RETENTION_DAYS, sammen med kontrollpunktene deres per linje, og tømme BLOB-innholdet i opplastede filer etter deres respektive expires_at. Av som standard: Alle eksisterende installasjoner beholder disse dataene nøyaktig som før frem til en operatør aktiverer funksjonen. Den operatørutløste ruten DELETE /api/v1/batches/delete-completed påvirkes uansett ikke – den er en separat, ubetinget offentlig API-kontrakt.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Dine AI-tilkoblings-URLer", "apiManager": "API-behandler", "apiManagerSubtitle": "Administrer API-nøkler og tilgang", + "modelCatalog": "Modeller og kombinasjoner", + "modelCatalogSubtitle": "Bla gjennom modeller og kombinasjoner på tvers av leverandører", "embeddedServices": "Innebygde tjenester", "embeddedServicesSubtitle": "Administrer lokale proxytjenester", "logs": "Logger", diff --git a/src/i18n/messages/or.json b/src/i18n/messages/or.json index 27d6d3646446..e9f6e6dc26ef 100644 --- a/src/i18n/messages/or.json +++ b/src/i18n/messages/or.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ପ୍ରଦାତା ଡିସ୍ପାଚ୍ (#9654) ପାଇଁ ପ୍ରତି-ଟେନାଣ୍ଟ ଅନୁକୂଳନଶୀଳ ଭର୍ଚୁଆଲ୍ ଆଡମିଶନ୍ ଲେନ୍ଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ: ଗୋଟିଏ ଟେନାଣ୍ଟର ହଠାତ୍ ଟ୍ରାଫିକ୍ ବୃଦ୍ଧି ଆଉ ଅନ୍ୟ ଟେନାଣ୍ଟ ପାଇଁ 503 ତ୍ରୁଟି ସୃଷ୍ଟି କରିବ ନାହିଁ। OMNIROUTE_CHAT_VIRTUAL_LANES env var ଏହି ଡ୍ୟାସ୍ବୋର୍ଡ ଓଭର୍ରାଇଡ୍ଠାରୁ ପ୍ରାଥମିକତା ପାଏ; ସର୍ଭର୍ ପୁନଃଚାଳନ ପରେ ପରିବର୍ତ୍ତନଗୁଡ଼ିକ କାର୍ଯ୍ୟକାରୀ ହୁଏ।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ଡ୍ୟାଶବୋର୍ଡ ପ୍ରଦାନକାରୀ ପୃଷ୍ଠାଗୁଡ଼ିକ: କେବଳ ପ୍ରଦାନକାରୀ ସ୍ୱୀକୃତି ଦେଉଥିବା ସଙ୍କେତଗୁଡ଼ିକ ଆଧାରରେ ମାଗଣା ବ୍ୟାଜ୍ ଦେଖାନ୍ତୁ — ଲିପିବଦ୍ଧ ମାଗଣା ସ୍ତର ନଥିବା ପଞ୍ଜୀକୃତ ପ୍ରଦାନକାରୀଙ୍କ ପାଇଁ ପ୍ରଦର୍ଶନ-ନାମ ଅନୁମାନ, ଅଣ-ବୁଲିୟନ୍ ମାଗଣା ଫିଲ୍ଡ ଏବଂ :free ପ୍ରତ୍ୟୟଗୁଡ଼ିକୁ ବାଦ ଦିଏ। ବନ୍ଦ ରଖିଲେ ପୂର୍ବରୁ ପ୍ରଚଳିତ ବ୍ୟାଜ୍ ନିୟମ ବଜାୟ ରହେ।", "featureFlagProxySkipRecentlyFailedDescription": "ପ୍ରକ୍ସି ପୁଲ୍ ଏବଂ opencodeର ପ୍ରତି-ଆକାଉଣ୍ଟ ରୋଟେସନ୍, ସଦ୍ୟ ବିଫଳ ହୋଇଥିବା ପ୍ରକ୍ସିକୁ (ପ୍ରତ୍ୟାଖ୍ୟାନ ହୋଇଥିବା TCP ପ୍ରୋବ୍ କିମ୍ବା ତାହା ମାଧ୍ୟମରେ ପ୍ରାପ୍ତ 429) ପ୍ରତ୍ୟେକ ପୁନରାବୃତ୍ତିରେ ଦ୍ୱିଗୁଣିତ ହେଉଥିବା, ଏକ ସର୍ବାଧିକ ସୀମା ପର୍ଯ୍ୟନ୍ତ ପ୍ରତି-ପ୍ରକ୍ରିୟା ଅବଧି ପାଇଁ ପୁଣି ସେବାରେ ବ୍ୟବହାର କରିବା ବନ୍ଦ କରେ। କୌଣସି ପ୍ରକ୍ସି ସ୍ଥିତି ଲେଖାଯାଏ ନାହିଁ; ପ୍ରତ୍ୟେକ ପ୍ରାର୍ଥୀକୁ ପାଖକୁ ରଖାଗଲେ ଚୟନ ଅପରିବର୍ତ୍ତିତ ରହେ। ଡିଫଲ୍ଟ ଭାବେ ଚାଲୁ; `false` ସାଧାରଣ ଚୟନକୁ ପୁନଃସ୍ଥାପନ କରେ।", + "featureFlagProxyPoolSharedEgressOrderDescription": "ଯେଉଁ ପ୍ରୋଭାଇଡର୍‌ମାନଙ୍କର କୋଟା egress address ଦ୍ୱାରା ବକେଟ୍ ହୋଇଛି, ସେମାନଙ୍କ ପାଇଁ ନିକଟରେ ପ୍ରତ୍ୟାଖ୍ୟାତ ହୋଇଥିବା ସଦସ୍ୟଙ୍କ ନିରୀକ୍ଷିତ egress address ସେୟାର କରୁଥିବା ପୁଲ୍ ସଦସ୍ୟଙ୍କୁ ସୁସ୍ଥ ସଦସ୍ୟମାନଙ୍କ ଠିକ୍ ତଳେ ସ୍ଥାନିତ କରନ୍ତୁ। କେବଳ କ୍ରମ, କେବେ ବି ବାଦ ଦିଆଯାଏ ନାହିଁ। PROXY_SKIP_RECENTLY_FAILED ଆବଶ୍ୟକ, ଯାହା ଏହା ପଢ଼ୁଥିବା ପ୍ରତ୍ୟାଖ୍ୟାନ ସିଗନାଲ୍ ଉତ୍ପନ୍ନ କରେ। ଡିଫଲ୍ଟ ଭାବରେ ବନ୍ଦ: ଚୟନ କ୍ରମ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ସାଧାରଣ ଘୂର୍ଣ୍ଣନ ଅଟେ।", "featureFlagProxyPoolEgressObservationDescription": "ଡ୍ୟାସବୋର୍ଡରେ ଗୋଟିଏ ପ୍ରକ୍ସି ପୁଲ୍ ଅଧୀନରେ, ଗତ 24 ଘଣ୍ଟାରେ କେତୋଟି ପର୍ଯ୍ୟବେକ୍ଷିତ ଏଗ୍ରେସ୍ IP ଏହାର ସଦସ୍ୟମାନଙ୍କୁ ସେବା ଦେଇଥିଲା, କେତୋଟି ସଂଯୋଗ ସେଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିଥିଲା ଏବଂ ଗୋଟିଏ IP ପଛରେ ସର୍ବାଧିକ କେତୋଟି ଦେଖାଯାଇଥିଲା, ତାହା ଦେଖାନ୍ତୁ। କେବଳ ପଠନୀୟ, ପ୍ରକ୍ସି ଲଗ୍ରୁ ଗଣନା କରାଯାଏ, ରାଉଟିଂ ପାଇଁ କେବେ ବ୍ୟବହୃତ ହୁଏ ନାହିଁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: ପୁଲ୍ ଏଡିଟର୍ ଅପରିବର୍ତ୍ତିତ ରହେ ଏବଂ ପର୍ଯ୍ୟବେକ୍ଷଣ ରୁଟ୍ null ଉତ୍ତର ଦିଏ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "ପ୍ରକ୍ସି ସ୍ୱାସ୍ଥ୍ୟ ଯାଞ୍ଚରେ, ଲକ୍ଷ୍ୟ ଦ୍ୱାରା ପ୍ରତ୍ୟାଖ୍ୟାନ ହୋଇଥିବା ପ୍ରୋବ୍କୁ (401/403/429: ପ୍ରକ୍ସି ରିଲେ କରିଥିଲା, ଗନ୍ତବ୍ୟସ୍ଥଳ ଏହି ଏଗ୍ରେସ୍ IPକୁ ପ୍ରତ୍ୟାଖ୍ୟାନ କରିଥିଲା) ଏକ ସେବା ପ୍ରଦାନ କରାଯାଇଥିବା ପ୍ରୋବ୍ ପରି ପ୍ରକ୍ସିର କ୍ରମାଗତ ବିଫଳତା ଧାରାକୁ ରିସେଟ୍ କରିବାକୁ ଦିଅନ୍ତୁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: ଏକ ପ୍ରତ୍ୟାଖ୍ୟାନ ନିରପେକ୍ଷ ରହେ ଏବଂ ଧାରାକୁ ଅପରିବର୍ତ୍ତିତ ରଖେ। ଉଭୟ କ୍ଷେତ୍ରରେ 5xx ଅନିର୍ଣ୍ଣାୟକ ରହେ, ଏବଂ ଏକ ପ୍ରତ୍ୟାଖ୍ୟାନ କେବେ ମଧ୍ୟ ପ୍ରକ୍ସିକୁ ହଟାଏ, ଅକ୍ଷମ କରେ କିମ୍ବା ପୁନଃସକ୍ରିୟ କରେ ନାହିଁ।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ସ୍ୱୟଂଚାଳିତ କ୍ଲିନଅପ୍ ସ୍ୱିପ୍କୁ OMNIROUTE_BATCH_RETENTION_DAYS ଠାରୁ ପୁରୁଣା ଟର୍ମିନାଲ୍ (ସମ୍ପୂର୍ଣ୍ଣ/ବିଫଳ/ବାତିଲ୍/ମିଆଦ ଶେଷ) Batch API କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ସେମାନଙ୍କର ପ୍ରତି-ଧାଡ଼ି ଚେକ୍ପଏଣ୍ଟ ସହିତ ଡିଲିଟ୍ କରିବାକୁ ଏବଂ ଅପଲୋଡ୍ ହୋଇଥିବା ଫାଇଲ୍ଗୁଡ଼ିକର ନିଜସ୍ୱ expires_at ଅତିକ୍ରମ ହେବା ପରେ ସେମାନଙ୍କ BLOB ବିଷୟବସ୍ତୁ ସଫା କରିବାକୁ ଦିଅନ୍ତୁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: କୌଣସି ଅପରେଟର୍ ଏହାକୁ ସକ୍ରିୟ ନ କରିବା ପର୍ଯ୍ୟନ୍ତ ପ୍ରତ୍ୟେକ ବିଦ୍ୟମାନ ଇନ୍ଷ୍ଟଲେସନ୍ ଏହି ଡାଟାକୁ ପୂର୍ବପରି ଠିକ୍ ସେହିଭଳି ରଖିଥାଏ। ଅପରେଟର୍ ଦ୍ୱାରା ଟ୍ରିଗର୍ ହେଉଥିବା DELETE /api/v1/batches/delete-completed ରୁଟ୍ ଉଭୟ କ୍ଷେତ୍ରରେ ଅପ୍ରଭାବିତ ରହେ — ଏହା ଏକ ପୃଥକ, ସର୍ତ୍ତହୀନ ସାର୍ବଜନୀନ API ଚୁକ୍ତି।", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "ଆପଣଙ୍କ AI ସଂଯୋଗ URLs", "apiManager": "API କୀଗୁଡ଼ିକ", "apiManagerSubtitle": "API କୀ ଏବଂ ପ୍ରବେଶ ପରିଚାଳନା କରନ୍ତୁ", + "modelCatalog": "ମଡେଲ୍ ଏବଂ କମ୍ବୋ", + "modelCatalogSubtitle": "ପ୍ରୋଭାଇଡର୍‌ଗୁଡ଼ିକ ମଧ୍ୟରେ ମଡେଲ୍ ଏବଂ କମ୍ବୋ ବ୍ରାଉଜ୍ କରନ୍ତୁ", "embeddedServices": "ଅନ୍ତର୍ନିହିତ ସେବାଗୁଡ଼ିକ", "embeddedServicesSubtitle": "ଇଚ୍ଛାଧୀନ ସ୍ଥାନୀୟ ସେବାଗୁଡ଼ିକ", "logs": "ଲଗ୍ଗୁଡ଼ିକ", diff --git a/src/i18n/messages/pa.json b/src/i18n/messages/pa.json index a1db13c21cbf..b18bf4d06e13 100644 --- a/src/i18n/messages/pa.json +++ b/src/i18n/messages/pa.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ਪ੍ਰਦਾਤਾ ਡਿਸਪੈਚ (#9654) ਲਈ ਪ੍ਰਤੀ-ਟੈਨੈਂਟ ਅਨੁਕੂਲ ਵਰਚੁਅਲ ਐਡਮਿਸ਼ਨ ਲੇਨ ਸਮਰੱਥ ਕਰੋ: ਹੁਣ ਇੱਕ ਟੈਨੈਂਟ ਦਾ ਅਚਾਨਕ ਵਧਿਆ ਲੋਡ ਦੂਜੇ ਲਈ 503 ਪੈਦਾ ਨਹੀਂ ਕਰੇਗਾ। OMNIROUTE_CHAT_VIRTUAL_LANES env var ਨੂੰ ਇਸ ਡੈਸ਼ਬੋਰਡ ਓਵਰਰਾਈਡ ਉੱਤੇ ਤਰਜੀਹ ਮਿਲਦੀ ਹੈ; ਤਬਦੀਲੀਆਂ ਸਰਵਰ ਮੁੜ ਚਾਲੂ ਹੋਣ 'ਤੇ ਲਾਗੂ ਹੁੰਦੀਆਂ ਹਨ।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ਡੈਸ਼ਬੋਰਡ ਪ੍ਰਦਾਤਾ ਪੰਨੇ: ਮੁਫ਼ਤ ਬੈਜ ਸਿਰਫ਼ ਉਹਨਾਂ ਸੰਕੇਤਾਂ ਉੱਤੇ ਦਿਖਾਓ ਜਿਨ੍ਹਾਂ ਨੂੰ ਪ੍ਰਦਾਤਾ ਮੰਨਦਾ ਹੈ — ਇਹ ਡਿਸਪਲੇ-ਨਾਮ ਅਨੁਮਾਨ, ਗੈਰ-ਬੂਲੀਅਨ free ਫ਼ੀਲਡਾਂ ਅਤੇ ਬਿਨਾਂ ਦਸਤਾਵੇਜ਼ਬੱਧ ਮੁਫ਼ਤ ਟੀਅਰ ਵਾਲੇ ਰਜਿਸਟਰਡ ਪ੍ਰਦਾਤਾਵਾਂ ਉੱਤੇ :free ਪਿਛੇਤਰਾਂ ਨੂੰ ਹਟਾਉਂਦਾ ਹੈ। ਬੰਦ ਹੋਣ ਉੱਤੇ ਪੁਰਾਣਾ ਬੈਜ ਨਿਯਮ ਬਰਕਰਾਰ ਰਹਿੰਦਾ ਹੈ।", "featureFlagProxySkipRecentlyFailedDescription": "Proxy ਪੂਲ ਅਤੇ opencode ਦੀ ਪ੍ਰਤੀ-ਖਾਤਾ ਰੋਟੇਸ਼ਨ ਉਸ Proxy ਨੂੰ ਮੁੜ ਵਰਤਣਾ ਬੰਦ ਕਰ ਦਿੰਦੇ ਹਨ ਜੋ ਹੁਣੇ ਅਸਫਲ ਹੋਇਆ ਹੈ (TCP ਪ੍ਰੋਬ ਅਸਵੀਕਾਰ ਹੋਈ, ਜਾਂ ਇਸ ਰਾਹੀਂ 429 ਮਿਲਿਆ), ਇੱਕ ਪ੍ਰਤੀ-ਪ੍ਰਕਿਰਿਆ ਮਿਆਦ ਲਈ ਜੋ ਹਰ ਦੁਹਰਾਅ ਨਾਲ ਦੁੱਗਣੀ ਹੁੰਦੀ ਹੈ, ਇੱਕ ਅਧਿਕਤਮ ਹੱਦ ਤੱਕ। ਕੋਈ Proxy ਸਥਿਤੀ ਲਿਖੀ ਨਹੀਂ ਜਾਂਦੀ; ਹਰ ਉਮੀਦਵਾਰ ਨੂੰ ਪਾਸੇ ਰੱਖਣ ’ਤੇ ਚੋਣ ਬਦਲਦੀ ਨਹੀਂ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਚਾਲੂ; `false` ਸਧਾਰਨ ਚੋਣ ਨੂੰ ਬਹਾਲ ਕਰਦਾ ਹੈ।", + "featureFlagProxyPoolSharedEgressOrderDescription": "ਉਹਨਾਂ ਪ੍ਰੋਵਾਈਡਰਾਂ ਲਈ ਜਿਨ੍ਹਾਂ ਦਾ ਕੋਟਾ egress ਐਡਰੈੱਸ ਅਨੁਸਾਰ ਬਕੇਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਹਾਲ ਹੀ ਵਿੱਚ ਅਸਵੀਕਾਰ ਕੀਤੇ ਗਏ ਮੈਂਬਰ ਦਾ ਦੇਖਿਆ ਗਿਆ egress ਐਡਰੈੱਸ ਸਾਂਝਾ ਕਰਨ ਵਾਲੇ ਪੂਲ ਮੈਂਬਰ ਨੂੰ ਸਿਹਤਮੰਦ ਮੈਂਬਰਾਂ ਤੋਂ ਠੀਕ ਹੇਠਾਂ ਰੈਂਕ ਕਰੋ। ਸਿਰਫ਼ ਕ੍ਰਮ ਲਈ, ਕਦੇ ਬਾਹਰ ਨਹੀਂ ਕੱਢਿਆ ਜਾਂਦਾ। PROXY_SKIP_RECENTLY_FAILED ਦੀ ਲੋੜ ਹੈ, ਜੋ ਅਸਵੀਕਾਰ ਸਿਗਨਲ ਤਿਆਰ ਕਰਦਾ ਹੈ ਜਿਸਨੂੰ ਇਹ ਪੜ੍ਹਦਾ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਚੋਣ ਕ੍ਰਮ ਬਿਲਕੁਲ ਸਾਧਾਰਨ ਰੋਟੇਸ਼ਨ ਹੈ।", "featureFlagProxyPoolEgressObservationDescription": "ਡੈਸ਼ਬੋਰਡ ਵਿੱਚ ਕਿਸੇ Proxy ਪੂਲ ਹੇਠ ਦਿਖਾਓ ਕਿ ਪਿਛਲੇ 24 ਘੰਟਿਆਂ ਦੌਰਾਨ ਕਿੰਨੇ ਦੇਖੇ ਗਏ egress IPs ਨੇ ਇਸ ਦੇ ਮੈਂਬਰਾਂ ਨੂੰ ਸੇਵਾ ਦਿੱਤੀ, ਕਿੰਨੇ ਕਨੈਕਸ਼ਨਾਂ ਨੇ ਉਨ੍ਹਾਂ ਨੂੰ ਵਰਤਿਆ ਅਤੇ ਇੱਕ IP ਦੇ ਪਿੱਛੇ ਸਭ ਤੋਂ ਵੱਧ ਕਿੰਨੇ ਦੇਖੇ ਗਏ। ਕੇਵਲ ਪੜ੍ਹਨਯੋਗ, Proxy ਲੌਗ ਤੋਂ ਗਣਨਾ ਕੀਤੀ ਗਈ, ਰੂਟਿੰਗ ਲਈ ਕਦੇ ਨਹੀਂ ਵਰਤੀ ਜਾਂਦੀ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਪੂਲ ਸੰਪਾਦਕ ਬਦਲਦਾ ਨਹੀਂ ਹੈ ਅਤੇ ਨਿਰੀਖਣ ਰੂਟ null ਜਵਾਬ ਦਿੰਦਾ ਹੈ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ਸਿਹਤ ਜਾਂਚ ਵਿੱਚ, ਟਾਰਗੇਟ ਵੱਲੋਂ ਅਸਵੀਕਾਰ ਕੀਤੀ ਪ੍ਰੋਬ (401/403/429: Proxy ਨੇ ਅੱਗੇ ਭੇਜਿਆ, ਮੰਜ਼ਿਲ ਨੇ ਇਸ egress IP ਨੂੰ ਅਸਵੀਕਾਰ ਕੀਤਾ) ਨੂੰ, ਸਫਲਤਾਪੂਰਵਕ ਸੇਵਾ ਕੀਤੀ ਪ੍ਰੋਬ ਵਾਂਗ, Proxy ਦੀ ਲਗਾਤਾਰ ਅਸਫਲਤਾ ਲੜੀ ਰੀਸੈੱਟ ਕਰਨ ਦਿਓ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਅਸਵੀਕਾਰਤਾ ਨਿਰਪੱਖ ਰਹਿੰਦੀ ਹੈ ਅਤੇ ਲੜੀ ਨੂੰ ਕਾਇਮ ਰੱਖਦੀ ਹੈ। 5xx ਦੋਵਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਅਨਿਰਣਾਇਕ ਰਹਿੰਦਾ ਹੈ, ਅਤੇ ਅਸਵੀਕਾਰਤਾ ਕਦੇ ਵੀ ਕਿਸੇ Proxy ਨੂੰ ਹਟਾਉਂਦੀ, ਅਯੋਗ ਜਾਂ ਮੁੜ ਸਰਗਰਮ ਨਹੀਂ ਕਰਦੀ।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ਆਟੋਮੈਟਿਕ ਕਲੀਨਅੱਪ ਸਵੀਪ ਨੂੰ OMNIROUTE_BATCH_RETENTION_DAYS ਤੋਂ ਪੁਰਾਣੀਆਂ ਟਰਮੀਨਲ (ਪੂਰੀਆਂ/ਅਸਫਲ/ਰੱਦ/ਮਿਆਦ ਪੁੱਗੀਆਂ) Batch API ਜੌਬਾਂ ਨੂੰ, ਉਨ੍ਹਾਂ ਦੇ ਪ੍ਰਤੀ-ਲਾਈਨ ਚੈਕਪੌਇੰਟਾਂ ਸਮੇਤ, ਮਿਟਾਉਣ ਦਿਓ ਅਤੇ ਆਪਣੀ expires_at ਮਿਆਦ ਲੰਘਾ ਚੁੱਕੀਆਂ ਅੱਪਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਦੀ BLOB ਸਮੱਗਰੀ ਸਾਫ਼ ਕਰੋ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਜਦੋਂ ਤੱਕ ਕੋਈ ਓਪਰੇਟਰ ਇਸਨੂੰ ਚਾਲੂ ਕਰਨ ਦੀ ਚੋਣ ਨਹੀਂ ਕਰਦਾ, ਹਰ ਮੌਜੂਦਾ ਇੰਸਟਾਲੇਸ਼ਨ ਇਹ ਡਾਟਾ ਬਿਲਕੁਲ ਪਹਿਲਾਂ ਵਾਂਗ ਹੀ ਰੱਖਦੀ ਹੈ। ਓਪਰੇਟਰ ਵੱਲੋਂ ਸ਼ੁਰੂ ਕੀਤਾ ਗਿਆ DELETE /api/v1/batches/delete-completed ਰੂਟ ਦੋਵਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਪ੍ਰਭਾਵਿਤ ਨਹੀਂ ਹੁੰਦਾ — ਇਹ ਇੱਕ ਵੱਖਰਾ, ਬਿਨਾਂ ਸ਼ਰਤ ਵਾਲਾ ਜਨਤਕ API ਇਕਰਾਰਨਾਮਾ ਹੈ।", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "ਤੁਹਾਡੇ AI ਕਨੈਕਸ਼ਨ URL", "apiManager": "API ਕੁੰਜੀਆਂ", "apiManagerSubtitle": "API ਕੁੰਜੀਆਂ ਅਤੇ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "modelCatalog": "ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼", + "modelCatalogSubtitle": "ਸਾਰੇ ਪ੍ਰੋਵਾਈਡਰਾਂ ਵਿੱਚ ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼ ਬ੍ਰਾਊਜ਼ ਕਰੋ", "embeddedServices": "ਐਂਬੈਡ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ", "embeddedServicesSubtitle": "ਵਿਕਲਪਿਕ ਲੋਕਲ ਸੇਵਾਵਾਂ", "logs": "ਲੌਗ", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index 74017d20d69d..7f5fc585068f 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Paganahin ang adaptive virtual admission lanes para sa bawat tenant sa pagpapadala ng provider (#9654): ang pag-akyat ng trapiko ng isang tenant ay hindi na nagbibigay ng 503 sa iba. Ang environment variable na OMNIROUTE_CHAT_VIRTUAL_LANES ay mas nangingibabaw sa setting na ito sa dashboard; magkakabisa ang mga pagbabago sa pag-restart ng server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Mga page ng provider sa Dashboard: ipakita lamang ang Libre na badge sa mga signal na kinikilala ng provider — inaalis nito ang heuristic ng display-name, mga non-boolean na free field, at mga :free suffix sa mga nakarehistrong provider na walang dokumentadong libreng tier. Kapag naka-off, pinananatili ang dating panuntunan sa badge.", "featureFlagProxySkipRecentlyFailedDescription": "Pinipigilan ng mga proxy pool at ng pag-ikot ng opencode sa bawat account na muling gumamit ng proxy na kabibigo lang (tinanggihan ang TCP probe, o nakatanggap ng 429 sa pamamagitan nito) sa loob ng isang panahon para sa bawat proseso na dumodoble sa bawat pag-ulit, hanggang sa itinakdang limitasyon. Walang isinusulat na status ng proxy; kapag isinantabi ang lahat ng kandidato, hindi nagbabago ang pagpili. Naka-on bilang default; ibinabalik ng `false` ang karaniwang pagpili.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Para sa mga provider na ang quota ay naka-bucket ayon sa egress address, i-rank ang isang pool member na kapareho ng naobserbahang egress address ng isang kamakailang tinanggihang miyembro sa ilalim lamang ng mga healthy na miyembro. Pagkakasunod-sunod lamang, hindi kailanman ibinubukod. Kinakailangan ang PROXY_SKIP_RECENTLY_FAILED, na bumubuo sa refusal signal na binabasa nito. Naka-off bilang default: ang pagkakasunod-sunod ng pagpili ay eksaktong karaniwang rotation.", "featureFlagProxyPoolEgressObservationDescription": "Ipakita sa ilalim ng isang proxy pool sa dashboard kung ilang naobserbahang egress IP ang ginamit ng mga miyembro nito sa nakalipas na 24 h, kung ilang koneksyon ang gumamit sa mga ito, at ang pinakamataas na bilang na nakita sa likod ng isang IP. Read-only, kinukuwenta mula sa proxy log, at hindi kailanman ginagamit sa pagruruta. Naka-off bilang default: hindi nagbabago ang editor ng pool at null ang isinasagot ng route ng obserbasyon.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Sa pagsusuri sa kalagayan ng proxy, hayaan ang isang probe na tinanggihan ng target (401/403/429: ipinasa ito ng proxy, ngunit tinanggihan ng destinasyon ang egress IP na ito) na i-reset ang sunod-sunod na pagkabigo ng proxy, tulad ng isang naihatid na probe. Naka-off bilang default: nananatiling neutral ang pagtanggi at hindi nito binabago ang sunod-sunod na pagkabigo. Nananatiling walang tiyak na resulta ang isang 5xx sa alinmang paraan, at ang pagtanggi ay hindi kailanman nag-aalis, nagdi-disable, o muling nag-a-activate ng proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Payagan ang awtomatikong cleanup sweep na burahin ang mga terminal (completed/failed/cancelled/expired) na Batch API job na mas luma kaysa OMNIROUTE_BATCH_RETENTION_DAYS, kasama ang kanilang mga checkpoint sa bawat linya, at i-clear ang BLOB content ng mga na-upload na file na lumampas na sa sarili nilang expires_at. Naka-off bilang default: pananatilihin ng bawat kasalukuyang install ang data na ito nang eksaktong gaya ng dati hanggang sa mag-opt in ang isang operator. Hindi maaapektuhan sa alinmang paraan ang route na DELETE /api/v1/batches/delete-completed na pinapagana ng operator -- isa itong hiwalay at walang-kondisyong pampublikong API contract.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Ang iyong mga URL ng koneksyon sa AI", "apiManager": "Tagapamahala ng API", "apiManagerSubtitle": "Pamahalaan ang mga API key at access", + "modelCatalog": "Mga Modelo at Combo", + "modelCatalogSubtitle": "Mag-browse ng mga modelo at combo sa iba't ibang provider", "embeddedServices": "Mga Naka-embed na Serbisyo", "embeddedServicesSubtitle": "Pamahalaan ang mga lokal na proxy na serbisyo", "logs": "Mga log", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index c9377cf4d704..4c5c627eb667 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Włącz adaptacyjne wirtualne pasma przyjęć dla każdego tenanta przy wysyłce do dostawców (#9654): przeciążenie jednego tenanta nie powoduje już błędu 503 u innego. Zmienna środowiskowa OMNIROUTE_CHAT_VIRTUAL_LANES ma pierwszeństwo przed tym ustawieniem w panelu; zmiany wchodzą w życie po restarcie serwera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Strony dostawców w panelu: wyświetlaj odznakę „Bezpłatne” tylko na podstawie sygnałów uznawanych przez dostawcę — pomija heurystykę nazwy wyświetlanej, niebędące wartościami logicznymi pola dotyczące bezpłatności oraz sufiksy :free u zarejestrowanych dostawców bez udokumentowanej bezpłatnej warstwy. Wyłączenie zachowuje dotychczasową regułę wyświetlania odznaki.", "featureFlagProxySkipRecentlyFailedDescription": "Pule serwerów proxy oraz rotacja opencode dla poszczególnych kont przestają ponownie wybierać serwer proxy, który właśnie zawiódł (odrzucona próba TCP lub otrzymany za jego pośrednictwem kod 429), na okres właściwy dla danego procesu, który podwaja się przy każdym kolejnym takim zdarzeniu, aż do osiągnięcia limitu. Stan serwera proxy nie jest zapisywany; po odłożeniu na bok wszystkich kandydatów wybór pozostaje bez zmian. Domyślnie włączone; `false` przywraca zwykły wybór.", + "featureFlagProxyPoolSharedEgressOrderDescription": "W przypadku dostawców, których limit jest dzielony według adresu wyjściowego, umieszczaj członka puli współdzielącego zaobserwowany adres wyjściowy niedawno odrzuconego członka tuż za zdrowymi członkami. Tylko kolejność, nigdy nie wyklucza. Wymaga PROXY_SKIP_RECENTLY_FAILED, który generuje odczytywany sygnał odmowy. Domyślnie wyłączone: kolejność wyboru odpowiada dokładnie zwykłej rotacji.", "featureFlagProxyPoolEgressObservationDescription": "Wyświetla w panelu, pod pulą serwerów proxy, ile zaobserwowanych wychodzących adresów IP obsługiwało jej elementy w ciągu ostatnich 24 godz., ile połączeń z nich korzystało oraz największą liczbę połączeń za jednym adresem IP. Tylko do odczytu, obliczane na podstawie dziennika serwerów proxy i nigdy niewykorzystywane do routingu. Domyślnie wyłączone: edytor puli pozostaje bez zmian, a trasa obserwacji zwraca null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Podczas kontroli kondycji serwerów proxy pozwala, aby próba odrzucona przez cel (401/403/429: serwer proxy przekazał żądanie, ale miejsce docelowe odrzuciło ten wychodzący adres IP) resetowała serię kolejnych niepowodzeń serwera proxy, tak jak obsłużona próba. Domyślnie wyłączone: odrzucenie pozostaje neutralne i nie przerywa serii. Odpowiedź 5xx pozostaje nierozstrzygająca w obu przypadkach, a odrzucenie nigdy nie usuwa, nie wyłącza ani nie aktywuje ponownie serwera proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Pozwól automatycznemu czyszczeniu usuwać zadania Batch API w stanie końcowym (ukończone/nieudane/anulowane/wygasłe), starsze niż OMNIROUTE_BATCH_RETENTION_DAYS, wraz z ich punktami kontrolnymi dla poszczególnych wierszy oraz czyścić zawartość BLOB przesłanych plików po upływie ich własnego terminu expires_at. Domyślnie wyłączone: każda istniejąca instalacja przechowuje te dane dokładnie tak jak wcześniej, dopóki operator nie włączy tej opcji. Wywoływana przez operatora trasa DELETE /api/v1/batches/delete-completed pozostaje niezależnie od tego bez zmian — jest to osobny, bezwarunkowy kontrakt publicznego API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Adresy URL połączeń AI", "apiManager": "Klucze API", "apiManagerSubtitle": "Zarządzanie kluczami API i dostępem", + "modelCatalog": "Modele i kombinacje", + "modelCatalogSubtitle": "Przeglądaj modele i kombinacje u różnych dostawców", "embeddedServices": "Usługi osadzone", "embeddedServicesSubtitle": "Zarządzanie lokalnymi usługami proxy", "logs": "Logi", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index bd8761ece584..b6e27d0ff566 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ative faixas de admissão virtuais adaptativas por tenant para o despacho de provedores (#9654): o pico de um tenant não gera mais 503 para outro. A variável de ambiente OMNIROUTE_CHAT_VIRTUAL_LANES tem precedência sobre esta configuração do painel; as alterações entram em vigor ao reiniciar o servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de provedores no painel: exibe o selo Grátis apenas quando houver sinais reconhecidos pelo provedor — descarta a heurística de nome de exibição, campos de gratuidade não booleanos e sufixos :free em provedores registrados sem uma modalidade gratuita documentada. Quando desativado, mantém a regra histórica do selo.", "featureFlagProxySkipRecentlyFailedDescription": "Pools de proxy e a rotação por conta do opencode deixam de reutilizar um proxy que acabou de falhar (sonda TCP recusada, ou um 429 recebido por ele) por um período por processo que dobra a cada repetição, até um limite. Nenhum status de proxy é gravado; com todos os candidatos deixados de lado, a escolha não muda. Ligado por padrão; `false` restaura a seleção simples.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Para provedores cuja cota é agrupada por endereço de saída, classifique um membro do pool que compartilha o endereço de saída observado de um membro recusado recentemente logo abaixo dos membros saudáveis. Apenas ordenação, nunca excluído. Requer PROXY_SKIP_RECENTLY_FAILED, que produz o sinal de recusa que ele lê. Desativado por padrão: a ordem de seleção é exatamente a rotação simples.", "featureFlagProxyPoolEgressObservationDescription": "Mostra, abaixo de um pool de proxy no painel, quantos IPs de saída observados atenderam seus membros nas últimas 24 h, quantas conexões os usaram e o máximo visto atrás de um mesmo IP. Somente leitura, calculado a partir do log de proxy, nunca usado para roteamento. Desligado por padrão: o editor de pool não muda e a rota de observação responde null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Na varredura de saúde de proxy, permite que uma sonda recusada pelo destino (401/403/429: o proxy retransmitiu, o destino recusou este IP de saída) zere a sequência de falhas consecutivas do proxy, como uma sonda atendida. Desligado por padrão: a recusa continua neutra e mantém a sequência. Um 5xx continua inconclusivo em qualquer caso, e uma recusa nunca remove, desativa ou reativa um proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permite que a varredura automática de limpeza exclua jobs terminais (completed/failed/cancelled/expired) da Batch API mais antigos que OMNIROUTE_BATCH_RETENTION_DAYS, junto com seus checkpoints por linha, e limpe o conteúdo BLOB de arquivos enviados que já passaram do próprio expires_at. Desligado por padrão: toda instalação existente mantém esses dados exatamente como estão até um operador ativar. A rota DELETE /api/v1/batches/delete-completed, acionada pelo operador, não é afetada de nenhuma forma -- é um contrato de API pública separado e incondicional.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Seus URLs de conexão de IA", "apiManager": "Gerenciador API", "apiManagerSubtitle": "Gerenciar chaves de API e acesso", + "modelCatalog": "Modelos e Combos", + "modelCatalogSubtitle": "Navegue por modelos e combos entre provedores", "embeddedServices": "Serviços Embarcados", "embeddedServicesSubtitle": "Gerenciar serviços de proxy locais", "logs": "Registros", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 79e5be87093a..e515dd38ea4e 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ative filas de admissão virtuais adaptativas por tenant para o encaminhamento de fornecedores (#9654): um pico de tráfego de um tenant já não gera 503 noutro. A variável de ambiente OMNIROUTE_CHAT_VIRTUAL_LANES sobrepõe-se a esta definição do painel; as alterações entram em vigor ao reiniciar o servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de fornecedores no dashboard: mostrar o distintivo Gratuito apenas com base nos sinais que o fornecedor reconhece — ignora a heurística do nome de apresentação, os campos free não booleanos e os sufixos :free em fornecedores registados sem um nível gratuito documentado. Desativado mantém a regra histórica do distintivo.", "featureFlagProxySkipRecentlyFailedDescription": "Os conjuntos de proxies e a rotação por conta do opencode deixam de voltar a disponibilizar um proxy que acabou de falhar (sondagem TCP recusada ou resposta 429 recebida através do mesmo) durante um período por processo que duplica a cada repetição, até um limite máximo. Não é registado qualquer estado do proxy; se todos os candidatos forem postos de parte, a escolha permanece inalterada. Ativado por predefinição; `false` repõe a seleção simples.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Para fornecedores cuja quota é agrupada por endereço de saída, classificar um membro do pool que partilha o endereço de saída observado de um membro recentemente recusado imediatamente abaixo dos membros saudáveis. Apenas ordenação, nunca excluído. Requer PROXY_SKIP_RECENTLY_FAILED, que produz o sinal de recusa que este lê. Desativado por predefinição: a ordem de seleção é exatamente a rotação simples.", "featureFlagProxyPoolEgressObservationDescription": "Mostrar, sob um conjunto de proxies no dashboard, quantos IPs de saída observados serviram os respetivos membros nas últimas 24 h, quantas ligações os utilizaram e o número máximo de membros observados por trás de um único IP. Apenas de leitura, calculado a partir do registo do proxy e nunca utilizado para encaminhamento. Desativado por predefinição: o editor do conjunto permanece inalterado e a rota de observação devolve null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Na verificação de integridade dos proxies, permitir que uma sondagem recusada pelo destino (401/403/429: o proxy reencaminhou o pedido, mas o destino recusou este IP de saída) reinicie a sequência de falhas consecutivas do proxy, tal como uma sondagem bem-sucedida. Desativado por predefinição: uma recusa permanece neutra e mantém a sequência. Uma resposta 5xx permanece inconclusiva em qualquer dos casos, e uma recusa nunca remove, desativa nem reativa um proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permitir que a limpeza automática elimine tarefas da Batch API em estado terminal (concluídas/com falha/canceladas/expiradas) com mais de OMNIROUTE_BATCH_RETENTION_DAYS, juntamente com os respetivos pontos de controlo por linha, e limpe o conteúdo BLOB dos ficheiros carregados cuja própria data expires_at já tenha passado. Desativado por predefinição: todas as instalações existentes mantêm estes dados exatamente como antes até que um operador ative esta opção. A rota DELETE /api/v1/batches/delete-completed acionada pelo operador não é afetada em nenhum dos casos — trata-se de um contrato de API pública separado e incondicional.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Seus URLs de conexão de IA", "apiManager": "Gerenciador de APIs", "apiManagerSubtitle": "Gerenciar chaves de API e acesso", + "modelCatalog": "Modelos e Combos", + "modelCatalogSubtitle": "Explorar modelos e combos entre fornecedores", "embeddedServices": "Serviços Integrados", "embeddedServicesSubtitle": "Gerenciar serviços proxy locais", "logs": "Registros", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index 88b166a076ed..531c54d463cc 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activați benzile de admitere virtuale adaptive per-tenant pentru expedierea către furnizori (#9654): un vârf de trafic al unui tenant nu mai returnează 503 altui tenant. Variabila de mediu OMNIROUTE_CHAT_VIRTUAL_LANES are prioritate față de această setare din panou; modificările intră în vigoare la repornirea serverului.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Paginile furnizorilor din tabloul de bord: afișează insigna Gratuit numai pe baza indiciilor confirmate de furnizor — elimină euristica bazată pe numele afișat, câmpurile pentru gratuitate care nu au valori booleene și sufixele :free în cazul furnizorilor înregistrați care nu au un nivel gratuit documentat. Opțiunea Dezactivat păstrează regula istorică privind insigna.", "featureFlagProxySkipRecentlyFailedDescription": "Pool-urile de proxy-uri și rotația per cont din opencode nu mai reutilizează un proxy care tocmai a eșuat (sondă TCP refuzată sau un răspuns 429 primit prin acesta) pentru o perioadă per proces care se dublează la fiecare repetare, până la o limită maximă. Nu este înregistrată nicio stare a proxy-ului; dacă toți candidații sunt puși deoparte, alegerea rămâne neschimbată. Activat în mod implicit; `false` restabilește selecția simplă.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Pentru furnizorii a căror cotă este grupată după adresa de egress, poziționează un membru din pool care partajează adresa de egress observată a unui membru refuzat recent imediat sub membrii sănătoși. Doar ordonare, niciodată exclus. Necesită PROXY_SKIP_RECENTLY_FAILED, care produce semnalul de refuz pe care îl citește. Dezactivat în mod implicit: ordinea de selecție este exact rotația simplă.", "featureFlagProxyPoolEgressObservationDescription": "Afișează, sub un pool de proxy-uri din panoul de control, câte IP-uri de ieșire observate au deservit membrii acestuia în ultimele 24 h, câte conexiuni le-au folosit și numărul maxim de conexiuni observate în spatele unui singur IP. Doar pentru citire, calculat din jurnalul proxy-ului și niciodată utilizat pentru rutare. Dezactivat în mod implicit: editorul pool-ului rămâne neschimbat, iar ruta de observare returnează null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "În verificarea periodică a stării proxy-urilor, permite unei sonde refuzate de destinație (401/403/429: proxy-ul a retransmis, iar destinația a refuzat acest IP de ieșire) să reseteze seria de eșecuri consecutive a proxy-ului, la fel ca o sondă procesată cu succes. Dezactivat în mod implicit: un refuz rămâne neutru și păstrează seria. Un răspuns 5xx rămâne neconcludent în ambele cazuri, iar un refuz nu elimină, nu dezactivează și nu reactivează niciodată un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permite procesului automat de curățare să șteargă sarcinile Batch API în stare terminală (finalizate/eșuate/anulate/expirate) mai vechi decât OMNIROUTE_BATCH_RETENTION_DAYS, împreună cu punctele de control pentru fiecare linie, și să golească conținutul BLOB al fișierelor încărcate care și-au depășit propria valoare expires_at. Dezactivată implicit: fiecare instalare existentă păstrează aceste date exact ca înainte, până când un operator activează opțiunea. Ruta DELETE /api/v1/batches/delete-completed declanșată de operator nu este afectată în niciun caz — aceasta este un contract API public separat și necondiționat.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Adresele URL ale conexiunii dvs. AI", "apiManager": "Manager API", "apiManagerSubtitle": "Gestionați cheile API și accesul", + "modelCatalog": "Modele & Combinații", + "modelCatalogSubtitle": "Răsfoiește modele și combinații de la diverși furnizori", "embeddedServices": "Servicii Integrate", "embeddedServicesSubtitle": "Gestionați serviciile proxy locale", "logs": "Bușteni", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index b8950d588044..874faffadb38 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Включите адаптивные виртуальные полосы допуска для каждого тенанта при маршрутизации к провайдерам (#9654): всплеск нагрузки одного тенанта больше не вызывает 503 у другого. Переменная окружения OMNIROUTE_CHAT_VIRTUAL_LANES имеет приоритет над этой настройкой в панели; изменения вступают в силу после перезапуска сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Страницы провайдеров на панели управления: показывать значок «Бесплатно» только для признаков, которые учитывает провайдер. Эвристика на основе отображаемого имени, небулевы поля free и суффиксы :free для зарегистрированных провайдеров без документально подтверждённого бесплатного тарифа больше не используются. При отключении сохраняется прежнее правило отображения значка.", "featureFlagProxySkipRecentlyFailedDescription": "Пулы прокси и ротация opencode для каждой учётной записи временно перестают повторно выбирать прокси сразу после сбоя (отказ при проверке TCP или ответ 429, полученный через него) на срок, действующий в рамках процесса и удваивающийся при каждом повторном сбое вплоть до установленного предела. Статус прокси не записывается; если отложены все кандидаты, выбор остаётся прежним. По умолчанию включено; `false` возвращает обычный выбор.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Для провайдеров, квота которых распределяется по egress-адресу: размещать участника пула, имеющего общий зафиксированный egress-адрес с недавно отклоненным участником, сразу после работоспособных участников. Влияет только на порядок, исключение не производится. Требуется PROXY_SKIP_RECENTLY_FAILED, формирующий считываемый сигнал отказа. По умолчанию отключено: порядок выбора строго соответствует обычной ротации.", "featureFlagProxyPoolEgressObservationDescription": "Показывать под пулом прокси на панели управления, сколько наблюдаемых исходящих IP-адресов использовалось его участниками за последние 24 ч, сколько подключений использовало эти адреса и какое наибольшее число подключений приходилось на один IP-адрес. Данные доступны только для чтения, вычисляются по журналу прокси и никогда не используются для маршрутизации. По умолчанию отключено: редактор пула остаётся без изменений, а маршрут наблюдений возвращает null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "При проверке работоспособности прокси позволить проверке, отклонённой целевым сервером (401/403/429: прокси передал запрос, но целевой сервер отклонил этот исходящий IP-адрес), сбрасывать счётчик последовательных сбоев прокси, как при успешно обслуженной проверке. По умолчанию отключено: отказ остаётся нейтральным и не сбрасывает счётчик. Ответ 5xx в любом случае остаётся неопределённым, а отказ никогда не удаляет, не отключает и не активирует прокси повторно.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Разрешить автоматической очистке удалять задания Batch API в конечном состоянии (завершённые/завершившиеся ошибкой/отменённые/с истёкшим сроком действия) старше OMNIROUTE_BATCH_RETENTION_DAYS вместе с их построчными контрольными точками, а также очищать содержимое BLOB загруженных файлов после наступления указанного для них expires_at. По умолчанию отключено: во всех существующих установках эти данные сохраняются без изменений, пока оператор не включит эту функцию. Маршрут DELETE /api/v1/batches/delete-completed, запускаемый оператором, не затрагивается независимо от этой настройки — это отдельный безусловный контракт публичного API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL-адреса вашего подключения к AI", "apiManager": "Менеджер API", "apiManagerSubtitle": "Управление ключами API и доступом", + "modelCatalog": "Модели и комбо", + "modelCatalogSubtitle": "Просмотр моделей и комбо среди провайдеров", "embeddedServices": "Встроенные Сервисы", "embeddedServicesSubtitle": "Управление локальными прокси-сервисами", "logs": "Журналы", diff --git a/src/i18n/messages/si.json b/src/i18n/messages/si.json index f4b254485e58..5207a998e218 100644 --- a/src/i18n/messages/si.json +++ b/src/i18n/messages/si.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "සපයන්නා වෙත යැවීම සඳහා එක් එක් ටෙනන්ට්ට අනුව අනුවර්තනය වන අතථ්ය ප්රවේශ මංතීරු සබල කරන්න (#9654): එක් ටෙනන්ට් කෙනෙකුගේ හදිසි ඉල්ලීම් වැඩිවීමක් තවදුරටත් වෙනත් අයෙකුට 503 දෝෂයක් ඇති නොකරයි. OMNIROUTE_CHAT_VIRTUAL_LANES පරිසර විචල්යය මෙම උපකරණ පුවරු අතික්රමණයට වඩා ප්රමුඛ වේ; වෙනස්කම් සේවාදායකය නැවත ආරම්භ කළ විට ක්රියාත්මක වේ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "උපකරණ පුවරුවේ සැපයුම්කරු පිටු: සැපයුම්කරු පිළිගන්නා සංඥා මත පමණක් නොමිලේ ලාංඡනය පෙන්වන්න — ලේඛනගත නොමිලේ මට්ටමක් නොමැති ලියාපදිංචි සැපයුම්කරුවන් සඳහා සංදර්ශක නාම අනුමානය, බූලීය නොවන නොමිලේ ක්ෂේත්ර සහ :free ප්රත්ය අත්හරියි. අක්රිය කළ විට ඓතිහාසික ලාංඡන රීතිය භාවිත කරයි.", "featureFlagProxySkipRecentlyFailedDescription": "ප්රොක්සි සංචිත සහ opencode හි ගිණුමකට වෙන් වූ මාරු කිරීම, අසාර්ථක වූ ප්රොක්සියක් (ප්රතික්ෂේප වූ TCP පරීක්ෂාවක් හෝ එය හරහා ලැබුණු 429 ප්රතිචාරයක්) එක් එක් නැවත සිදුවීමේදී දෙගුණ වන, උපරිම සීමාවකට යටත් ක්රියාවලි-විශේෂිත කාලයක් සඳහා නැවත භාවිත කිරීම නවත්වයි. කිසිදු ප්රොක්සි තත්ත්වයක් ලියනු නොලැබේ; සෑම අපේක්ෂකයෙකුම පසෙකට කළ විට තේරීම වෙනස් නොවේ. පෙරනිමියෙන් සක්‍රියයි; `false` සරල තේරීම ප්‍රතිසාධනය කරයි.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Egress ලිපිනය අනුව කෝටාව කාණ්ඩ කර ඇති සපයන්නන් සඳහා, මෑතකදී ප්‍රතික්ෂේප වූ සාමාජිකයෙකුගේ නිරීක්ෂිත egress ලිපිනය බෙදාගන්නා pool සාමාජිකයෙකු නිරෝගී සාමාජිකයින්ට මදක් පහළින් ශ්‍රේණිගත කරන්න. අනුපිළිවෙල පමණි, කිසිවිටෙකත් බැහැර නොකෙරේ. මෙය කියවන ප්‍රතික්ෂේප කිරීමේ සංඥාව ලබා දෙන PROXY_SKIP_RECENTLY_FAILED අවශ්‍ය වේ. පෙරනිමියෙන් අක්‍රියයි: තේරීම් අනුපිළිවෙල සාමාන්‍ය භ්‍රමණයම වේ.", "featureFlagProxyPoolEgressObservationDescription": "උපකරණ පුවරුවේ ප්රොක්සි සංචිතයක් යටතේ, පසුගිය පැය 24 තුළ එහි සාමාජිකයන්ට සේවය සැපයූ නිරීක්ෂිත පිටතට යන IP ලිපින ගණන, ඒවා භාවිත කළ සම්බන්ධතා ගණන සහ එක් IP ලිපිනයක් පිටුපසින් නිරීක්ෂණය වූ උපරිම ගණන පෙන්වන්න. මෙය කියවීමට පමණක් වන අතර ප්රොක්සි ලොගයෙන් ගණනය කෙරෙන අතර මාර්ගගත කිරීම සඳහා කිසි විටෙක භාවිත නොකෙරේ. පෙරනිමියෙන් අක්රියයි: සංචිත සංස්කාරකය වෙනස් නොවන අතර නිරීක්ෂණ මාර්ගය null ලෙස පිළිතුරු දෙයි.", "featureFlagProxyHealthBlockedResetsStreakDescription": "ප්රොක්සි සෞඛ්ය පරීක්ෂණ වටයේදී, ඉලක්කය ප්රතික්ෂේප කළ පරීක්ෂාවකට (401/403/429: ප්රොක්සිය ඉල්ලීම යොමු කළ නමුත් ගමනාන්තය මෙම පිටතට යන IP ලිපිනය ප්රතික්ෂේප කළේය) සාර්ථකව සේවය කළ පරීක්ෂාවක් මෙන් ප්රොක්සියේ අඛණ්ඩ අසාර්ථකවීම් පෙළ යළි සැකසීමට ඉඩ දෙන්න. පෙරනිමියෙන් අක්රියයි: ප්රතික්ෂේප කිරීමක් මධ්යස්ථව පවතින අතර අඛණ්ඩ අසාර්ථකවීම් පෙළ එලෙසම තබයි. 5xx ප්රතිචාරයක් අවස්ථා දෙකේදීම අවිනිශ්චිතව පවතින අතර, ප්රතික්ෂේප කිරීමක් කිසි විටෙක ප්රොක්සියක් ඉවත් කිරීම, අක්රිය කිරීම හෝ නැවත සක්රිය කිරීම සිදු නොකරයි.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ස්වයංක්රීය පිරිසිදු කිරීමේ ක්රියාවලියට OMNIROUTE_BATCH_RETENTION_DAYS ට වඩා පැරණි අවසන් තත්ත්වයේ (සම්පූර්ණ කළ/අසාර්ථක වූ/අවලංගු කළ/කල් ඉකුත් වූ) Batch API කාර්ය, ඒවායේ එක් එක් පේළියේ checkpoints සමඟ මකා දැමීමටත්, තමන්ගේ expires_at පසු කළ උඩුගත කළ ගොනුවල BLOB අන්තර්ගතය හිස් කිරීමටත් ඉඩ දෙන්න. පෙරනිමියෙන් අක්රියයි: ක්රියාකරු තේරීමෙන් සක්රිය කරන තෙක් පවතින සෑම ස්ථාපනයක්ම මෙම දත්ත පෙර පරිදිම තබා ගනී. ක්රියාකරු විසින් ක්රියාත්මක කරන DELETE /api/v1/batches/delete-completed මාර්ගයට මෙය කෙසේ සැකසුවත් බලපෑමක් නැත — එය වෙනම, කොන්දේසි රහිත පොදු API ගිවිසුමකි.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "ඔබගේ AI සම්බන්ධතා URL", "apiManager": "API යතුරු", "apiManagerSubtitle": "API යතුරු සහ ප්රවේශය කළමනාකරණය කරන්න", + "modelCatalog": "මොඩල සහ සංයෝජන", + "modelCatalogSubtitle": "සපයන්නන් හරහා මොඩල සහ සංයෝජන පිරික්සන්න", "embeddedServices": "කාවැද්දූ සේවා", "embeddedServicesSubtitle": "විකල්ප දේශීය සේවා", "logs": "ලොග්", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index b9d6cdb5615d..a79085fe4936 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Povoľte adaptívne virtuálne vstupné pruhy pre každého nájomcu (tenant) pri odosielaní poskytovateľom (#9654): špička jedného nájomcu už nespôsobí 503 u iného. Premenná prostredia OMNIROUTE_CHAT_VIRTUAL_LANES má prednosť pred týmto nastavením v riadiacom paneli; zmeny sa prejavia po reštarte servera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stránky poskytovateľov na ovládacom paneli: zobrazovať odznak Bezplatné iba na základe signálov, ktoré poskytovateľ uznáva — nepoužíva sa heuristika zobrazovaného názvu, polia bez booleovskej hodnoty označujúce bezplatnosť ani prípony :free pri registrovaných poskytovateľoch bez zdokumentovanej bezplatnej úrovne. Vypnutie zachová pôvodné pravidlo zobrazovania odznaku.", "featureFlagProxySkipRecentlyFailedDescription": "Fondy proxy serverov a rotácia opencode pre jednotlivé účty prestanú počas obdobia platného pre daný proces opätovne používať proxy server, ktorý práve zlyhal (odmietnutá sonda TCP alebo odpoveď 429 prijatá cez tento proxy server). Toto obdobie sa pri každom opakovaní zdvojnásobí až po stanovený limit. Stav proxy servera sa nezapisuje; ak sú všetci kandidáti odložení bokom, výber zostáva nezmenený. Predvolene zapnuté; `false` obnoví bežný výber.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Pre poskytovateľov, ktorých kvóta je rozdelená podľa egress adresy, zaraďte člena fondu zdieľajúceho zaznamenanú egress adresu nedávno odmietnutého člena tesne za zdravých členov. Iba zmena poradia, nikdy nie vylúčenie. Vyžaduje PROXY_SKIP_RECENTLY_FAILED, ktoré generuje signál odmietnutia, z ktorého číta. Predvolene vypnuté: poradie výberu presne zodpovedá bežnej rotácii.", "featureFlagProxyPoolEgressObservationDescription": "V ovládacom paneli zobraziť pod fondom proxy serverov, cez koľko pozorovaných výstupných IP adries komunikovali jeho členovia za posledných 24 h, koľko pripojení ich použilo a aký najvyšší počet pripojení bol zaznamenaný za jednou IP adresou. Iba na čítanie, vypočítané z denníka proxy servera a nikdy nepoužívané na smerovanie. Predvolene vypnuté: editor fondu zostáva nezmenený a trasa pozorovania vracia null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Pri kontrole stavu proxy serverov umožniť, aby sonda odmietnutá cieľom (401/403/429: proxy server ju preniesol, ale cieľ odmietol túto výstupnú IP adresu) vynulovala sériu po sebe nasledujúcich zlyhaní proxy servera rovnako ako obslúžená sonda. Predvolene vypnuté: odmietnutie zostáva neutrálne a zachováva sériu. Odpoveď 5xx zostáva v oboch prípadoch nejednoznačná a odmietnutie nikdy neodstráni, nezakáže ani znovu neaktivuje proxy server.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Povoliť automatickému čisteniu odstraňovať ukončené (dokončené/neúspešné/zrušené/expirované) úlohy Batch API staršie než OMNIROUTE_BATCH_RETENTION_DAYS spolu s ich kontrolnými bodmi pre jednotlivé riadky a vymazať obsah BLOB nahraných súborov po uplynutí ich vlastného expires_at. Predvolene vypnuté: každá existujúca inštalácia uchováva tieto údaje presne ako doteraz, kým operátor túto funkciu nezapne. Trasa DELETE /api/v1/batches/delete-completed spúšťaná operátorom zostáva v oboch prípadoch nedotknutá – ide o samostatný, bezpodmienečný verejný kontrakt API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Vaše webové adresy pripojenia AI", "apiManager": "Kľúče API", "apiManagerSubtitle": "Spravujte kľúče API a prístup", + "modelCatalog": "Modely a kombinácie", + "modelCatalogSubtitle": "Prehliadajte modely a kombinácie naprieč poskytovateľmi", "embeddedServices": "Zabudované Služby", "embeddedServicesSubtitle": "Spravovať lokálne proxy služby", "logs": "Denníky", diff --git a/src/i18n/messages/sl.json b/src/i18n/messages/sl.json index 39cb783673fd..eea19776fb35 100644 --- a/src/i18n/messages/sl.json +++ b/src/i18n/messages/sl.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogoči prilagodljive navidezne sprejemne pasove za posameznega najemnika pri posredovanju ponudniku (#9654): nenaden porast zahtev enega najemnika ne povzroča več napak 503 pri drugem. Spremenljivka okolja OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost pred to nastavitvijo nadzorne plošče; spremembe začnejo veljati po ponovnem zagonu strežnika.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Strani ponudnikov na nadzorni plošči: značko Brezplačno prikaži samo pri signalih, ki jih ponudnik upošteva — brez hevristike prikaznega imena, neboolovskih polj free in pripon :free pri registriranih ponudnikih brez dokumentirane brezplačne ravni. Izklopljeno ohrani preteklo pravilo za značke.", "featureFlagProxySkipRecentlyFailedDescription": "Skupine posredniških strežnikov in vrtenje opencode za posamezen račun za določeno obdobje znotraj procesa prenehajo znova uporabljati posredniški strežnik, ki je pravkar odpovedal (zavrnjeno preverjanje TCP ali prek njega prejeta napaka 429). To obdobje se ob vsaki ponovitvi podvoji do določene zgornje meje. Stanje posredniškega strežnika se ne zapiše; če so vsi kandidati izločeni, izbira ostane nespremenjena. Privzeto vklopljeno; `false` obnovi običajno izbiro.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Za ponudnike, katerih kvota je razdeljena po izhodnem naslovu, uvrsti člana bazena, ki si deli zabeleženi izhodni naslov nedavno zavrnjenega člana, tik pod zdrave člane. Vpliva samo na vrstni red, nikoli ni izključen. Zahteva PROXY_SKIP_RECENTLY_FAILED, ki ustvari signal zavrnitve, ki ga ta možnost bere. Privzeto izklopljeno: vrstni red izbire je natanko običajna rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Na nadzorni plošči pod skupino posredniških strežnikov prikaži, koliko opaženih izhodnih naslovov IP so v zadnjih 24 h uporabljali njeni člani, koliko povezav jih je uporabilo in največje število povezav prek enega naslova IP. Podatki so samo za branje, izračunani iz dnevnika posredniškega strežnika in se nikoli ne uporabljajo za usmerjanje. Privzeto izklopljeno: urejevalnik skupine ostane nespremenjen, opazovalna pot pa vrne null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Pri preverjanju zdravja posredniških strežnikov naj sonda, ki jo je cilj zavrnil (401/403/429: posredniški strežnik jo je posredoval, cilj pa je zavrnil ta izhodni naslov IP), ponastavi niz zaporednih neuspehov posredniškega strežnika, tako kot uspešno izvedena sonda. Privzeto izklopljeno: zavrnitev ostane nevtralna in ohrani niz. Odziv 5xx v obeh primerih ostane nedoločen, zavrnitev pa posredniškega strežnika nikoli ne odstrani, onemogoči ali znova aktivira.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dovolite, da samodejno čiščenje izbriše končana (uspešno zaključena/neuspešna/preklicana/potekla) opravila Batch API, starejša od OMNIROUTE_BATCH_RETENTION_DAYS, skupaj z njihovimi kontrolnimi točkami za posamezne vrstice, ter počisti vsebino BLOB naloženih datotek, ki jim je potekel njihov expires_at. Privzeto je izklopljeno: vsaka obstoječa namestitev te podatke ohrani popolnoma enako kot prej, dokler skrbnik funkcije ne omogoči. To v nobenem primeru ne vpliva na pot DELETE /api/v1/batches/delete-completed, ki jo sproži skrbnik – gre za ločeno, brezpogojno javno pogodbo API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL-ji vaših povezav z umetno inteligenco", "apiManager": "Ključi API", "apiManagerSubtitle": "Upravljanje ključev API in dostopa", + "modelCatalog": "Modeli in kombinacije", + "modelCatalogSubtitle": "Prebrskajte modele in kombinacije pri različnih ponudnikih", "embeddedServices": "Vdelane storitve", "embeddedServicesSubtitle": "Izbirne lokalne storitve", "logs": "Dnevniki", diff --git a/src/i18n/messages/sr.json b/src/i18n/messages/sr.json index a901e9a0d5a4..bf1f1e01bea7 100644 --- a/src/i18n/messages/sr.json +++ b/src/i18n/messages/sr.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Омогући адаптивне виртуелне линије пријема по закупцу за слање захтева провајдерима (#9654): нагли скок захтева једног закупца више не изазива 503 грешку код другог. Env варијабла OMNIROUTE_CHAT_VIRTUAL_LANES има приоритет над овим прекидачем у контролној табли; промене се примењују при поновном покретању сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Странице добављача на контролној табли: приказују ознаку „Бесплатно“ само за сигнале које добављач уважава — без претпоставки на основу приказаног назива, небуловских поља за бесплатан приступ и суфикса :free код регистрованих добављача без документованог бесплатног пакета. Када је искључено, задржава се претходно правило за приказ ознаке.", "featureFlagProxySkipRecentlyFailedDescription": "Прокси скупови и ротација по налогу у opencode престају да поново користе прокси који је управо отказао (одбијена TCP провера или одговор 429 примљен преко њега) током периода на нивоу процеса који се удвостручује при сваком понављању, до задате горње границе. Статус проксија се не уписује; када су сви кандидати издвојени, избор остаје непромењен. Подразумевано је укључено; `false` враћа обичан избор.", + "featureFlagProxyPoolSharedEgressOrderDescription": "За пружаоце услуга чија је квота груписана према излазној адреси, рангирај члана пула који дели уочену излазну адресу недавно одбијеног члана одмах испод здравих чланова. Само редослед, никада се не искључује. Захтева PROXY_SKIP_RECENTLY_FAILED, који производи сигнал одбијања који се овде чита. Подразумевано искључено: редослед избора је управо обична ротација.", "featureFlagProxyPoolEgressObservationDescription": "У контролној табли, испод прокси скупа, прикажите колико је уочених излазних IP адреса опслуживало његове чланове током последња 24 ч, колико веза их је користило и највећи број веза забележен иза једне IP адресе. Само за читање, израчунава се из евиденције проксија и никада се не користи за усмеравање. Подразумевано је искључено: уређивач скупа остаје непромењен, а рута за посматрање враћа null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "У провери исправности проксија омогућите да провера коју је циљ одбио (401/403/429: прокси је проследио захтев, а одредиште је одбило ову излазну IP адресу) ресетује низ узастопних неуспеха проксија, као и успешно опслужена провера. Подразумевано је искључено: одбијање остаје неутрално и задржава низ. Одговор 5xx у оба случаја остаје неодређен, а одбијање никада не уклања, не онемогућава нити поново активира прокси.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Дозволи аутоматском чишћењу да избрише завршене (успешне/неуспешне/отказане/истекле) Batch API послове старије од вредности OMNIROUTE_BATCH_RETENTION_DAYS, заједно са њиховим контролним тачкама по редовима, и да обрише BLOB садржај отпремљених датотека након њиховог сопственог expires_at. Подразумевано је искључено: свака постојећа инсталација наставља да чува ове податке потпуно исто као раније док оператер не омогући ову опцију. Рута DELETE /api/v1/batches/delete-completed коју покреће оператер ни у једном случају није погођена — она представља засебан, безуслован уговор јавног API-ја.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL адресе за повезивање са AI-јем", "apiManager": "API кључеви", "apiManagerSubtitle": "Управљајте API кључевима и приступом", + "modelCatalog": "Модели и комбинације", + "modelCatalogSubtitle": "Прегледајте моделе и комбинације код различитих пружалаца услуга", "embeddedServices": "Уграђене услуге", "embeddedServicesSubtitle": "Необавезне локалне услуге", "logs": "Записи", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 339bfc9ae67e..57ac46c8ef2b 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivera adaptiva virtuella åtkomstfiler per tenant för providerutskick (#9654): en tenants burst ger inte längre en annan 503. Miljövariabeln OMNIROUTE_CHAT_VIRTUAL_LANES har företräde framför den här inställningen i instrumentpanelen; ändringarna träder i kraft vid omstart av servern.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leverantörssidor på kontrollpanelen: visa märket Gratis endast utifrån uppgifter som leverantören bekräftar – bortse från heuristiken för visningsnamn, icke-booleska gratisfält och suffixet :free för registrerade leverantörer utan en dokumenterad kostnadsfri nivå. Av behåller den tidigare märkesregeln.", "featureFlagProxySkipRecentlyFailedDescription": "Proxypooler och rotationen per konto för opencode slutar att återanvända en proxy som nyss misslyckades (nekad TCP-kontroll eller ett 429-svar som togs emot via den) under en processpecifik period som fördubblas vid varje upprepat fel, upp till en maxgräns. Ingen proxystatus skrivs; om alla kandidater läggs åt sidan förblir valet oförändrat. Påslaget som standard; `false` återställer det vanliga urvalet.", + "featureFlagProxyPoolSharedEgressOrderDescription": "För leverantörer vars kvot är uppdelad per utgående adress, rangordna en poolmedlem som delar en nyligen nekad medlems observerade utgående adress strax under felfria medlemmar. Endast ordning, exkluderas aldrig. Kräver PROXY_SKIP_RECENTLY_FAILED, som genererar avvisningssignalen den läser. Inaktiverad som standard: urvalsordningen är exakt den vanliga rotationen.", "featureFlagProxyPoolEgressObservationDescription": "Visa under en proxypool på instrumentpanelen hur många observerade utgående IP-adresser som betjänade dess medlemmar under de senaste 24 timmarna, hur många anslutningar som använde dem och det högsta antalet som observerades bakom en och samma IP-adress. Skrivskyddat, beräknat från proxyloggen och används aldrig för dirigering. Avstängt som standard: poolredigeraren är oförändrad och observationsrutten returnerar null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Låt en kontroll som avvisades av målet (401/403/429: proxyn vidarebefordrade begäran men destinationen avvisade den utgående IP-adressen) nollställa proxyns serie av på varandra följande fel i proxyhälsokontrollen, precis som en besvarad kontroll. Avstängt som standard: ett avvisande förblir neutralt och bibehåller serien. Ett 5xx-svar förblir icke avgörande i båda fallen, och ett avvisande tar aldrig bort, inaktiverar eller återaktiverar en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Låt den automatiska rensningen ta bort avslutade (slutförda/misslyckade/avbrutna/utgångna) Batch API-jobb som är äldre än OMNIROUTE_BATCH_RETENTION_DAYS, tillsammans med deras kontrollpunkter per rad, och rensa BLOB-innehållet i uppladdade filer efter deras egna expires_at. Av som standard: varje befintlig installation behåller dessa data precis som tidigare tills en operatör väljer att aktivera funktionen. Den operatörsutlösta rutten DELETE /api/v1/batches/delete-completed påverkas inte oavsett inställning – det är ett separat, ovillkorligt offentligt API-kontrakt.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Dina AI-anslutningsadresser", "apiManager": "API-hanterare", "apiManagerSubtitle": "Hantera API-nycklar och åtkomst", + "modelCatalog": "Modeller & kombinationer", + "modelCatalogSubtitle": "Bläddra bland modeller och kombinationer från olika leverantörer", "embeddedServices": "Inbäddade Tjänster", "embeddedServicesSubtitle": "Hantera lokala proxytjänster", "logs": "Loggar", diff --git a/src/i18n/messages/sw.json b/src/i18n/messages/sw.json index 64d6c4f5c727..7ad2c0e01a6b 100644 --- a/src/i18n/messages/sw.json +++ b/src/i18n/messages/sw.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Washa njia za uandikishaji pepe zinazobadilika kwa kila mpangaji (tenant) kwa utumaji wa watoa huduma (#9654): mlipuko wa mpangaji mmoja hautoi tena 503 kwa mwingine. Kigezo cha mazingira cha OMNIROUTE_CHAT_VIRTUAL_LANES kinashinda mpangilio huu wa dashibodi; mabadiliko yanatumika wakati seva inapoanzishwa upya.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Kurasa za watoa huduma kwenye dashibodi: onyesha beji ya Bila Malipo kwenye viashiria ambavyo mtoa huduma anavitambua pekee — huondoa utambuzi wa kukisia kwa kutumia jina la kuonyesha, sehemu zisizo za Boolean zinazoashiria huduma ya bila malipo, na viambishi :free kwa watoa huduma waliosajiliwa ambao hawana kiwango cha huduma ya bila malipo kilichoandikwa. Kuzima huhifadhi kanuni ya awali ya beji.", "featureFlagProxySkipRecentlyFailedDescription": "Makundi ya proksi na uzungushaji wa kila akaunti wa opencode huacha kutumia tena proksi iliyoshindwa hivi punde (jaribio la TCP lilikataliwa, au 429 ilipokelewa kupitia proksi hiyo) kwa kipindi maalumu kwa kila mchakato, ambacho huongezeka maradufu kila kushindwa kunaporudiwa, hadi kikomo fulani. Hakuna hali ya proksi inayoandikwa; kila chaguo linalowezekana likiwekwa kando, uteuzi hubaki bila kubadilika. Imewashwa kwa chaguo-msingi; `false` hurejesha uteuzi wa kawaida.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Kwa watoa huduma ambao kiwango chao kimegawanywa kulingana na anwani ya egress, panga mwanachama wa pool anayeshiriki anwani ya egress iliyoonekana ya mwanachama aliyekataliwa hivi karibuni chini kidogo ya wanachama wenye afya. Ni upangaji tu, haondolewi kamwe. Inahitaji PROXY_SKIP_RECENTLY_FAILED, ambayo hutoa ishara ya kukataliwa inayoisoma. Imezimwa kwa chaguo-msingi: mpangilio wa uteuzi ni mzunguko wa kawaida kabisa.", "featureFlagProxyPoolEgressObservationDescription": "Onyesha, chini ya kundi la proksi kwenye dashibodi, idadi ya anwani za IP za kutoka zilizozingatiwa ambazo zilitumiwa na wanachama wake katika saa 24 zilizopita, idadi ya miunganisho iliyozitumia, na idadi kubwa zaidi iliyoonekana nyuma ya anwani moja ya IP. Ni ya kusoma pekee, huhesabiwa kutoka kwenye kumbukumbu ya proksi, na haitumiki kamwe kuelekeza trafiki. Imezimwa kwa chaguo-msingi: kihariri cha kundi hakibadiliki na njia ya uchunguzi hujibu null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Katika ukaguzi wa afya ya proksi, ruhusu jaribio lililokataliwa na lengwa (401/403/429: proksi ilisambaza ombi, lakini lengwa lilikataa anwani hii ya IP ya kutoka) liweke upya mfululizo wa kushindwa kwa proksi, kama jaribio lililohudumiwa. Imezimwa kwa chaguo-msingi: kukataliwa hubaki bila upande na hudumisha mfululizo huo. 5xx hubaki bila hitimisho kwa vyovyote vile, na kukataliwa kamwe hakuondoi, hakuzima wala kuwezesha tena proksi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ruhusu usafishaji wa kiotomatiki ufute kazi za Batch API zilizo katika hali ya mwisho (zilizokamilika/zilizoshindwa/zilizoghairiwa/zilizopitwa na muda) ambazo ni za zamani kuliko OMNIROUTE_BATCH_RETENTION_DAYS, pamoja na vituo vyake vya ukaguzi vya kila mstari, na ufute maudhui ya BLOB ya faili zilizopakiwa ambazo muda wake wa expires_at umepita. Huzimwa kwa chaguo-msingi: kila usakinishaji uliopo utaendelea kuhifadhi data hii kama hapo awali hadi mwendeshaji atakapochagua kuwasha kipengele hiki. Njia ya DELETE /api/v1/batches/delete-completed inayoanzishwa na mwendeshaji haiathiriwi kwa vyovyote vile — ni mkataba tofauti wa API ya umma usio na masharti.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL zako za muunganisho wa AI", "apiManager": "Funguo za API", "apiManagerSubtitle": "Dhibiti funguo za API na ufikiaji", + "modelCatalog": "Miundo na Michanganyiko", + "modelCatalogSubtitle": "Vinjari miundo na michanganyiko katika watoa huduma wote", "embeddedServices": "Huduma Zilizounganishwa", "embeddedServicesSubtitle": "Dhibiti huduma za wakala wa ndani", "logs": "Kumbukumbu za Matukio", diff --git a/src/i18n/messages/ta.json b/src/i18n/messages/ta.json index 60e481b599bb..d2924fb61e5d 100644 --- a/src/i18n/messages/ta.json +++ b/src/i18n/messages/ta.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "வழங்குநர் அனுப்பீட்டிற்கு ஒவ்வொரு குத்தகைதாரருக்கும் (tenant) தகவமைப்பு மெய்நிகர் சேர்க்கைப் பாதைகளை இயக்கு (#9654): ஒரு குத்தகைதாரரின் அதிகரிப்பு இனி மற்றொருவருக்கு 503 ஐ அளிக்காது. OMNIROUTE_CHAT_VIRTUAL_LANES சூழல் மாறி இந்த டாஷ்போர்டு அமைப்பை விட முன்னுரிமை பெறுகிறது; மாற்றங்கள் சேவையகம் மறுதொடக்கத்தில் நடைமுறைக்கு வரும்.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "டாஷ்போர்டு வழங்குநர் பக்கங்கள்: வழங்குநர் ஏற்கும் குறியீடுகளில் மட்டும் இலவசம் என்ற அடையாளத்தைக் காட்டும் — ஆவணப்படுத்தப்பட்ட இலவச அடுக்கு இல்லாத பதிவுசெய்யப்பட்ட வழங்குநர்களுக்கான காட்சிப் பெயர் ஊகம், பூலியன் அல்லாத இலவசப் புலங்கள் மற்றும் :free பின்னொட்டுகளைப் புறக்கணிக்கும். இதை முடக்கினால், முந்தைய அடையாள விதி பயன்படுத்தப்படும்.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy குளங்களும் opencode-இன் ஒவ்வொரு கணக்கிற்குமான சுழற்சியும், இப்போது தோல்வியடைந்த ஒரு proxy-ஐ (மறுக்கப்பட்ட TCP ஆய்வு அல்லது அதன் வழியாகப் பெறப்பட்ட 429) ஒவ்வொரு செயல்முறைக்கும் உரிய ஒரு காலகட்டத்திற்கு மீண்டும் வழங்குவதை நிறுத்தும்; ஒவ்வொரு தொடர் தோல்வியின்போதும் அந்தக் காலகட்டம் இரட்டிப்பாகி, அதிகபட்ச வரம்பு வரை செல்லும். எந்த proxy நிலையும் எழுதப்படாது; ஒவ்வொரு தேர்வுக்குரியதும் ஒதுக்கி வைக்கப்பட்டால், தேர்வு மாறாமல் இருக்கும். இயல்பாக இயக்கப்பட்டிருக்கும்; `false` சாதாரண தேர்வை மீட்டமைக்கும்.", + "featureFlagProxyPoolSharedEgressOrderDescription": "வெளியேறும் முகவரியின்படி (egress address) ஒதுக்கீடு நிர்வகிக்கப்படும் வழங்குநர்களுக்கு, சமீபத்தில் நிராகரிக்கப்பட்ட உறுப்பினரின் கண்டறியப்பட்ட வெளியேறும் முகவரியைப் பகிரும் பூல் உறுப்பினரை, ஆரோக்கியமான உறுப்பினர்களுக்கு சற்று கீழே தரவரிசைப்படுத்துங்கள். வரிசை மட்டுமே மாற்றப்படும், ஒருபோதும் விலக்கப்படாது. இது படிக்கும் நிராகரிப்பு சிக்னலை உருவாக்கும் PROXY_SKIP_RECENTLY_FAILED இதற்குத் தேவை. இயல்பாக முடக்கப்பட்டுள்ளது: தேர்வு வரிசை என்பது துல்லியமாக வழக்கமான சுழற்சி முறையாகும்.", "featureFlagProxyPoolEgressObservationDescription": "டாஷ்போர்டில் ஒரு proxy குளத்தின் கீழ், கடந்த 24 மணிநேரத்தில் அதன் உறுப்பினர்களுக்குச் சேவையளித்த கண்டறியப்பட்ட வெளியேற்ற IP-களின் எண்ணிக்கை, அவற்றைப் பயன்படுத்திய இணைப்புகளின் எண்ணிக்கை மற்றும் ஓர் IP-க்குப் பின்னால் காணப்பட்ட அதிகபட்ச இணைப்புகளின் எண்ணிக்கை ஆகியவற்றைக் காட்டும். படிக்க மட்டும்; proxy பதிவிலிருந்து கணக்கிடப்படும்; வழித்தடத் தேர்வுக்கு ஒருபோதும் பயன்படுத்தப்படாது. இயல்பாக முடக்கப்பட்டிருக்கும்: குளத் திருத்தி மாறாமல் இருக்கும், மேலும் கண்காணிப்பு வழித்தடம் null எனப் பதிலளிக்கும்.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ஆரோக்கியச் சோதனையில், இலக்கு மறுத்த ஓர் ஆய்வு (401/403/429: proxy அதை அனுப்பியது, ஆனால் இலக்கு இந்த வெளியேற்ற IP-ஐ மறுத்தது), சேவையளிக்கப்பட்ட ஆய்வைப் போலவே proxy-இன் தொடர்ச்சியான தோல்வி வரிசையை மீட்டமைக்க அனுமதிக்கும். இயல்பாக முடக்கப்பட்டிருக்கும்: ஒரு மறுப்பு நடுநிலையாகவே இருந்து, தோல்வி வரிசையைத் தொடர வைத்திருக்கும். எந்த நிலையிலும் 5xx தீர்மானிக்க முடியாததாகவே இருக்கும்; மேலும் ஒரு மறுப்பு ஒருபோதும் proxy-ஐ அகற்றவோ, முடக்கவோ அல்லது மீண்டும் செயல்படுத்தவோ செய்யாது.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS-ஐ விடப் பழைய, இறுதி நிலையை அடைந்த (completed/failed/cancelled/expired) Batch API பணிகளையும், அவற்றின் ஒவ்வொரு வரிக்குமான checkpoints-ஐயும் தானியங்குச் சுத்தப்படுத்தல் நீக்க அனுமதிக்கவும்; மேலும், தங்களின் expires_at-ஐக் கடந்த பதிவேற்றப்பட்ட கோப்புகளின் BLOB உள்ளடக்கத்தை அழிக்கவும். இயல்பாக முடக்கப்பட்டுள்ளது: ஒரு நிர்வாகி இதைத் தேர்வுசெய்து இயக்கும் வரை, ஏற்கனவே உள்ள ஒவ்வொரு நிறுவலும் இந்தத் தரவை முன்பு போலவே வைத்திருக்கும். நிர்வாகியால் தூண்டப்படும் DELETE /api/v1/batches/delete-completed வழித்தடம் எந்த நிலையிலும் பாதிக்கப்படாது — அது ஒரு தனியான, நிபந்தனையற்ற பொது API ஒப்பந்தமாகும்.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "உங்கள் AI இணைப்பு URLகள்", "apiManager": "API விசைகள்", "apiManagerSubtitle": "API விசைகள் மற்றும் அணுகலை நிர்வகிக்கவும்", + "modelCatalog": "மாடல்கள் & காம்போக்கள்", + "modelCatalogSubtitle": "பல்வேறு வழங்குநர்களின் மாடல்கள் மற்றும் காம்போக்களை உலாவவும்", "embeddedServices": "உட்பொதிக்கப்பட்ட சேவைகள்", "embeddedServicesSubtitle": "உள்ளூர் proxy சேவைகளை நிர்வகிக்கவும்", "logs": "பதிவுகள்", diff --git a/src/i18n/messages/te.json b/src/i18n/messages/te.json index b5358f7533de..ce94760b8688 100644 --- a/src/i18n/messages/te.json +++ b/src/i18n/messages/te.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "ప్రొవైడర్ డిస్పాచ్ కోసం ప్రతి-టెనెంట్ అడాప్టివ్ వర్చువల్ అడ్మిషన్ లేన్లను ప్రారంభించండి (#9654): ఒక టెనెంట్ బర్స్ట్ ఇకపై మరొక టెనెంట్కు 503 ఇవ్వదు. OMNIROUTE_CHAT_VIRTUAL_LANES ఎన్విరాన్మెంట్ వేరియబుల్ ఈ డాష్బోర్డ్ సెట్టింగ్ కంటే ప్రాధాన్యత పొందుతుంది; మార్పులు సర్వర్ పునఃప్రారంభంలో ప్రభావం చూపుతాయి.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "డ్యాష్బోర్డ్ ప్రొవైడర్ పేజీలు: ప్రొవైడర్ గుర్తించే సంకేతాలపైనే ఉచిత బ్యాడ్జ్ను చూపించండి — డాక్యుమెంట్ చేయబడిన ఉచిత టైర్ లేని నమోదిత ప్రొవైడర్లలో డిస్ప్లే-పేరు హ్యూరిస్టిక్, బూలియన్ కాని ఉచిత ఫీల్డ్లు మరియు :free ప్రత్యయాలను విస్మరిస్తుంది. ఆఫ్ చేస్తే మునుపటి బ్యాడ్జ్ నియమాన్ని కొనసాగిస్తుంది.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy పూల్లు మరియు opencode యొక్క ఒక్కో ఖాతా రొటేషన్లో, అప్పుడే విఫలమైన Proxyని (TCP ప్రోబ్ తిరస్కరించబడటం లేదా దాని ద్వారా 429 అందుకోవడం) ప్రతి పునరావృతంతో రెట్టింపయ్యే, గరిష్ఠ పరిమితి వరకు ఉండే ఒక్కో ప్రాసెస్ వ్యవధిలో మళ్లీ అందించకుండా ఆపుతుంది. Proxy స్థితి ఏదీ వ్రాయబడదు; ప్రతి అభ్యర్థినీ పక్కన పెడితే ఎంపికలో మార్పు ఉండదు. డిఫాల్ట్‌గా ఆన్‌లో ఉంటుంది; `false` సాధారణ ఎంపికను పునరుద్ధరిస్తుంది.", + "featureFlagProxyPoolSharedEgressOrderDescription": "ఎగ్రెస్ అడ్రస్ ఆధారంగా కోటా కేటాయించబడే ప్రొవైడర్ల కోసం, ఇటీవల తిరస్కరించబడిన మెంబర్ యొక్క గుర్తించిన ఎగ్రెస్ అడ్రస్‌ను షేర్ చేసుకునే పూల్ మెంబర్‌ను హెల్తీ మెంబర్ల కంటే సరిగ్గా దిగువన ర్యాంక్ చేయండి. ఆర్డర్ మాత్రమే, ఎప్పటికీ మినహాయించబడదు. దీనికి PROXY_SKIP_RECENTLY_FAILED అవసరం, ఇది చదివే తిరస్కరణ సిగ్నల్‌ను ఉత్పత్తి చేస్తుంది. డిఫాల్ట్‌గా ఆఫ్ చేయబడి ఉంటుంది: ఎంపిక క్రమం ఖచ్చితంగా సాధారణ రొటేషన్ లాగే ఉంటుంది.", "featureFlagProxyPoolEgressObservationDescription": "డ్యాష్బోర్డ్లోని Proxy పూల్ కింద, గత 24 గంటల్లో దాని సభ్యులకు సేవలందించిన గమనించిన ఎగ్రెస్ IPల సంఖ్య, వాటిని ఉపయోగించిన కనెక్షన్ల సంఖ్య మరియు ఒకే IP వెనుక అత్యధికంగా కనిపించిన సంఖ్యను చూపండి. ఇది చదవడానికి మాత్రమే, Proxy లాగ్ నుండి గణించబడుతుంది, రూటింగ్ కోసం ఎప్పుడూ ఉపయోగించబడదు. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: పూల్ ఎడిటర్ మారదు మరియు పరిశీలన రూట్ null అని సమాధానమిస్తుంది.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ఆరోగ్య స్వీప్లో, లక్ష్యం తిరస్కరించిన ప్రోబ్ (401/403/429: Proxy ప్రసారం చేసింది, గమ్యస్థానం ఈ ఎగ్రెస్ IPని తిరస్కరించింది) విజయవంతంగా సేవలందించిన ప్రోబ్లాగే Proxy యొక్క వరుస వైఫల్యాల పరంపరను రీసెట్ చేయనివ్వండి. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: తిరస్కరణ తటస్థంగానే ఉండి పరంపరను అలాగే ఉంచుతుంది. ఏ విధంగానైనా 5xx అనిశ్చితంగానే ఉంటుంది, అలాగే తిరస్కరణ ఎప్పుడూ Proxyని తొలగించదు, నిలిపివేయదు లేదా మళ్లీ సక్రియం చేయదు.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS కంటే పాతవైన టెర్మినల్ (పూర్తయిన/విఫలమైన/రద్దయిన/గడువు ముగిసిన) Batch API జాబ్లను, వాటి ప్రతి-లైన్ చెక్పాయింట్లతో సహా ఆటోమేటిక్ క్లీనప్ స్వీప్ తొలగించేలా చేయండి; అలాగే వాటి స్వంత expires_at దాటిన అప్లోడ్ చేసిన ఫైల్ల BLOB కంటెంట్ను క్లియర్ చేయండి. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: ఆపరేటర్ దీన్ని ఎంచుకునే వరకు ప్రతి ప్రస్తుత ఇన్స్టాలేషన్ ఈ డేటాను మునుపటిలాగే ఉంచుతుంది. ఆపరేటర్ ప్రారంభించే DELETE /api/v1/batches/delete-completed రూట్పై ఏ విధంగానూ ప్రభావం ఉండదు — అది ప్రత్యేకమైన, షరతులు లేని పబ్లిక్ API ఒప్పందం.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "మీ AI కనెక్షన్ URLలు", "apiManager": "API కీలు", "apiManagerSubtitle": "API కీలు మరియు యాక్సెస్‌ని నిర్వహించండి", + "modelCatalog": "మోడల్స్ & కాంబోలు", + "modelCatalogSubtitle": "వివిధ ప్రొవైడర్ల అంతటా మోడల్స్ మరియు కాంబోలను బ్రౌజ్ చేయండి", "embeddedServices": "ఎంబెడ్ సేవలు", "embeddedServicesSubtitle": "స్థానిక ప్రాక్సీ సేవలను నిర్వహించండి", "logs": "లాగ్లు", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index 8c8cfbd4a3d8..05f2cc3095dc 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "เปิดใช้เลนรับเข้าเสมือนแบบปรับตัวต่อเทนแนนต์สำหรับการส่งไปยังผู้ให้บริการ (#9654): การพุ่งสูงของเทนแนนต์หนึ่งจะไม่ทำให้อีกเทนแนนต์ได้รับ 503 อีกต่อไป ตัวแปรสภาพแวดล้อม OMNIROUTE_CHAT_VIRTUAL_LANES มีผลเหนือการตั้งค่าแดชบอร์ดนี้ การเปลี่ยนแปลงมีผลเมื่อรีสตาร์ทเซิร์ฟเวอร์", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "หน้าผู้ให้บริการในแดชบอร์ด: แสดงป้าย ฟรี เฉพาะสัญญาณที่ผู้ให้บริการรองรับเท่านั้น — เลิกใช้การอนุมานจากชื่อที่แสดง ฟิลด์ฟรีที่ไม่ใช่ค่าบูลีน และคำต่อท้าย :free สำหรับผู้ให้บริการที่ลงทะเบียนแต่ไม่มีระดับใช้งานฟรีที่ระบุไว้ในเอกสาร เมื่อปิด จะยังคงใช้กฎการแสดงป้ายแบบเดิม", "featureFlagProxySkipRecentlyFailedDescription": "พูลพร็อกซีและการหมุนเวียนต่อบัญชีของ opencode จะหยุดนำพร็อกซีที่เพิ่งล้มเหลว (ปฏิเสธการตรวจสอบ TCP หรือได้รับ 429 ผ่านพร็อกซีนั้น) กลับมาให้บริการซ้ำเป็นระยะเวลาต่อโปรเซส ซึ่งจะเพิ่มเป็นสองเท่าทุกครั้งที่เกิดซ้ำจนถึงขีดจำกัด โดยจะไม่มีการบันทึกสถานะพร็อกซี และหากตัวเลือกทั้งหมดถูกพักไว้ การเลือกจะไม่เปลี่ยนแปลง เปิดไว้โดยค่าเริ่มต้น โดย `false` จะคืนค่าการเลือกแบบปกติ", + "featureFlagProxyPoolSharedEgressOrderDescription": "สำหรับผู้ให้บริการที่มีการจัดสรรโควตาตาม egress address ระบบจะจัดลำดับสมาชิกในพูลที่ใช้ egress address เดียวกับสมาชิกที่เพิ่งถูกปฏิเสธให้อยู่ต่ำกว่าสมาชิกที่ทำงานปกติ เป็นเพียงการจัดลำดับเท่านั้น ไม่มีการคัดออก จำเป็นต้องมี PROXY_SKIP_RECENTLY_FAILED ซึ่งสร้างสัญญาณการปฏิเสธที่ระบบจะอ่าน ปิดใช้งานโดยค่าเริ่มต้น: ลำดับการเลือกจะเป็นไปตามการหมุนเวียนปกติอย่างแท้จริง", "featureFlagProxyPoolEgressObservationDescription": "แสดงใต้พูลพร็อกซีในแดชบอร์ดว่ามี IP ขาออกที่ตรวจพบกี่รายการซึ่งให้บริการสมาชิกของพูลในช่วง 24 h ที่ผ่านมา มีการเชื่อมต่อผ่าน IP เหล่านั้นกี่ครั้ง และจำนวนการเชื่อมต่อสูงสุดที่พบภายใต้ IP เดียว ข้อมูลนี้เป็นแบบอ่านอย่างเดียว คำนวณจากบันทึกพร็อกซี และไม่เคยนำไปใช้กำหนดเส้นทาง ปิดไว้โดยค่าเริ่มต้น: ตัวแก้ไขพูลจะไม่เปลี่ยนแปลง และเส้นทางการสังเกตการณ์จะตอบกลับเป็น null", "featureFlagProxyHealthBlockedResetsStreakDescription": "ในการกวาดตรวจสุขภาพพร็อกซี ให้การตรวจสอบที่ถูกเป้าหมายปฏิเสธ (401/403/429: พร็อกซีส่งต่อสำเร็จ แต่ปลายทางปฏิเสธ IP ขาออกนี้) รีเซ็ตจำนวนความล้มเหลวต่อเนื่องของพร็อกซีได้เช่นเดียวกับการตรวจสอบที่ให้บริการสำเร็จ ปิดไว้โดยค่าเริ่มต้น: การปฏิเสธจะยังคงเป็นกลางและคงจำนวนความล้มเหลวต่อเนื่องไว้ 5xx ยังคงถือว่าไม่สามารถสรุปผลได้ในทั้งสองกรณี และการปฏิเสธจะไม่ลบ ปิดใช้งาน หรือเปิดใช้งานพร็อกซีอีกครั้ง", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "อนุญาตให้การล้างข้อมูลอัตโนมัติลบงาน Batch API ที่อยู่ในสถานะสิ้นสุดแล้ว (เสร็จสิ้น/ล้มเหลว/ยกเลิก/หมดอายุ) ซึ่งเก่ากว่า OMNIROUTE_BATCH_RETENTION_DAYS พร้อมจุดตรวจสอบรายบรรทัดของงานเหล่านั้น และล้างเนื้อหา BLOB ของไฟล์ที่อัปโหลดซึ่งเลย expires_at ของไฟล์นั้นแล้ว ค่าเริ่มต้นคือปิด: การติดตั้งที่มีอยู่ทุกแห่งจะยังคงเก็บข้อมูลนี้ไว้เหมือนเดิมทุกประการจนกว่าผู้ดูแลระบบจะเลือกเปิดใช้ ไม่ว่าจะตั้งค่าอย่างไร เส้นทาง DELETE /api/v1/batches/delete-completed ที่ผู้ดูแลระบบเรียกใช้จะไม่ได้รับผลกระทบ เนื่องจากเป็นสัญญา API สาธารณะที่แยกต่างหากและทำงานโดยไม่มีเงื่อนไข", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "URL การเชื่อมต่อ AI ของคุณ", "apiManager": "ผู้จัดการ API", "apiManagerSubtitle": "จัดการคีย์ API และการเข้าถึง", + "modelCatalog": "โมเดลและคอมโบ", + "modelCatalogSubtitle": "เรียกดูโมเดลและคอมโบจากผู้ให้บริการต่างๆ", "embeddedServices": "บริการที่ฝังตัว", "embeddedServicesSubtitle": "จัดการบริการพร็อกซีในเครื่อง", "logs": "บันทึก", diff --git a/src/i18n/messages/tr.json b/src/i18n/messages/tr.json index bdefea8de70b..ec3277753df4 100644 --- a/src/i18n/messages/tr.json +++ b/src/i18n/messages/tr.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Sağlayıcı gönderimi için kiracı başına uyarlanabilir sanal kabul şeritlerini etkinleştirin (#9654): bir kiracının ani yükü artık diğerinde 503 hatasına neden olmaz. OMNIROUTE_CHAT_VIRTUAL_LANES ortam değişkeni bu panel ayarına göre önceliklidir; değişiklikler sunucu yeniden başlatıldığında geçerli olur.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Kontrol paneli sağlayıcı sayfaları: Ücretsiz rozetini yalnızca sağlayıcının dikkate aldığı sinyallere göre gösterir — belgelenmiş bir ücretsiz katmanı olmayan kayıtlı sağlayıcılarda görünen ad sezgisini, Boole türünde olmayan ücretsiz alanlarını ve :free son eklerini kullanmaz. Kapalı olduğunda geçmiş rozet kuralını korur.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy havuzları ve opencode'un hesap başına rotasyonu, henüz başarısız olmuş bir proxy'nin (reddedilen TCP yoklaması veya proxy üzerinden alınan 429 yanıtı) süreç başına belirlenen ve her tekrarda üst sınıra kadar iki katına çıkan bir süre boyunca yeniden kullanılmasını engeller. Proxy durumuna hiçbir şey yazılmaz; tüm adaylar kenara ayrıldığında seçim değişmeden kalır. Varsayılan olarak açıktır; `false` normal seçimi geri getirir.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Kotası çıkış adresine göre gruplandırılan sağlayıcılar için, yakın zamanda reddedilen bir üyenin gözlemlenen çıkış adresini paylaşan havuz üyesini sağlıklı üyelerin hemen altına yerleştirin. Yalnızca sıralamadır, asla hariç tutulmaz. Okuduğu ret sinyalini üreten PROXY_SKIP_RECENTLY_FAILED gerektirir. Varsayılan olarak kapalıdır: seçim sırası tamamen standart rotasyondur.", "featureFlagProxyPoolEgressObservationDescription": "Kontrol panelinde bir proxy havuzunun altında, son 24 saatte üyelerine kaç farklı gözlemlenen çıkış IP'sinin hizmet verdiğini, bunları kaç bağlantının kullandığını ve tek bir IP'nin arkasında en fazla kaç bağlantı görüldüğünü gösterir. Salt okunurdur, proxy günlüğünden hesaplanır ve yönlendirme için asla kullanılmaz. Varsayılan olarak kapalıdır: havuz düzenleyicisi değişmeden kalır ve gözlem rotası null yanıtını verir.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy sağlık taramasında, hedefin reddettiği bir yoklamanın (401/403/429: proxy isteği iletti, hedef bu çıkış IP'sini reddetti) proxy'nin ardışık başarısızlık serisini, başarıyla iletilen bir yoklamada olduğu gibi sıfırlamasını sağlar. Varsayılan olarak kapalıdır: bir ret nötr kalır ve seriyi korur. 5xx her iki durumda da sonuçsuz kalır ve bir ret hiçbir zaman proxy'yi kaldırmaz, devre dışı bırakmaz veya yeniden etkinleştirmez.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Otomatik temizleme işleminin, OMNIROUTE_BATCH_RETENTION_DAYS değerinden daha eski olan ve son duruma ulaşmış (tamamlanmış/başarısız/iptal edilmiş/süresi dolmuş) Batch API işlerini satır bazındaki kontrol noktalarıyla birlikte silmesine ve kendi expires_at sürelerini aşmış yüklenen dosyaların BLOB içeriğini temizlemesine izin verin. Varsayılan olarak kapalıdır: operatör etkinleştirene kadar mevcut tüm kurulumlar bu verileri aynen eskisi gibi saklar. Operatör tarafından tetiklenen DELETE /api/v1/batches/delete-completed rotası her iki durumda da etkilenmez; bu, ayrı ve koşulsuz bir genel API sözleşmesidir.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AI bağlantı URL'leriniz", "apiManager": "API Yöneticisi", "apiManagerSubtitle": "API anahtarlarını ve erişimi yönetin", + "modelCatalog": "Modeller ve Kombolar", + "modelCatalogSubtitle": "Sağlayıcılar genelinde modellere ve kombolara göz atın", "embeddedServices": "Gömülü Hizmetler", "embeddedServicesSubtitle": "Yerel proxy hizmetlerini yönetin", "logs": "Günlükler", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index cc596c09fc29..a24c7a0a0918 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Увімкніть адаптивні віртуальні смуги допуску для кожного тенанта під час надсилання провайдерам (#9654): сплеск навантаження одного тенанта більше не викликає 503 в іншого. Змінна середовища OMNIROUTE_CHAT_VIRTUAL_LANES має пріоритет над цим налаштуванням у панелі; зміни набувають чинності після перезапуску сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Сторінки провайдерів на панелі керування: показувати позначку «Безкоштовно» лише на підставі ознак, які підтримує провайдер. Це скасовує евристику на основі відображуваного імені, небулеві поля безкоштовності та суфікси :free для зареєстрованих провайдерів без документально підтвердженого безкоштовного рівня. Якщо вимкнено, використовується попереднє правило відображення позначки.", "featureFlagProxySkipRecentlyFailedDescription": "Пули проксі та ротація opencode для кожного облікового запису тимчасово припиняють повторно використовувати проксі, який щойно дав збій (відхилена перевірка TCP або отримана через нього відповідь 429), на період у межах процесу, що подвоюється після кожного повторного збою, аж до встановленої межі. Статус проксі не записується; якщо всі кандидати відкладені, вибір залишається незмінним. За замовчуванням увімкнено; `false` відновлює звичайний вибір.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Для провайдерів, чия квота групується за вихідною адресою, ранжувати учасника пулу зі спільною зафіксованою вихідною адресою нещодавно відхиленого учасника одразу під справними учасниками. Лише зміна порядку, без виключення. Потрібен PROXY_SKIP_RECENTLY_FAILED, який генерує сигнал відмови, що ним зчитується. За замовчуванням вимкнено: порядок вибору точно відповідає звичайній ротації.", "featureFlagProxyPoolEgressObservationDescription": "Показувати на інформаційній панелі під пулом проксі, скільки спостережуваних вихідних IP-адрес обслуговували його учасників протягом останніх 24 год, скільки з’єднань їх використовували та найбільшу кількість з’єднань через одну IP-адресу. Лише для читання, обчислюється з журналу проксі та ніколи не використовується для маршрутизації. За замовчуванням вимкнено: редактор пулу залишається без змін, а маршрут спостереження повертає null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Під час перевірки працездатності проксі дозволити перевірці, яку відхилила ціль (401/403/429: проксі передав запит, а місце призначення відхилило цю вихідну IP-адресу), скидати лічильник послідовних збоїв проксі, як у разі успішно обслугованої перевірки. За замовчуванням вимкнено: відмова залишається нейтральною та не скидає лічильник. Відповідь 5xx в обох випадках залишається невизначеною, а відмова ніколи не призводить до видалення, вимкнення чи повторної активації проксі.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Дозволити автоматичному очищенню видаляти завдання Batch API у кінцевому стані (завершені/невдалі/скасовані/прострочені), старші за OMNIROUTE_BATCH_RETENTION_DAYS, разом із їхніми контрольними точками для кожного рядка, а також очищати вміст BLOB завантажених файлів після настання їхнього власного expires_at. За замовчуванням вимкнено: кожна наявна інсталяція зберігатиме ці дані так само, як і раніше, доки оператор не ввімкне цю функцію. Маршрут DELETE /api/v1/batches/delete-completed, який запускає оператор, у будь-якому разі не змінюється — це окремий безумовний контракт публічного API.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Ваші URL-адреси підключення AI", "apiManager": "Менеджер API", "apiManagerSubtitle": "Керуйте ключами API та доступом", + "modelCatalog": "Моделі та комбо", + "modelCatalogSubtitle": "Переглядайте моделі та комбо від різних провайдерів", "embeddedServices": "Вбудовані сервіси", "embeddedServicesSubtitle": "Керування локальними проксі-сервісами", "logs": "Журнали", diff --git a/src/i18n/messages/ur.json b/src/i18n/messages/ur.json index 05a6ed248411..cea69885fda1 100644 --- a/src/i18n/messages/ur.json +++ b/src/i18n/messages/ur.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "پرووائیڈر بھیجنے کے لیے فی ٹیننٹ انکولی ورچوئل ایڈمیشن لین فعال کریں (#9654): ایک ٹیننٹ کا اچانک بوجھ اب دوسرے ٹیننٹ کو 503 نہیں دیتا۔ OMNIROUTE_CHAT_VIRTUAL_LANES ماحولیاتی متغیر اس ڈیش بورڈ سیٹنگ پر فوقیت رکھتا ہے؛ تبدیلیاں سرور دوبارہ شروع ہونے پر اثر انداز ہوتی ہیں۔", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ڈیش بورڈ کے فراہم کنندہ صفحات: مفت بیج صرف ان سگنلز پر دکھائیں جنہیں فراہم کنندہ تسلیم کرتا ہے — یہ ڈسپلے نام پر مبنی اندازے، غیر بولین مفت فیلڈز، اور دستاویزی مفت درجے کے بغیر رجسٹرڈ فراہم کنندگان پر :free لاحقوں کو نظر انداز کرتا ہے۔ غیر فعال کرنے پر تاریخی بیج کا اصول برقرار رہتا ہے۔", "featureFlagProxySkipRecentlyFailedDescription": "پراکسی پولز اور opencode کی فی اکاؤنٹ روٹیشن کسی ایسی پراکسی کو دوبارہ پیش کرنے سے عارضی طور پر روکتی ہے جو ابھی ناکام ہوئی ہو (TCP پروب مسترد ہوا ہو، یا اس کے ذریعے 429 موصول ہوا ہو)۔ یہ فی پروسیس مدت ہر بار ناکامی دہرائے جانے پر دگنی ہوتی ہے، ایک مقررہ حد تک۔ پراکسی کا کوئی اسٹیٹس نہیں لکھا جاتا؛ تمام امیدواروں کو ایک طرف رکھ دیے جانے کی صورت میں انتخاب میں کوئی تبدیلی نہیں آتی۔ بطور ڈیفالٹ فعال؛ `false` سادہ انتخاب بحال کرتا ہے۔", + "featureFlagProxyPoolSharedEgressOrderDescription": "ان فراہم کنندگان کے لیے جن کا کوٹہ egress ایڈریس کے لحاظ سے تقسیم کیا گیا ہے، پول کے ایسے رکن کو جو حال ہی میں مسترد کیے گئے رکن کے مشاہدہ کردہ egress ایڈریس کا اشتراک کرتا ہو، صحت مند ارکان سے بالکل نیچے درجہ دیں۔ صرف ترتیب، کبھی خارج نہیں کیا جاتا۔ PROXY_SKIP_RECENTLY_FAILED درکار ہے، جو مسترد ہونے کا وہ سگنل پیدا کرتا ہے جسے یہ پڑھتا ہے۔ ڈیفالٹ طور پر بند: انتخاب کی ترتیب بالکل سادہ روٹیشن جیسی ہوتی ہے۔", "featureFlagProxyPoolEgressObservationDescription": "ڈیش بورڈ میں کسی پراکسی پول کے تحت دکھائیں کہ گزشتہ 24 گھنٹوں کے دوران کتنے مشاہدہ شدہ ایگریس IPs نے اس کے اراکین کو سروس فراہم کی، کتنے کنکشنز نے انہیں استعمال کیا، اور ایک IP کے پیچھے سب سے زیادہ کتنے اراکین دیکھے گئے۔ صرف پڑھنے کے لیے، پراکسی لاگ سے شمار شدہ، اور روٹنگ کے لیے کبھی استعمال نہیں ہوتا۔ بطور ڈیفالٹ بند: پول ایڈیٹر میں کوئی تبدیلی نہیں ہوتی اور مشاہدے کا روٹ null واپس کرتا ہے۔", "featureFlagProxyHealthBlockedResetsStreakDescription": "پراکسی ہیلتھ سویپ میں، ہدف کی جانب سے مسترد کردہ پروب (401/403/429: پراکسی نے اسے آگے پہنچایا، مگر منزل نے اس ایگریس IP کو مسترد کر دیا) کو پراکسی کی مسلسل ناکامیوں کا سلسلہ اسی طرح ری سیٹ کرنے دیں جیسے پیش کیا گیا پروب کرتا ہے۔ بطور ڈیفالٹ بند: مسترد ہونا غیر جانب دار رہتا ہے اور سلسلے کو برقرار رکھتا ہے۔ 5xx دونوں صورتوں میں غیر فیصلہ کن رہتا ہے، اور مسترد ہونا کبھی بھی کسی پراکسی کو ہٹاتا، غیر فعال کرتا یا دوبارہ فعال نہیں کرتا۔", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "خودکار صفائی کے عمل کو OMNIROUTE_BATCH_RETENTION_DAYS سے زیادہ پرانی اختتامی حالت والی (مکمل/ناکام/منسوخ/میعاد ختم شدہ) Batch API جابز، ان کے ہر سطر کے چیک پوائنٹس سمیت، حذف کرنے دیں اور ان اپ لوڈ شدہ فائلوں کا BLOB مواد صاف کر دیں جن کی اپنی expires_at گزر چکی ہو۔ بطور ڈیفالٹ بند: آپریٹر کے فعال کرنے تک ہر موجودہ انسٹالیشن یہ ڈیٹا بالکل پہلے کی طرح برقرار رکھتی ہے۔ آپریٹر کی جانب سے شروع کیا جانے والا DELETE /api/v1/batches/delete-completed روٹ دونوں صورتوں میں غیر متاثر رہتا ہے — یہ ایک الگ، غیر مشروط عوامی API معاہدہ ہے۔", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "آپ کے AI کنکشن کے URLs", "apiManager": "API کلیدیں", "apiManagerSubtitle": "API کیز اور رسائی کا نظم کریں۔", + "modelCatalog": "ماڈلز اور کمبوز", + "modelCatalogSubtitle": "مختلف فراہم کنندگان میں ماڈلز اور کمبوز براؤز کریں", "embeddedServices": "ایمبیڈڈ سروسز", "embeddedServicesSubtitle": "مقامی پراکسی سروسز کا انتظام کریں", "logs": "لاگز", diff --git a/src/i18n/messages/uz.json b/src/i18n/messages/uz.json index 8cf1a1233e10..0154ddd60a9b 100644 --- a/src/i18n/messages/uz.json +++ b/src/i18n/messages/uz.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Provayderga joʻnatish uchun har bir ijarachiga moslashuvchan virtual qabul yoʻlaklarini yoqish (#9654): endi bir ijarachining keskin soʻrovlar oqimi boshqasida 503 xatosini keltirib chiqarmaydi. OMNIROUTE_CHAT_VIRTUAL_LANES muhit oʻzgaruvchisi boshqaruv panelidagi ushbu sozlamadan ustun turadi; oʻzgarishlar server qayta ishga tushirilganda kuchga kiradi.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Boshqaruv panelidagi provayder sahifalari: Bepul nishonini faqat provayder qo‘llab-quvvatlaydigan signallarda ko‘rsating — hujjatlashtirilgan bepul tarifi bo‘lmagan ro‘yxatdan o‘tgan provayderlar uchun ko‘rsatiladigan nomga asoslangan evristika, mantiqiy bo‘lmagan bepul maydonlar va :free suffikslari hisobga olinmaydi. O‘chirilsa, tarixiy nishon qoidasi saqlanadi.", "featureFlagProxySkipRecentlyFailedDescription": "Proksi-pullar va opencode’ning har bir hisob bo‘yicha aylantirish mexanizmi hozirgina ishlamay qolgan proksini (TCP tekshiruvini rad etgan yoki u orqali 429 javobi olingan) har bir jarayon uchun takroriy urinish sayin ikki baravar oshib, belgilangan chegaragacha yetadigan muddat davomida qayta taqdim etmaydi. Proksi holati yozib qo‘yilmaydi; barcha nomzodlar chetga surilsa, tanlov o‘zgarmaydi. Standart holatda yoqilgan; `false` oddiy tanlovni tiklaydi.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Kvotasi chiqish manzili boʻyicha taqsimlangan provayderlar uchun yaqinda rad etilgan aʼzoning kuzatilgan chiqish manziliga ega pul aʼzosini sogʻlom aʼzolardan sal pastroqqa joylashtirish. Faqat tartiblash, hech qachon chiqarib tashlanmaydi. U oʻqiydigan rad etish signalini hosil qiluvchi PROXY_SKIP_RECENTLY_FAILED talab etiladi. Standart holatda oʻchiq: tanlash tartibi aynan oddiy rotatsiyadir.", "featureFlagProxyPoolEgressObservationDescription": "Boshqaruv panelida proksi-pul ostida so‘nggi 24 soat ichida uning a’zolariga nechta kuzatilgan chiquvchi IP xizmat ko‘rsatgani, ulardan nechta ulanish foydalangani va bitta IP ortida eng ko‘p nechta a’zo kuzatilganini ko‘rsating. Faqat o‘qish uchun mo‘ljallangan, proksi jurnalidan hisoblanadi va yo‘naltirish uchun hech qachon ishlatilmaydi. Standart holatda o‘chiq: pul muharriri o‘zgarmaydi va kuzatuv marshruti null javobini qaytaradi.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proksi holatini tekshirish jarayonida maqsad rad etgan tekshiruv (401/403/429: proksi uzatdi, manzil esa ushbu chiquvchi IP’ni rad etdi) muvaffaqiyatli xizmat ko‘rsatilgan tekshiruv kabi proksining ketma-ket muvaffaqiyatsizliklar hisoblagichini tiklashiga ruxsat bering. Standart holatda o‘chiq: rad etish neytral bo‘lib qoladi va hisoblagichni saqlaydi. 5xx har ikki holatda ham noaniq bo‘lib qoladi, rad etish esa proksini hech qachon olib tashlamaydi, o‘chirib qo‘ymaydi yoki qayta faollashtirmaydi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Avtomatik tozalash jarayoniga OMNIROUTE_BATCH_RETENTION_DAYS muddatidan eski yakuniy holatdagi (completed/failed/cancelled/expired) Batch API vazifalarini ularning har bir qator uchun nazorat nuqtalari bilan birga oʻchirishga va oʻz expires_at muddatidan oʻtgan yuklangan fayllarning BLOB tarkibini tozalashga ruxsat bering. Odatiy holatda oʻchiq: operator bu imkoniyatni yoqmaguncha, barcha mavjud oʻrnatishlarda bu maʼlumotlar avvalgidek saqlanadi. Operator ishga tushiradigan DELETE /api/v1/batches/delete-completed marshrutiga bundan qatʼi nazar taʼsir qilinmaydi — u alohida, shartsiz ommaviy API shartnomasidir.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "AI ulanish URL manzillaringiz", "apiManager": "API kalitlari", "apiManagerSubtitle": "API kalitlari va kirishni boshqarish", + "modelCatalog": "Modellar va kombinatsiyalar", + "modelCatalogSubtitle": "Provayderlar boʻylab modellar va kombinatsiyalarni koʻrib chiqing", "embeddedServices": "Ichki xizmatlar", "embeddedServicesSubtitle": "Ixtiyoriy mahalliy xizmatlar", "logs": "Jurnallar", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index 6e7090670d15..98350ed8eb8f 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -1030,6 +1030,8 @@ "endpointsSubtitle": "URL kết nối AI của bạn", "apiManager": "Khóa API", "apiManagerSubtitle": "Quản lý khóa API và quyền truy cập", + "modelCatalog": "Mô hình & Combo", + "modelCatalogSubtitle": "Duyệt các mô hình và combo trên các nhà cung cấp", "embeddedServices": "Dịch vụ nhúng", "embeddedServicesSubtitle": "Quản lý các dịch vụ proxy cục bộ", "logs": "Nhật ký", @@ -11429,10 +11431,10 @@ "compressed": "Nén", "tps": "TPS", "duration": "Thời lượng", + "addedWait": "Thời gian chờ thêm", "time": "Thời gian", "conversation": "Cuộc trò chuyện", - "ttft": "TTFT", - "addedWait": "Thời gian chờ thêm" + "ttft": "TTFT" }, "loadingLogs": "Đang tải nhật ký...", "noLogs": "Chưa có nhật ký nào. Hãy thực hiện một số cuộc gọi API để xem chúng ở đây.", diff --git a/src/i18n/messages/yo.json b/src/i18n/messages/yo.json index 8adfc0eb27b4..50209be1deff 100644 --- a/src/i18n/messages/yo.json +++ b/src/i18n/messages/yo.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "Mú àwọn ọ̀nà ìgbàwọlé aláfojúṣe tí ń mú ara wọn bá ipò mu fún tenant kọ̀ọ̀kan ṣiṣẹ́ fún provider dispatch (#9654): ìrujáde tenant kan kò ní fa 503 fún tenant mìíràn mọ́. env var OMNIROUTE_CHAT_VIRTUAL_LANES ni ó ṣáájú àtúnṣe dashboard yìí; àwọn ìyípadà yóò bẹ̀rẹ̀ sí í ṣiṣẹ́ nígbà tí server bá tún bẹ̀rẹ̀.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Àwọn ojú-ìwé olùpèsè lórí Dashboard: fi báàjì Ọ̀fẹ́ hàn lórí àwọn àmì tí olùpèsè náà fọwọ́ sí nìkan — èyí yọ ọ̀nà ìfojúrí orúkọ ìfihàn, àwọn ààyè ọ̀fẹ́ tí kì í ṣe Boolean àti àwọn ìparí :free kúrò lórí àwọn olùpèsè tí a forúkọsílẹ̀ tí kò ní ipele ọ̀fẹ́ tí a ṣàkọsílẹ̀. Pípa rẹ̀ yóò pa òfin báàjì ìṣáájú mọ́.", "featureFlagProxySkipRecentlyFailedDescription": "Àwọn àkójọpọ̀ proxy àti yíyí opencode fún àkọọ́lẹ̀ kọ̀ọ̀kan máa ń dáwọ́ lílo proxy kan tí ó ṣẹ̀ṣẹ̀ kùnà dúró (ìdánwò TCP tí a kọ̀, tàbí 429 tí a gbà nípasẹ̀ rẹ̀) fún àkókò kan nínú process kọ̀ọ̀kan, èyí tí yóò di ìlọ́po méjì ní gbogbo ìgbà tí ó tún ṣẹlẹ̀, títí dé òpin tí a yàn. A kì í kọ ipò proxy sílẹ̀; bí a bá fi gbogbo olùdíje sí ẹ̀gbẹ́ kan, yíyan náà kì í yí padà. Ó wà ní títàn ní àkọ́kọ́; `false` máa ń dá yíyan lasán padà.", + "featureFlagProxyPoolSharedEgressOrderDescription": "Fún àwọn olùpèsè tí kótà wọn jẹ́ pípín nípasẹ̀ àdírẹ́sì egress, fi ọmọ ẹgbẹ́ pool tí ó ń pín àdírẹ́sì egress tí a kíyèsí ti ọmọ ẹgbẹ́ tí a kọ̀ láìpẹ́ sí abẹ́ àwọn ọmọ ẹgbẹ́ tí ó dára díẹ̀. Àtòjọ nìkan, a kì í yọ ọ́ kúrò láéláé. Nílò PROXY_SKIP_RECENTLY_FAILED, èyí tí ń mú àmì ìkọ̀sílẹ̀ tí ó ń kà jáde. Kò ṣiṣẹ́ ní àkọ́kọ́: àtòjọ yíyàn jẹ́ ìyípo lásán gangan.", "featureFlagProxyPoolEgressObservationDescription": "Ṣàfihàn, lábẹ́ àkójọpọ̀ proxy kan nínú dashboard, iye àwọn IP egress tí a ṣàkíyèsí tí ó ṣiṣẹ́ fún àwọn ọmọ ẹgbẹ́ rẹ̀ láàárín wákàtí 24 tó kọjá, iye àwọn ìsopọ̀ tí ó lò wọ́n àti iye tó pọ̀ jù tí a rí lẹ́yìn IP kan. Fún kíkà nìkan, a ṣírò rẹ̀ láti inú àkọsílẹ̀ proxy, a kò sì lò ó fún routing láé. Ó wà ní pípa ní àkọ́kọ́: olóòtú àkójọpọ̀ náà kò yí padà, ipa-ọ̀nà àkíyèsí sì ń dá null padà.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Nínú àyẹ̀wò ìlera proxy, jẹ́ kí ìdánwò kan tí ibi àfojúsùn kọ̀ (401/403/429: proxy náà gbé e dé, ibi àfojúsùn sì kọ IP egress yìí) tún iye àwọn ìkùnà tẹ̀léra ti proxy náà bẹ̀rẹ̀, bí ìdánwò tí a dáhùn sí. Ó wà ní pípa ní àkọ́kọ́: ìkọ̀ kan ṣì jẹ́ aláìdásí, ó sì ń pa iye tẹ̀léra náà mọ́. 5xx ṣì jẹ́ aláìdánilójú lọ́nà méjèèjì, ìkọ̀ kò sì lè yọ proxy kan kúrò, mú un má ṣiṣẹ́, tàbí tún mú un ṣiṣẹ́ láé.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Jẹ́ kí ìfọ̀mọ́ aládàáṣe pa àwọn iṣẹ́ Batch API tó ti dé òpin (tó parí/tó kùnà/tí a fagilé/tó kọjá àkókò) tí ọjọ́ orí wọn ti ju OMNIROUTE_BATCH_RETENTION_DAYS lọ, pẹ̀lú àwọn ibi ìṣàyẹ̀wò wọn fún ìlà kọ̀ọ̀kan, kí ó sì pa àkóónú BLOB àwọn fáìlì tí a ti rù sókè tí wọ́n ti kọjá expires_at tiwọn. A pa á ní àkọ́kọ́: gbogbo ìfìdásílẹ̀ tó wà tẹ́lẹ̀ yóò pa dátà yìí mọ́ gẹ́gẹ́ bí ó ti rí tẹ́lẹ̀ títí olùṣàkóso yóò fi yàn láti tan án. Ọ̀nà DELETE /api/v1/batches/delete-completed tí olùṣàkóso ń ṣiṣẹ́ kò ní ipa lọ́nàkọnà — ó jẹ́ àdéhùn API gbogbogbò tó yàtọ̀, tí kò gbára lé ipò kankan.", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "Àwọn URL àsopọ̀ AI rẹ", "apiManager": "Àwọn Kọ́kọ́rọ́ API", "apiManagerSubtitle": "Ṣàkóso àwọn kọ́kọ́rọ́ API àti ìráàyèsí", + "modelCatalog": "Àwọn Mọ́dẹ́lì & Àkójọpọ̀", + "modelCatalogSubtitle": "Ṣàwárí àwọn mọ́dẹ́lì àti àkójọpọ̀ kọjá àwọn olùpèsè", "embeddedServices": "Àwọn Iṣẹ́ Tí a Fi Sínú", "embeddedServicesSubtitle": "Àwọn iṣẹ́ abẹ́lé àṣàyàn", "logs": "Àwọn Àkọsílẹ̀", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index a91265350807..28f5a066c4a5 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "为提供者调度启用按租户的自适应虚拟准入通道(#9654):一个租户的突发流量不再导致另一个租户收到 503。OMNIROUTE_CHAT_VIRTUAL_LANES 环境变量优先于此仪表板设置;更改在服务器重启后生效。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "控制面板提供者页面:仅根据提供者认可的信号显示“免费”徽章——对于没有文档说明免费层级的已注册提供者,不再使用显示名称启发式规则、非布尔型免费字段和 :free 后缀。关闭时沿用旧版徽章规则。", "featureFlagProxySkipRecentlyFailedDescription": "代理池和 opencode 的按账户轮换会在每个进程的一段时间内,停止再次提供刚刚失败的代理(TCP 探测被拒绝,或通过该代理收到 429)。每次重复失败时,该时段都会翻倍,直至达到上限。不会写入代理状态;当所有候选代理都被暂时搁置时,选择保持不变。默认开启;设为 `false` 可恢复普通选择。", + "featureFlagProxyPoolSharedEgressOrderDescription": "对于配额按出口地址分桶的提供商,将与最近被拒绝成员共享相同观测出口地址的池成员排在健康成员之后。仅调整排序,绝不排除。需要 PROXY_SKIP_RECENTLY_FAILED,由其生成此功能所读取的拒绝信号。默认关闭:选择顺序完全遵循常规轮询。", "featureFlagProxyPoolEgressObservationDescription": "在仪表板的代理池下显示:过去 24 小时内观察到多少个出口 IP 为其成员提供服务、使用这些 IP 的连接数,以及单个 IP 对应的最大连接数。此信息为只读,根据代理日志计算,绝不用于路由。默认关闭:代理池编辑器保持不变,观测路由返回 null。", "featureFlagProxyHealthBlockedResetsStreakDescription": "在代理健康检查中,如果探测被目标拒绝(401/403/429:代理已转发,但目标拒绝了此出口 IP),则像探测成功一样重置代理的连续失败计数。默认关闭:拒绝保持中性,并保留当前连续失败计数。无论如何,5xx 均保持结果不确定,而且拒绝绝不会导致代理被移除、禁用或重新激活。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "允许自动清理任务删除早于 OMNIROUTE_BATCH_RETENTION_DAYS 的终态(已完成/失败/已取消/已过期)Batch API 作业及其逐行检查点,并清除超过各自 expires_at 的已上传文件的 BLOB 内容。默认关闭:在运维人员选择启用之前,所有现有安装都将继续像以前一样保留这些数据。无论是否启用,运维人员触发的 DELETE /api/v1/batches/delete-completed 路由均不受影响——它是一个独立且无条件执行的公共 API 契约。", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "您的 AI 连接 URL", "apiManager": "API 管理", "apiManagerSubtitle": "管理 API 密钥和访问", + "modelCatalog": "模型与组合", + "modelCatalogSubtitle": "浏览各提供商的模型和组合", "embeddedServices": "内嵌服务", "embeddedServicesSubtitle": "管理本地代理服务", "logs": "日志", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 872918cca631..9d0425102289 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -994,6 +994,7 @@ "featureFlagChatVirtualLanesEnabledDescription": "為提供者調度啟用按租戶的自適應虛擬准入通道(#9654):一個租戶的突發流量不再導致另一個租戶收到 503。OMNIROUTE_CHAT_VIRTUAL_LANES 環境變數優先於此儀表板設定;變更在伺服器重新啟動後生效。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "儀表板提供者頁面:僅根據提供者明確認可的訊號顯示「免費」徽章——不再對沒有文件說明免費方案的已註冊提供者使用顯示名稱啟發法、非布林值免費欄位及 :free 後綴。關閉時會沿用過往的徽章規則。", "featureFlagProxySkipRecentlyFailedDescription": "Proxy 集區以及 opencode 的每帳戶輪替機制,會在每個處理程序的一段期間內,停止再次使用剛失敗的 Proxy(TCP 探測遭拒,或透過該 Proxy 收到 429)。每次重複失敗時,這段期間都會加倍,直到達到上限。不會寫入任何 Proxy 狀態;即使所有候選項目都被暫時擱置,選擇結果仍維持不變。預設開啟;設為 `false` 可恢復一般選擇。", + "featureFlagProxyPoolSharedEgressOrderDescription": "對於配額依出口位址劃分的提供者,將與近期遭拒成員共用所觀測出口位址的集區成員排在健康成員之後。僅調整順序,絕不排除。需要 PROXY_SKIP_RECENTLY_FAILED,由其產生所讀取的拒絕信號。預設為關閉:選取順序完全為一般的輪替。", "featureFlagProxyPoolEgressObservationDescription": "在儀表板的 Proxy 集區下方,顯示過去 24 小時內觀察到多少個出口 IP 為其成員提供服務、使用這些 IP 的連線數,以及單一 IP 後方觀察到的最高數量。唯讀,根據 Proxy 記錄計算,絕不會用於路由。預設關閉:集區編輯器維持不變,觀察路由會回傳 null。", "featureFlagProxyHealthBlockedResetsStreakDescription": "在 Proxy 健康狀態掃描中,讓遭目標拒絕的探測(401/403/429:Proxy 已轉送,但目的地拒絕此出口 IP)能像已提供服務的探測一樣,重設 Proxy 的連續失敗次數。預設關閉:拒絕仍視為中性,並保留目前的連續失敗次數。無論此設定為何,5xx 仍視為無法判定,而且拒絕絕不會移除、停用或重新啟用 Proxy。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "允許自動清理程序刪除早於 OMNIROUTE_BATCH_RETENTION_DAYS 且處於最終狀態(已完成/失敗/已取消/已過期)的 Batch API 作業及其逐行檢查點,並清除已超過各自 expires_at 的上傳檔案 BLOB 內容。預設關閉:在操作員選擇啟用前,所有現有安裝都會完全比照以往保留這些資料。無論是否啟用,操作員觸發的 DELETE /api/v1/batches/delete-completed 路由都不受影響——它是獨立且無條件的公開 API 合約。", @@ -1029,6 +1030,8 @@ "endpointsSubtitle": "您的 AI 連線 URL", "apiManager": "API 管理", "apiManagerSubtitle": "管理 API 金鑰和訪問", + "modelCatalog": "模型與組合", + "modelCatalogSubtitle": "瀏覽各提供者的模型與組合", "embeddedServices": "內嵌服務", "embeddedServicesSubtitle": "管理本地代理服務", "logs": "日誌", From b5206a1dc3fcaaba8f39f27baeb72e39f38b44cb Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 15:24:59 +0300 Subject: [PATCH 03/16] i18n(dashboard): translate every models and combos catalog label --- .../dashboard/models/CatalogBulkActionBar.tsx | 10 +- .../dashboard/models/CatalogTestBadge.tsx | 43 ++++---- .../dashboard/models/ComboCatalogFilters.tsx | 43 ++++---- .../dashboard/models/ComboCatalogTable.tsx | 51 +++++---- .../dashboard/models/ModelCatalogFilters.tsx | 61 +++++----- .../dashboard/models/ModelCatalogTable.tsx | 65 +++++------ src/app/(dashboard)/dashboard/models/page.tsx | 91 +++++++-------- src/i18n/messages/am.json | 104 +++++++++++++++++- src/i18n/messages/ar.json | 104 +++++++++++++++++- src/i18n/messages/az.json | 104 +++++++++++++++++- src/i18n/messages/bg.json | 104 +++++++++++++++++- src/i18n/messages/bn.json | 104 +++++++++++++++++- src/i18n/messages/bs.json | 104 +++++++++++++++++- src/i18n/messages/cs.json | 104 +++++++++++++++++- src/i18n/messages/da.json | 104 +++++++++++++++++- src/i18n/messages/de.json | 104 +++++++++++++++++- src/i18n/messages/el.json | 104 +++++++++++++++++- src/i18n/messages/en.json | 103 +++++++++++++++++ src/i18n/messages/es.json | 104 +++++++++++++++++- src/i18n/messages/et.json | 104 +++++++++++++++++- src/i18n/messages/fa.json | 104 +++++++++++++++++- src/i18n/messages/fi.json | 104 +++++++++++++++++- src/i18n/messages/fr.json | 104 +++++++++++++++++- src/i18n/messages/ga.json | 104 +++++++++++++++++- src/i18n/messages/gu.json | 104 +++++++++++++++++- src/i18n/messages/ha.json | 104 +++++++++++++++++- src/i18n/messages/he.json | 104 +++++++++++++++++- src/i18n/messages/hi.json | 104 +++++++++++++++++- src/i18n/messages/hr.json | 104 +++++++++++++++++- src/i18n/messages/hu.json | 104 +++++++++++++++++- src/i18n/messages/hy.json | 104 +++++++++++++++++- src/i18n/messages/id.json | 104 +++++++++++++++++- src/i18n/messages/ig.json | 104 +++++++++++++++++- src/i18n/messages/it.json | 104 +++++++++++++++++- src/i18n/messages/ja.json | 104 +++++++++++++++++- src/i18n/messages/ka.json | 104 +++++++++++++++++- src/i18n/messages/km.json | 104 +++++++++++++++++- src/i18n/messages/kn.json | 104 +++++++++++++++++- src/i18n/messages/ko.json | 104 +++++++++++++++++- src/i18n/messages/lt.json | 104 +++++++++++++++++- src/i18n/messages/lv.json | 104 +++++++++++++++++- src/i18n/messages/ml.json | 104 +++++++++++++++++- src/i18n/messages/mr.json | 104 +++++++++++++++++- src/i18n/messages/ms.json | 104 +++++++++++++++++- src/i18n/messages/mt.json | 104 +++++++++++++++++- src/i18n/messages/my.json | 104 +++++++++++++++++- src/i18n/messages/ne.json | 104 +++++++++++++++++- src/i18n/messages/nl.json | 104 +++++++++++++++++- src/i18n/messages/no.json | 104 +++++++++++++++++- src/i18n/messages/or.json | 104 +++++++++++++++++- src/i18n/messages/pa.json | 104 +++++++++++++++++- src/i18n/messages/phi.json | 104 +++++++++++++++++- src/i18n/messages/pl.json | 104 +++++++++++++++++- src/i18n/messages/pt-BR.json | 104 +++++++++++++++++- src/i18n/messages/pt.json | 104 +++++++++++++++++- src/i18n/messages/ro.json | 104 +++++++++++++++++- src/i18n/messages/ru.json | 104 +++++++++++++++++- src/i18n/messages/si.json | 104 +++++++++++++++++- src/i18n/messages/sk.json | 104 +++++++++++++++++- src/i18n/messages/sl.json | 104 +++++++++++++++++- src/i18n/messages/sr.json | 104 +++++++++++++++++- src/i18n/messages/sv.json | 104 +++++++++++++++++- src/i18n/messages/sw.json | 104 +++++++++++++++++- src/i18n/messages/ta.json | 104 +++++++++++++++++- src/i18n/messages/te.json | 104 +++++++++++++++++- src/i18n/messages/th.json | 104 +++++++++++++++++- src/i18n/messages/tr.json | 104 +++++++++++++++++- src/i18n/messages/uk-UA.json | 104 +++++++++++++++++- src/i18n/messages/ur.json | 104 +++++++++++++++++- src/i18n/messages/uz.json | 104 +++++++++++++++++- src/i18n/messages/vi.json | 103 +++++++++++++++++ src/i18n/messages/yo.json | 104 +++++++++++++++++- src/i18n/messages/zh-CN.json | 104 +++++++++++++++++- src/i18n/messages/zh-TW.json | 104 +++++++++++++++++- .../unit/dashboard/modelCatalogPage.test.tsx | 17 ++- .../dashboard/modelsCombosCatalog.test.tsx | 17 ++- 76 files changed, 7119 insertions(+), 245 deletions(-) diff --git a/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx index 56508db69fc0..6a025cee225b 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslations } from "next-intl"; import { Button } from "@/shared/components"; import type { ProgressState } from "./useCatalogTestRunner"; @@ -26,6 +27,7 @@ export default function CatalogBulkActionBar({ onClearResults: () => void; entityLabel?: "models" | "combos"; }) { + const t = useTranslations("modelCatalog"); const percent = progress.total > 0 ? Math.round((progress.completed / progress.total) * 100) : 0; return ( @@ -38,7 +40,7 @@ export default function CatalogBulkActionBar({ onClick={onTestSelected} data-testid="test-selected-btn" > - {`Test selected (${selectedCount})`} + {t("testSelected", { count: selectedCount })} {running && ( )} @@ -63,7 +65,7 @@ export default function CatalogBulkActionBar({ onClick={onClearResults} data-testid="clear-test-results-btn" > - Clear results + {t("clearResults")} )} diff --git a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx index 3050aec1c029..239d775bd07b 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslations } from "next-intl"; import { Badge } from "@/shared/components"; import type { CatalogTestResult } from "./catalogTestStorage"; @@ -9,15 +10,16 @@ function formatLatency(ms?: number): string { return `${(ms / 1000).toFixed(1)}s`; } -function formatTimeAgo(timestamp?: number): string { +function formatTestTime(timestamp?: number): string { if (!timestamp) return ""; - const diffSec = Math.floor((Date.now() - timestamp) / 1000); - if (diffSec < 60) return "Just now"; - const diffMin = Math.floor(diffSec / 60); - if (diffMin < 60) return `${diffMin}m ago`; - const diffHours = Math.floor(diffMin / 60); - if (diffHours < 24) return `${diffHours}h ago`; - return new Date(timestamp).toLocaleDateString(); + try { + return new Date(timestamp).toLocaleTimeString([], { + hour: "2-digit", + minute: "2-digit", + }); + } catch { + return ""; + } } export default function CatalogTestBadge({ @@ -27,6 +29,8 @@ export default function CatalogTestBadge({ result?: CatalogTestResult; loading?: boolean; }) { + const t = useTranslations("modelCatalog"); + if (loading) { return (
@@ -34,14 +38,14 @@ export default function CatalogTestBadge({ className="inline-block size-3 animate-spin rounded-full border-2 border-primary border-t-transparent" aria-hidden="true" /> - Testing... + {t("testing")}
); } if (!result) { return ( - + — ); @@ -50,17 +54,18 @@ export default function CatalogTestBadge({ const variant = result.status === "ok" ? "success" : result.status === "slow" ? "warning" : "error"; - const label = - result.status === "ok" - ? "OK" - : result.status === "slow" - ? "Slow" - : result.errorClass - ? result.errorClass.replace("-", " ") - : "Error"; + const getLabel = () => { + if (result.status === "ok") return t("statusOk"); + if (result.status === "slow") return t("statusSlow"); + if (result.errorClass === "rate-limited") return t("rateLimited"); + if (result.errorClass === "quota") return t("quotaExceeded"); + if (result.errorClass === "timeout") return t("timeout"); + return t("otherError"); + }; + const label = getLabel(); const latencyStr = formatLatency(result.latencyMs); - const timeStr = formatTimeAgo(result.testedAt); + const timeStr = formatTestTime(result.testedAt); return (
onChange({ query: event.target.value })} className="min-w-0 flex-1" @@ -39,11 +42,11 @@ export default function ComboCatalogFiltersComponent({
- {totalCount} {totalCount === 1 ? "combo" : "combos"} + {totalCount} {totalCount === 1 ? t("comboCountSingle") : t("comboCountPlural")} {hasActiveFilters && ( )}
@@ -51,13 +54,13 @@ export default function ComboCatalogFiltersComponent({
Model catalog across all providers
+ { + if (el) el.indeterminate = someOnPageSelected; + }} + onChange={onToggleSelectAll} + aria-label="Select all models on this page" + className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" + /> + + Health Test + + Actions +
+ onToggleSelect(rowId)} + aria-label={`Select model ${model.name}`} + className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" + /> + - {model.provider} +
+ {model.provider} + {providerHealth && providerHealth !== "healthy" && ( + + {providerHealth} + + )} +
{model.providerId} @@ -246,6 +326,22 @@ export default function ModelCatalogTable({ )}
+ + + +
- + - Health Test + {t("healthTest")} @@ -174,7 +181,7 @@ export default function ComboCatalogTable({ type="checkbox" checked={isSelected} onChange={() => onToggleSelect(combo.id)} - aria-label={`Select combo ${combo.name}`} + aria-label={t("selectCombo", { name: combo.name })} className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" /> @@ -196,7 +203,8 @@ export default function ComboCatalogTable({ @@ -245,18 +253,19 @@ export default function ComboCatalogTable({

- Showing {formatCount(firstResult)}–{formatCount(lastResult)} of {formatCount(totalCount)} - {" combos"} + {t("showingCombos", { + first: formatCount(firstResult), + last: formatCount(lastResult), + total: formatCount(totalCount), + })}

- - Page {page} of {pageCount} - + {t("page", { page, pageCount })}
diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx index c3465885199b..e579c025d61d 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslations } from "next-intl"; import { Button, Input } from "@/shared/components"; import type { CatalogFilters } from "./modelCatalogUtils"; @@ -31,13 +32,15 @@ export default function ModelCatalogFiltersComponent({ hasActiveFilters: boolean; totalCount: number; }) { + const t = useTranslations("modelCatalog"); + return (
onChange({ query: event.target.value })} className="min-w-0 flex-1" @@ -45,11 +48,11 @@ export default function ModelCatalogFiltersComponent({
- {totalCount} {totalCount === 1 ? "model" : "models"} + {totalCount} {totalCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} {hasActiveFilters && ( )}
@@ -57,13 +60,13 @@ export default function ModelCatalogFiltersComponent({
Combos catalog with health test results{t("combosTableCaption")}
@@ -109,34 +116,34 @@ export default function ComboCatalogTable({ if (el) el.indeterminate = someOnPageSelected; }} onChange={onToggleSelectAll} - aria-label="Select all combos on this page" + aria-label={t("selectAllCombos")} className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" /> - Actions + {t("actions")}
- {combo.memberCount} {combo.memberCount === 1 ? "model" : "models"} + {combo.memberCount}{" "} + {combo.memberCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} {combo.models.length > 0 && (
@@ -211,7 +219,7 @@ export default function ComboCatalogTable({ ))} {combo.models.length > 3 && ( - +{combo.models.length - 3} more + {t("moreMembers", { count: combo.models.length - 3 })} )}
@@ -219,7 +227,7 @@ export default function ComboCatalogTable({
- {combo.status === "active" ? "Active" : "Paused"} + {combo.status === "active" ? t("active") : t("paused")} @@ -233,7 +241,7 @@ export default function ComboCatalogTable({ onClick={() => onTestCombo(combo.name)} data-testid={`test-combo-${combo.name}`} > - Test + {t("test")}
- + {onToggleSelectAll && ( @@ -145,28 +149,28 @@ export default function ModelCatalogTable({ if (el) el.indeterminate = someOnPageSelected; }} onChange={onToggleSelectAll} - aria-label="Select all models on this page" + aria-label={t("selectAllModels")} className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" /> )} - {labels.capabilities} + {labels.capabilities || t("capabilities")} - {labels.flags} + {labels.flags || t("flags")} {onTestModel && ( )} @@ -237,7 +241,7 @@ export default function ModelCatalogTable({ type="checkbox" checked={isSelected} onChange={() => onToggleSelect(rowId)} - aria-label={`Select model ${model.name}`} + aria-label={t("selectModel", { name: model.name })} className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" /> @@ -251,7 +255,7 @@ export default function ModelCatalogTable({ variant={providerHealth === "degraded" ? "warning" : "error"} dot > - {providerHealth} + {providerHealth === "degraded" ? t("degraded") : t("down")} )} @@ -296,7 +300,7 @@ export default function ModelCatalogTable({ )} ) : ( - + — )} @@ -311,16 +315,16 @@ export default function ModelCatalogTable({
{model.custom === true && ( - {labels.custom} + {labels.custom || t("custom")} )} {model.free === true && ( - {labels.free} + {labels.free || t("free")} )} {model.custom !== true && model.free !== true && ( - + — )} @@ -338,7 +342,7 @@ export default function ModelCatalogTable({ onClick={() => onTestModel(model.providerId, model.id)} data-testid={`test-model-${model.id}`} > - Test + {t("test")} )} @@ -351,24 +355,21 @@ export default function ModelCatalogTable({

- Showing {formatCount(firstResult)}–{formatCount(lastResult)} of {formatCount(totalCount)} - {" models"} - {loading && Refreshing…} - {error && ( - - Refresh failed. Showing the last loaded catalog. - - )} + {t("showingModels", { + first: formatCount(firstResult), + last: formatCount(lastResult), + total: formatCount(totalCount), + })} + {loading && {t("refreshing")}} + {error && {t("refreshFailed")}}

- - Page {page} of {pageCount} - + {t("page", { page, pageCount })}
diff --git a/src/app/(dashboard)/dashboard/models/page.tsx b/src/app/(dashboard)/dashboard/models/page.tsx index 6cadfa06949a..946db619fbde 100644 --- a/src/app/(dashboard)/dashboard/models/page.tsx +++ b/src/app/(dashboard)/dashboard/models/page.tsx @@ -34,12 +34,6 @@ import { useCatalogTestRunner } from "./useCatalogTestRunner"; const PAGE_SIZE = 50; -type Translator = ((key: string) => string) & { has?: (key: string) => boolean }; - -function commonText(translator: Translator, key: string, fallback: string): string { - return typeof translator.has === "function" && translator.has(key) ? translator(key) : fallback; -} - type CatalogTab = "models" | "combos"; function getUrlParams(): URLSearchParams { @@ -89,7 +83,7 @@ function parseInitialComboFilters( } export default function ModelCatalogPage() { - const commonTranslator = useTranslations("common") as unknown as Translator; + const t = useTranslations("modelCatalog"); // Active Tab const [activeTab, setActiveTab] = useState(() => { @@ -177,26 +171,33 @@ export default function ModelCatalogPage() { if (mFilters.providerId !== "all") params.set("provider", mFilters.providerId); if (mFilters.type !== "all") params.set("type", mFilters.type); if (mFilters.subtype && mFilters.subtype !== "all") params.set("subtype", mFilters.subtype); - if (mFilters.capability && mFilters.capability !== "all") + if (mFilters.capability && mFilters.capability !== "all") { params.set("capability", mFilters.capability); + } if (mFilters.pricing && mFilters.pricing !== "all") params.set("pricing", mFilters.pricing); - if (mFilters.providerHealth && mFilters.providerHealth !== "all") + if (mFilters.providerHealth && mFilters.providerHealth !== "all") { params.set("health", mFilters.providerHealth); - if (mFilters.testResult && mFilters.testResult !== "all") + } + if (mFilters.testResult && mFilters.testResult !== "all") { params.set("testResult", mFilters.testResult); - if (typeof mFilters.minContextLength === "number") + } + if (typeof mFilters.minContextLength === "number") { params.set("minContext", String(mFilters.minContextLength)); - if (typeof mFilters.minMaxOutputTokens === "number") + } + if (typeof mFilters.minMaxOutputTokens === "number") { params.set("minOutput", String(mFilters.minMaxOutputTokens)); + } } else { if (cFilters.query) params.set("query", cFilters.query); if (cFilters.strategy !== "all") params.set("strategy", cFilters.strategy); if (cFilters.status !== "all") params.set("status", cFilters.status); if (cFilters.testResult !== "all") params.set("testResult", cFilters.testResult); - if (typeof cFilters.minMembers === "number") + if (typeof cFilters.minMembers === "number") { params.set("minMembers", String(cFilters.minMembers)); - if (typeof cFilters.maxMembers === "number") + } + if (typeof cFilters.maxMembers === "number") { params.set("maxMembers", String(cFilters.maxMembers)); + } } setUrlParams(params); @@ -485,17 +486,13 @@ export default function ModelCatalogPage() { const hasTestResults = Object.keys(testResults).length > 0; - const text = (key: string, fallback: string) => commonText(commonTranslator, key, fallback); - return (
-

Models & Combos

-

- Browse and health-test models and combo routing pipelines across every provider. -

+

{t("title")}

+

{t("subtitle")}

{/* Tab Navigation */}
@@ -586,17 +583,17 @@ export default function ModelCatalogPage() { aria-live="polite" className="flex min-h-64 items-center justify-center p-8 text-sm text-text-muted" > - {text("loading", "Loading...")} + {t("loading")}
) : modelsError && models.length === 0 ? (
-

Unable to load the model catalog.

-

Check the connection and try again.

+

{t("unableToLoad")}

+

{t("checkConnection")}

) : visibleModels.length === 0 ? ( @@ -608,13 +605,11 @@ export default function ModelCatalogPage() { search_off

- {models.length === 0 - ? text("noModelsFound", "No models are available yet.") - : "No models match these filters."} + {models.length === 0 ? t("noModelsAvailable") : t("noModelsMatch")}

{models.length > 0 && ( )}
@@ -643,15 +638,15 @@ export default function ModelCatalogPage() { setRequestedModelPage((c) => Math.min(modelPage.pageCount - 1, c + 1)) } labels={{ - provider: text("provider", "Provider"), - model: text("model", "Model"), - type: text("type", "Type"), - capabilities: "Capabilities", - context: "Context", - output: text("output", "Max output"), - flags: "Flags", - custom: text("custom", "Custom"), - free: text("free", "Free"), + provider: t("provider"), + model: t("model"), + type: t("type"), + capabilities: t("capabilities"), + context: t("context"), + output: t("output"), + flags: t("flags"), + custom: t("custom"), + free: t("free"), }} selectedIds={selectedModelIds} onToggleSelect={toggleSelectModel} @@ -703,17 +698,17 @@ export default function ModelCatalogPage() { aria-live="polite" className="flex min-h-64 items-center justify-center p-8 text-sm text-text-muted" > - {text("loading", "Loading...")} + {t("loading")} ) : combosError && combos.length === 0 ? (
-

Unable to load combos.

-

Check the connection and try again.

+

{t("unableToLoadCombos")}

+

{t("checkConnection")}

) : visibleCombos.length === 0 ? ( @@ -725,13 +720,11 @@ export default function ModelCatalogPage() { search_off

- {combos.length === 0 - ? "No combos are available yet." - : "No combos match these filters."} + {combos.length === 0 ? t("noCombosAvailable") : t("noCombosMatch")}

{combos.length > 0 && ( )} diff --git a/src/i18n/messages/am.json b/src/i18n/messages/am.json index 87a52e75f2f2..1538a5d3a22f 100644 --- a/src/i18n/messages/am.json +++ b/src/i18n/messages/am.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ለአቅራቢ ማሰራጨት በተከራይ ደረጃ የሚላመዱ ምናባዊ የመቀበያ መስመሮችን ያንቁ (#9654)፦ የአንድ ተከራይ ድንገተኛ ጭማሪ ከእንግዲህ በሌላው ላይ 503 ስህተት አያስከትልም። የOMNIROUTE_CHAT_VIRTUAL_LANES የአካባቢ ተለዋዋጭ ከዚህ የዳሽቦርድ ማሻሻያ ቅድሚያ ይኖረዋል፤ ለውጦች አገልጋዩ ዳግም ሲጀመር ተግባራዊ ይሆናሉ።", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "የዳሽቦርድ አቅራቢ ገጾች፦ ነፃ ባጁን አቅራቢው በሚያከብራቸው ምልክቶች ላይ ብቻ ያሳዩ — የማሳያ ስም ግምታዊ ደንብን፣ ቡሊያን ያልሆኑ የነፃ መስኮችን እና ሰነድ የተደረገለት ነፃ ደረጃ በሌላቸው የተመዘገቡ አቅራቢዎች ላይ ያሉ :free ቅጥያዎችን ያስወግዳል። ማጥፋት ታሪካዊውን የባጅ ደንብ ይጠብቃል።", "featureFlagProxySkipRecentlyFailedDescription": "የፕሮክሲ ፑሎች እና የ opencode የየመለያው ዙር ምርጫ፣ አሁን ያልተሳካውን ፕሮክሲ (ውድቅ የተደረገ TCP ሙከራ ወይም በእሱ በኩል የተቀበለ 429) በድጋሚ እንዳያቀርቡ ያደርጋሉ፤ ይህም በእያንዳንዱ ድግግሞሽ እስከ ከፍተኛው ገደብ ድረስ በእጥፍ ለሚጨምር የየሂደቱ ጊዜ ነው። ምንም የፕሮክሲ ሁኔታ አይጻፍም፤ እያንዳንዱ እጩ ወደ ጎን ሲቀመጥ ምርጫው አይለወጥም። በነባሪ በርቷል፤ `false` ተራውን ምርጫ ይመልሳል።", - "featureFlagProxyPoolSharedEgressOrderDescription": "ኮታቸው በegress አድራሻ ለተመደበላቸው አቅራቢዎች፣ በቅርቡ ውድቅ ከተደረገ አባል ጋር የታየውን egress አድራሻ የሚጋራ የፑል አባልን ከጤናማ አባላት ዝቅ ብሎ ደረጃ ይስጡ። የቅደም ተከተል ብቻ ነው፣ በጭራሽ አይገለልም። የሚያነበውን የውድቅ ማድረጊያ ምልክት የሚያመነጨውን PROXY_SKIP_RECENTLY_FAILED ይፈልጋል። በነባሪነት ጠፍቷል፡ የምርጫ ቅደም ተከተሉ ልክ እንደ መደበኛ ዙር ነው።", "featureFlagProxyPoolEgressObservationDescription": "በዳሽቦርዱ ውስጥ ከፕሮክሲ ፑል ሥር፣ ባለፉት 24 ሰዓታት ምን ያህል የታዩ የመውጫ IPዎች አባላቱን እንዳገለገሉ፣ ምን ያህል ግንኙነቶች እንደተጠቀሙባቸው እና ከአንድ IP ጀርባ የታየውን ከፍተኛ ቁጥር አሳይ። ለንባብ ብቻ ነው፣ ከፕሮክሲ ሎጉ ይሰላል፣ ለማዞሪያም ፈጽሞ ጥቅም ላይ አይውልም። በነባሪ ጠፍቷል፦ የፑሉ አርታዒ አይለወጥም፣ የምልከታ መስመሩም null ይመልሳል።", "featureFlagProxyHealthBlockedResetsStreakDescription": "በፕሮክሲ ጤና ፍተሻ ውስጥ፣ ዒላማው ውድቅ ያደረገው ሙከራ (401/403/429፦ ፕሮክሲው አስተላልፏል፣ መዳረሻው ግን ይህን የመውጫ IP ውድቅ አድርጓል) ልክ እንደተሳካ ሙከራ የፕሮክሲውን ተከታታይ የውድቀት ቆጠራ ዳግም እንዲጀምር ፍቀድ። በነባሪ ጠፍቷል፦ ውድቅ መደረጉ ገለልተኛ ሆኖ ይቆያል እና ቆጠራውን እንዳለ ያቆያል። 5xx በሁለቱም ሁኔታ የማያረጋግጥ ሆኖ ይቆያል፣ እና ውድቅ መደረግ ፕሮክሲን ፈጽሞ አያስወግድም፣ አያሰናክልም ወይም ዳግም አያነቃም።", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ራስ-ሰር የማጽዳት ሂደቱ ከOMNIROUTE_BATCH_RETENTION_DAYS በላይ የቆዩ የተጠናቀቁ (completed/failed/cancelled/expired) Batch API ሥራዎችን ከየመስመራቸው ማረጋገጫ ነጥቦች ጋር እንዲሰርዝ እና የራሳቸው expires_at ያለፈባቸው የተሰቀሉ ፋይሎችን BLOB ይዘት እንዲያጸዳ ይፍቀዱ። በነባሪ የተሰናከለ ነው፦ ኦፕሬተር እስኪያነቃው ድረስ እያንዳንዱ ነባር ጭነት ይህን ውሂብ ልክ እንደበፊቱ ያቆያል። በኦፕሬተር የሚጀመረው DELETE /api/v1/batches/delete-completed መስመር በሁለቱም ሁኔታ አይነካም -- ይህ የተለየ፣ ቅድመ ሁኔታ የሌለው ይፋዊ API ውል ነው።", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "ዝማኔ ይገኛል፦ v{current} → v{latest}", "cliproxyapiVersion": "ስሪት" }, + "modelCatalog": { + "title": "ሞዴሎች እና ኮምቦዎች", + "subtitle": "በእያንዳንዱ አቅራቢ ዙሪያ ሞዴሎችን እና የኮምቦ ማዘዋወሪያ መስመሮችን ያስሱ እና ጤናቸውን ይፈትሹ።", + "refresh": "አድስ", + "modelsTab": "ሞዴሎች", + "combosTab": "ኮምቦዎች", + "catalogSections": "የካታሎግ ክፍሎች", + "loading": "በመጫን ላይ...", + "retry": "እንደገና ሞክር", + "unableToLoad": "የሞዴል ካታሎጉን መጫን አልተቻለም።", + "unableToLoadCombos": "ኮምቦዎችን መጫን አልተቻለም።", + "checkConnection": "ግንኙነትዎን ያረጋግጡ እና እንደገና ይሞክሩ።", + "noModelsAvailable": "እስካሁን ምንም ሞዴሎች አይገኙም።", + "noModelsMatch": "እነዚህን ማጣሪያዎች የሚያሟላ ምንም ሞዴል የለም።", + "noCombosAvailable": "እስካሁን ምንም ኮምቦዎች አይገኙም።", + "noCombosMatch": "እነዚህን ማጣሪያዎች የሚያሟላ ምንም ኮምቦ የለም።", + "clearFilters": "ማጣሪያዎችን አጽዳ", + "searchModels": "ሞዴሎችን ፈልግ", + "searchModelsPlaceholder": "በሞዴል፣ በአቅራቢ ወይም በችሎታ ፈልግ", + "searchCombos": "ኮምቦዎችን ፈልግ", + "searchCombosPlaceholder": "በኮምቦ ስም፣ በሞዴሎች ወይም በመግለጫ ፈልግ", + "modelCountSingle": "ሞዴል", + "modelCountPlural": "ሞዴሎች", + "comboCountSingle": "ኮምቦ", + "comboCountPlural": "ኮምቦዎች", + "provider": "አቅራቢ", + "allProviders": "ሁሉም አቅራቢዎች", + "type": "ዓይነት", + "allTypes": "ሁሉም ዓይነቶች", + "subtype": "ንዑስ ዓይነት", + "allSubtypes": "ሁሉም ንዑስ ዓይነቶች", + "capability": "ችሎታ", + "allCapabilities": "ሁሉም ችሎታዎች", + "pricing": "ዋጋ", + "allPricing": "ሁሉም ዋጋዎች", + "freeOnly": "ነፃ ብቻ", + "nonFree": "መደበኛ / ነፃ ያልሆነ", + "providerHealth": "የአቅራቢ ጤና", + "allHealthStates": "ሁሉም የጤና ሁኔታዎች", + "healthy": "ጤናማ", + "degraded": "የተዳከመ", + "down": "ወድቋል", + "testResult": "የሙከራ ውጤት", + "allResults": "ሁሉም ውጤቶች", + "untested": "ያልተሞከረ", + "statusOk": "ጥሩ", + "statusSlow": "ዝግተኛ", + "statusError": "ስህተት", + "minContext": "አነስተኛ አውድ", + "minContextPlaceholder": "ለምሳሌ 32000", + "strategy": "ስትራቴጂ", + "allStrategies": "ሁሉም ስትራቴጂዎች", + "status": "ሁኔታ", + "allStatuses": "ሁሉም ሁኔታዎች", + "active": "ንቁ", + "paused": "ለጊዜው የቆመ", + "minMembers": "አነስተኛ አባላት", + "minMembersPlaceholder": "ለምሳሌ 1", + "maxMembers": "ከፍተኛ አባላት", + "maxMembersPlaceholder": "ለምሳሌ 10", + "testSelected": "የተመረጡትን ሞክር ({count})", + "testAllFiltered": "የተጣሩትን ሁሉ ሞክር ({count})", + "cancel": "ይቅር", + "clearResults": "ውጤቶችን አጽዳ", + "testing": "በመሞከር ላይ...", + "rateLimited": "የተመን ገደብ ተጥሏል", + "quotaExceeded": "ኮታ አልቋል", + "timeout": "ጊዜው አልቋል", + "otherError": "ስህተት", + "justNow": "አሁን", + "minutesAgo": "ከ{count}ደቂቃ በፊት", + "hoursAgo": "ከ{count}ሰዓት በፊት", + "tableRegion": "የሞዴል ካታሎግ ሠንጠረዥ", + "combosTableRegion": "የጥምረቶች ካታሎግ ሠንጠረዥ", + "tableCaption": "በሁሉም አቅራቢዎች ላይ ያለ የሞዴል ካታሎግ", + "combosTableCaption": "የጥምረቶች ካታሎግ ከጤና ምርመራ ውጤቶች ጋር", + "selectAllModels": "በዚህ ገጽ ላይ ያሉትን ሁሉንም ሞዴሎች ምረጥ", + "selectAllCombos": "በዚህ ገጽ ላይ ያሉትን ሁሉንም ጥምረቶች ምረጥ", + "selectModel": "ሞዴል {name} ምረጥ", + "selectCombo": "ጥምረት {name} ምረጥ", + "model": "ሞዴል", + "capabilities": "ችሎታዎች", + "context": "አውድ", + "output": "ከፍተኛ ውፅአት", + "flags": "ባንዲራዎች", + "healthTest": "የጤና ሙከራ", + "actions": "እርምጃዎች", + "test": "ሙከራ", + "custom": "ብጁ", + "free": "ነፃ", + "noFlags": "ምንም ዋጋ ወይም የምንጭ ባንዲራ አልተዘገበም", + "noCapabilities": "ምንም የችሎታ ሜታዳታ አልተዘገበም", + "showingModels": "ከ{total} ሞዴሎች ውስጥ {first}–{last} በማሳየት ላይ", + "showingCombos": "ከ{total} ጥምረቶች ውስጥ {first}–{last} በማሳየት ላይ", + "refreshing": "በማደስ ላይ…", + "refreshFailed": "ማደስ አልተሳካም። መጨረሻ የተጫነውን ካታሎግ በማሳየት ላይ።", + "page": "ገጽ {page} ከ {pageCount}", + "previous": "ቀዳሚ", + "next": "ቀጣይ", + "combo": "ጥምረት", + "members": "አባላት", + "moreMembers": "+{count} ተጨማሪ" + }, "combos": { "title": "ጥምረቶች", "description": "ክብደት ያለው ማስተላለፊያ እና የመጠባበቂያ ድጋፍ ያላቸው የሞዴል ጥምረቶችን ይፍጠሩ", diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 0db20b97acdc..21771bf5b534 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "فعّل مسارات القبول الافتراضية التكيفية لكل مستأجر (tenant) لتوزيع المزودين (#9654): لم يعد انفجار حركة أحد المستأجرين يسبب خطأ 503 لمستأجر آخر. متغير البيئة OMNIROUTE_CHAT_VIRTUAL_LANES له الأولوية على هذا الإعداد في لوحة التحكم؛ تصبح التغييرات سارية بعد إعادة تشغيل الخادم.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "صفحات مزوّدي لوحة المعلومات: اعرض شارة «مجاني» فقط استنادًا إلى الإشارات التي يعتمدها المزوّد — مع إلغاء أسلوب الاستدلال المستند إلى اسم العرض، وحقول المجانية غير المنطقية، واللواحق :free لدى المزوّدين المسجّلين الذين ليست لديهم فئة مجانية موثّقة. عند التعطيل، تُستخدم قاعدة الشارة السابقة.", "featureFlagProxySkipRecentlyFailedDescription": "تمنع مجموعات الوكلاء والتناوب لكل حساب في opencode إعادة استخدام وكيل فشل للتو (رفض فحص TCP، أو تم تلقي 429 من خلاله) لمدة خاصة بكل عملية تتضاعف مع كل تكرار، حتى حد أقصى. لا تُكتب أي حالة للوكيل؛ وعند استبعاد جميع المرشحين، يظل الاختيار دون تغيير. مفعّل افتراضيًا؛ تعيد القيمة `false` الاختيار العادي.", - "featureFlagProxyPoolSharedEgressOrderDescription": "بالنسبة للمزودين الذين يتم تقسيم حصتهم حسب عنوان الخروج، رتّب عضو التجمع الذي يشارك عنوان الخروج المرصود لعضو رُفض مؤخراً مباشرة بعد الأعضاء السليمين. ترتيب فقط، دون استبعاد أبداً. يتطلب PROXY_SKIP_RECENTLY_FAILED، والذي يولّد إشارة الرفض التي يقرؤها. معطل افتراضياً: ترتيب الاختيار يطابق التدوير العادي تماماً.", "featureFlagProxyPoolEgressObservationDescription": "اعرض، أسفل مجموعة وكلاء في لوحة المعلومات، عدد عناوين IP الصادرة المرصودة التي خدمت أعضاءها خلال آخر 24 ساعة، وعدد الاتصالات التي استخدمتها، وأكبر عدد شوهد خلف عنوان IP واحد. للقراءة فقط، ويُحتسب من سجل الوكيل، ولا يُستخدم مطلقًا للتوجيه. معطّل افتراضيًا: يظل محرر المجموعة دون تغيير ويُرجع مسار الرصد null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "في فحص سلامة الوكلاء، اسمح للفحص الذي رفضه الهدف (401/403/429: قام الوكيل بالترحيل، لكن الوجهة رفضت عنوان IP الصادر هذا) بإعادة تعيين سلسلة حالات الفشل المتتالية للوكيل، كما لو كان فحصًا تمت خدمته. معطّل افتراضيًا: يظل الرفض محايدًا ويحافظ على السلسلة. تظل استجابة 5xx غير حاسمة في كلتا الحالتين، ولا يؤدي الرفض مطلقًا إلى إزالة وكيل أو تعطيله أو إعادة تنشيطه.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "اسمح لعملية التنظيف التلقائي بحذف مهام Batch API النهائية (المكتملة/الفاشلة/الملغاة/منتهية الصلاحية) الأقدم من OMNIROUTE_BATCH_RETENTION_DAYS، إلى جانب نقاط التحقق الخاصة بكل سطر، ومسح محتوى BLOB للملفات المرفوعة التي تجاوزت قيمة expires_at الخاصة بها. معطّل افتراضيًا: يحتفظ كل تثبيت حالي بهذه البيانات كما كان تمامًا إلى أن يفعّله أحد المشغّلين. لا يتأثر المسار DELETE /api/v1/batches/delete-completed الذي يشغّله المشغّل في كلتا الحالتين — فهو عقد API عام منفصل وغير مشروط.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "تحديث متاح: v{current} → v{latest}", "cliproxyapiVersion": "الإصدار" }, + "modelCatalog": { + "title": "النماذج والمجموعات", + "subtitle": "تصفح واختبر حالة النماذج ومسارات توجيه المجموعات عبر جميع المزودين.", + "refresh": "تحديث", + "modelsTab": "النماذج", + "combosTab": "المجموعات", + "catalogSections": "أقسام الكتالوج", + "loading": "جارٍ التحميل...", + "retry": "إعادة المحاولة", + "unableToLoad": "تعذر تحميل كتالوج النماذج.", + "unableToLoadCombos": "تعذر تحميل المجموعات.", + "checkConnection": "تحقق من الاتصال وأعد المحاولة.", + "noModelsAvailable": "لا تتوفر نماذج بعد.", + "noModelsMatch": "لا توجد نماذج تطابق عوامل التصفية هذه.", + "noCombosAvailable": "لا تتوفر مجموعات بعد.", + "noCombosMatch": "لا توجد مجموعات تطابق عوامل التصفية هذه.", + "clearFilters": "مسح عوامل التصفية", + "searchModels": "البحث في النماذج", + "searchModelsPlaceholder": "البحث حسب النموذج أو المزود أو الإمكانية", + "searchCombos": "البحث في المجموعات", + "searchCombosPlaceholder": "البحث حسب اسم المجموعة أو النماذج أو الوصف", + "modelCountSingle": "نموذج", + "modelCountPlural": "نماذج", + "comboCountSingle": "مجموعة", + "comboCountPlural": "مجموعات", + "provider": "المزود", + "allProviders": "جميع المزودين", + "type": "النوع", + "allTypes": "جميع الأنواع", + "subtype": "النوع الفرعي", + "allSubtypes": "جميع الأنواع الفرعية", + "capability": "الإمكانية", + "allCapabilities": "جميع الإمكانيات", + "pricing": "التسعير", + "allPricing": "جميع الأسعار", + "freeOnly": "المجانية فقط", + "nonFree": "قياسي / غير مجاني", + "providerHealth": "حالة المزود", + "allHealthStates": "جميع الحالات", + "healthy": "سليم", + "degraded": "متدهور", + "down": "متوقف", + "testResult": "نتيجة الاختبار", + "allResults": "جميع النتائج", + "untested": "لم يُختبر", + "statusOk": "سليم", + "statusSlow": "بطيء", + "statusError": "خطأ", + "minContext": "الحد الأدنى للسياق", + "minContextPlaceholder": "مثلاً 32000", + "strategy": "الاستراتيجية", + "allStrategies": "جميع الاستراتيجيات", + "status": "الحالة", + "allStatuses": "جميع الحالات", + "active": "نشط", + "paused": "متوقف مؤقتاً", + "minMembers": "الحد الأدنى للأعضاء", + "minMembersPlaceholder": "مثلاً 1", + "maxMembers": "الحد الأقصى للأعضاء", + "maxMembersPlaceholder": "مثلاً 10", + "testSelected": "اختبار المحدد ({count})", + "testAllFiltered": "اختبار جميع النتائج المصفاة ({count})", + "cancel": "إلغاء", + "clearResults": "مسح النتائج", + "testing": "جارٍ الاختبار...", + "rateLimited": "تجاوز معدل الطلبات", + "quotaExceeded": "تجاوز الحصة المحددة", + "timeout": "انتهت مهلة الطلب", + "otherError": "خطأ", + "justNow": "الآن", + "minutesAgo": "منذ {count} د", + "hoursAgo": "منذ {count} س", + "tableRegion": "جدول دليل النماذج", + "combosTableRegion": "جدول دليل المجموعات", + "tableCaption": "دليل النماذج عبر جميع المزودين", + "combosTableCaption": "دليل المجموعات مع نتائج اختبارات الحالة", + "selectAllModels": "تحديد جميع النماذج في هذه الصفحة", + "selectAllCombos": "تحديد جميع المجموعات في هذه الصفحة", + "selectModel": "تحديد النموذج {name}", + "selectCombo": "تحديد المجموعة {name}", + "model": "النموذج", + "capabilities": "القدرات", + "context": "السياق", + "output": "الحد الأقصى للمخرجات", + "flags": "العلامات", + "healthTest": "فحص الحالة", + "actions": "الإجراءات", + "test": "اختبار", + "custom": "مخصص", + "free": "مجاني", + "noFlags": "لم يتم الإبلاغ عن أي سعر أو علامة مصدر", + "noCapabilities": "لم يتم الإبلاغ عن أي بيانات وصفية للقدرات", + "showingModels": "عرض {first}–{last} من أصل {total} نموذج", + "showingCombos": "عرض {first}–{last} من أصل {total} توليفة", + "refreshing": "جارٍ التحديث…", + "refreshFailed": "فشل التحديث. يتم عرض آخر كتالوج تم تحميله.", + "page": "الصفحة {page} من {pageCount}", + "previous": "السابق", + "next": "التالي", + "combo": "توليفة", + "members": "الأعضاء", + "moreMembers": "+{count} المزيد" + }, "combos": { "title": "المجموعات", "description": "أنشئ مجموعات نماذج باستخدام التوجيه المرجّح والتبديل الاحتياطي", diff --git a/src/i18n/messages/az.json b/src/i18n/messages/az.json index fef9ceb68fc7..4f13c10dc4e8 100644 --- a/src/i18n/messages/az.json +++ b/src/i18n/messages/az.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Təchizatçı göndərişi üçün hər bir icarəçi (tenant) üzrə adaptiv virtual qəbul zolaqlarını aktivləşdirin (#9654): bir icarəçinin ani yükü artıq digərinə 503 qaytarmır. OMNIROUTE_CHAT_VIRTUAL_LANES mühit dəyişəni bu idarəetmə paneli ayarından üstündür; dəyişikliklər server yenidən işə salındıqda qüvvəyə minir.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "İdarə panelindəki provayder səhifələri: Pulsuz nişanını yalnız provayderin dəstəklədiyi siqnallar əsasında göstərin — sənədləşdirilmiş pulsuz səviyyəsi olmayan qeydiyyatdan keçmiş provayderlər üçün göstərilən ad evristikasından, Boolean tipli olmayan pulsuz sahələrdən və :free şəkilçilərindən artıq istifadə edilmir. Deaktiv olduqda əvvəlki nişan qaydası saxlanılır.", "featureFlagProxySkipRecentlyFailedDescription": "Proksi hovuzları və opencode-un hər hesab üzrə rotasiyası yenicə uğursuz olmuş proksini (TCP yoxlaması rədd edilib və ya onun vasitəsilə 429 cavabı alınıb) hər təkrarda ikiqat artan, lakin maksimum hədlə məhdudlaşan, hər proses üçün müəyyən edilmiş müddət ərzində yenidən təqdim etmir. Heç bir proksi statusu yazılmır; bütün namizədlər kənara qoyulduqda seçim dəyişməz qalır. Defolt olaraq aktivdir; `false` adi seçimi bərpa edir.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Kvotası çıxış ünvanına görə qruplaşdırılan provayderlər üçün, bu yaxınlarda imtina edilmiş üzvün müşahidə olunan çıxış ünvanını paylaşan hovuz üzvünü sağlam üzvlərdən dərhal sonra sıralayın. Yalnız sıralama üçündür, heç vaxt xaric edilmir. Oxuduğu imtina siqnalını generasiya edən PROXY_SKIP_RECENTLY_FAILED tələb olunur. Standart olaraq qeyri-aktivdir: seçim ardıcıllığı dəqiq adi növbələşmədir.", "featureFlagProxyPoolEgressObservationDescription": "İdarə panelində proksi hovuzunun altında son 24 saat ərzində onun üzvlərinə xidmət göstərən neçə çıxış IP-sinin müşahidə edildiyini, neçə bağlantının onlardan istifadə etdiyini və bir IP-nin arxasında müşahidə edilən ən yüksək sayı göstərin. Yalnız oxuma üçündür, proksi jurnalından hesablanır və marşrutlaşdırma üçün heç vaxt istifadə edilmir. Defolt olaraq deaktivdir: hovuz redaktoru dəyişməz qalır və müşahidə marşrutu null cavabı verir.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proksinin sağlamlıq yoxlamasında hədəfin rədd etdiyi yoxlamanın (401/403/429: proksi sorğunu ötürüb, təyinat nöqtəsi bu çıxış IP-sini rədd edib) uğurla ötürülmüş yoxlama kimi proksinin ardıcıl uğursuzluq sayğacını sıfırlamasına icazə verin. Defolt olaraq deaktivdir: rədd cavabı neytral qalır və ardıcıl uğursuzluq sayğacını dəyişmir. 5xx hər iki halda qeyri-müəyyən qalır və rədd cavabı heç vaxt proksini silmir, deaktiv etmir və ya yenidən aktivləşdirmir.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Avtomatik təmizləmə prosesinə OMNIROUTE_BATCH_RETENTION_DAYS müddətindən daha köhnə olan son vəziyyətdəki (tamamlanmış/uğursuz/ləğv edilmiş/müddəti bitmiş) Batch API tapşırıqlarını onların hər sətir üzrə nəzarət nöqtələri ilə birlikdə silməyə və öz expires_at vaxtı keçmiş yüklənmiş faylların BLOB məzmununu təmizləməyə icazə verin. Defolt olaraq deaktivdir: operator bunu aktiv edənədək bütün mövcud quraşdırmalar bu məlumatları əvvəlki kimi saxlayır. Operator tərəfindən işə salınan DELETE /api/v1/batches/delete-completed marşrutu istənilən halda bundan təsirlənmir — bu, ayrıca və qeyd-şərtsiz ictimai API müqaviləsidir.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Yeniləmə mövcuddur: v{current} → v{latest}", "cliproxyapiVersion": "Versiya" }, + "modelCatalog": { + "title": "Modellər və Kombolar", + "subtitle": "Bütün provayderlər üzrə modelləri və kombo marşrutlaşdırma xətlərini nəzərdən keçirin və sağlamlığını test edin.", + "refresh": "Yenilə", + "modelsTab": "Modellər", + "combosTab": "Kombolar", + "catalogSections": "Kataloq bölmələri", + "loading": "Yüklənir...", + "retry": "Yenidən cəhd et", + "unableToLoad": "Model kataloqunu yükləmək mümkün olmadı.", + "unableToLoadCombos": "Komboları yükləmək mümkün olmadı.", + "checkConnection": "Bağlantını yoxlayın və yenidən cəhd edin.", + "noModelsAvailable": "Hələ heç bir model əlçatan deyil.", + "noModelsMatch": "Bu filtrlərə uyğun model tapılmadı.", + "noCombosAvailable": "Hələ heç bir kombo əlçatan deyil.", + "noCombosMatch": "Bu filtrlərə uyğun kombo tapılmadı.", + "clearFilters": "Filtrləri təmizlə", + "searchModels": "Modelləri axtar", + "searchModelsPlaceholder": "Model, provayder və ya imkana görə axtarın", + "searchCombos": "Komboları axtar", + "searchCombosPlaceholder": "Kombo adına, modellərə və ya təsvirə görə axtarın", + "modelCountSingle": "model", + "modelCountPlural": "modellər", + "comboCountSingle": "kombo", + "comboCountPlural": "kombolar", + "provider": "Provayder", + "allProviders": "Bütün provayderlər", + "type": "Növ", + "allTypes": "Bütün növlər", + "subtype": "Alt növ", + "allSubtypes": "Bütün alt növlər", + "capability": "İmkan", + "allCapabilities": "Bütün imkanlar", + "pricing": "Qiymətləndirmə", + "allPricing": "Bütün qiymətlər", + "freeOnly": "Yalnız pulsuz", + "nonFree": "Standart / Ödənişli", + "providerHealth": "Provayder vəziyyəti", + "allHealthStates": "Bütün vəziyyətlər", + "healthy": "Sağlam", + "degraded": "Pisləşmiş", + "down": "İşləmir", + "testResult": "Test nəticəsi", + "allResults": "Bütün nəticələr", + "untested": "Test edilməyib", + "statusOk": "OK", + "statusSlow": "Yavaş", + "statusError": "Xəta", + "minContext": "Min. kontekst", + "minContextPlaceholder": "məs. 32000", + "strategy": "Strategiya", + "allStrategies": "Bütün strategiyalar", + "status": "Status", + "allStatuses": "Bütün statuslar", + "active": "Aktiv", + "paused": "Fasilədə", + "minMembers": "Min. üzv", + "minMembersPlaceholder": "məs. 1", + "maxMembers": "Maks. üzv", + "maxMembersPlaceholder": "məs. 10", + "testSelected": "Seçilmişləri test et ({count})", + "testAllFiltered": "Bütün filtrlənənləri test et ({count})", + "cancel": "Ləğv et", + "clearResults": "Nəticələri təmizlə", + "testing": "Test edilir...", + "rateLimited": "Sorğu limiti aşıldı", + "quotaExceeded": "Kvota aşıldı", + "timeout": "Vaxt aşımı", + "otherError": "Xəta", + "justNow": "İndicə", + "minutesAgo": "{count} dəq əvvəl", + "hoursAgo": "{count} saat əvvəl", + "tableRegion": "Model kataloqu cədvəli", + "combosTableRegion": "Kombolar kataloqu cədvəli", + "tableCaption": "Bütün provayderlər üzrə model kataloqu", + "combosTableCaption": "Sağlamlıq testi nəticələri ilə kombo kataloqu", + "selectAllModels": "Bu səhifədəki bütün modelləri seç", + "selectAllCombos": "Bu səhifədəki bütün komboları seç", + "selectModel": "{name} modelini seç", + "selectCombo": "{name} kombosunu seç", + "model": "Model", + "capabilities": "İmkanlar", + "context": "Kontekst", + "output": "Maksimum çıxış", + "flags": "Bayraqlar", + "healthTest": "Sağlamlıq testi", + "actions": "Əməliyyatlar", + "test": "Test", + "custom": "Fərdi", + "free": "Pulsuz", + "noFlags": "Heç bir qiymət və ya mənbə bayrağı bildirilməyib", + "noCapabilities": "İmkan metaməlumatı bildirilməyib", + "showingModels": "{total} modeldən {first}–{last} arası göstərilir", + "showingCombos": "{total} kombodan {first}–{last} arası göstərilir", + "refreshing": "Yenilənir…", + "refreshFailed": "Yeniləmə uğursuz oldu. Son yüklənmiş kataloq göstərilir.", + "page": "Səhifə {page} / {pageCount}", + "previous": "Əvvəlki", + "next": "Növbəti", + "combo": "Kombo", + "members": "Üzvlər", + "moreMembers": "+{count} daha" + }, "combos": { "title": "Kombinasiyalar", "description": "Çəkili yönləndirmə və ehtiyat keçid dəstəyi ilə model kombinasiyaları yaradın", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index 00cc53dab72a..e3111968bb06 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Активирайте адаптивни виртуални ленти за допускане за всеки наемател (tenant) при изпращане към доставчици (#9654): скокът в натоварването на един наемател вече не връща 503 на друг. Променливата на средата OMNIROUTE_CHAT_VIRTUAL_LANES има предимство пред тази настройка в таблото; промените влизат в сила след рестартиране на сървъра.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Страници на доставчиците в таблото: показва значката „Безплатно“ само при сигнали, които доставчикът зачита — премахва евристиката за показваното име, небулевите полета за безплатен достъп и суфиксите :free при регистрирани доставчици без документиран безплатен план. При „Изкл.“ се запазва предишното правило за значката.", "featureFlagProxySkipRecentlyFailedDescription": "Пуловете от проксита и ротацията на opencode за всеки акаунт временно спират повторното използване на прокси, което току-що е дало грешка (отказана TCP проверка или получен чрез него отговор 429), за период в рамките на процеса, който се удвоява при всяко повторение до достигане на максимална стойност. Не се записва състояние на проксито; ако всички кандидати бъдат временно изключени, изборът остава непроменен. Включено по подразбиране; `false` възстановява обикновения избор.", - "featureFlagProxyPoolSharedEgressOrderDescription": "За доставчици, чиято квота е групирана по изходящ адрес, подрежда член на пула, споделящ наблюдавания изходящ адрес на наскоро отказан член, непосредствено след изправните членове. Само подреждане, никога изключване. Изисква PROXY_SKIP_RECENTLY_FAILED, който генерира сигнала за отказ, който се разчита. Изключено по подразбиране: редът на избор е точно стандартната ротация.", "featureFlagProxyPoolEgressObservationDescription": "Показва под пул от проксита в таблото колко наблюдавани изходящи IP адреса са обслужвали членовете му през последните 24 ч., колко връзки са ги използвали и най-големия брой връзки зад един IP адрес. Само за четене, изчислява се от дневника на проксито и никога не се използва за маршрутизиране. Изключено по подразбиране: редакторът на пула остава непроменен, а маршрутът за наблюдение връща null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "При проверката на състоянието на прокситата позволява на проверка, отказана от целта (401/403/429: проксито е препратило заявката, но местоназначението е отказало този изходящ IP адрес), да нулира поредицата от последователни неуспехи на проксито, както при успешно обслужена проверка. Изключено по подразбиране: отказът остава неутрален и запазва поредицата. Отговор 5xx остава неубедителен и в двата случая, а отказът никога не премахва, деактивира или активира повторно прокси.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Позволява на автоматичното почистване да изтрива задания на Batch API в крайно състояние (завършени/неуспешни/отменени/изтекли), по-стари от OMNIROUTE_BATCH_RETENTION_DAYS, заедно с контролните им точки за всеки ред, както и да изчиства BLOB съдържанието на качените файлове след собствената им стойност expires_at. Изключено по подразбиране: всяка съществуваща инсталация продължава да съхранява тези данни точно както преди, докато оператор не активира опцията. Маршрутът DELETE /api/v1/batches/delete-completed, задействан от оператор, не се влияе и в двата случая — той е отделен, безусловен договор на публичния API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Налична актуализация: v{current} → v{latest}", "cliproxyapiVersion": "Версия" }, + "modelCatalog": { + "title": "Модели и комбота", + "subtitle": "Преглеждайте и тествайте състоянието на модели и конвейери за маршрутизиране на комбота при всеки доставчик.", + "refresh": "Опресняване", + "modelsTab": "Модели", + "combosTab": "Комбота", + "catalogSections": "Раздели на каталога", + "loading": "Зареждане...", + "retry": "Повторен опит", + "unableToLoad": "Неуспешно зареждане на каталога с модели.", + "unableToLoadCombos": "Неуспешно зареждане на комботата.", + "checkConnection": "Проверете връзката и опитайте отново.", + "noModelsAvailable": "Все още няма налични модели.", + "noModelsMatch": "Няма модели, отговарящи на тези филтри.", + "noCombosAvailable": "Все още няма налични комбота.", + "noCombosMatch": "Няма комбота, отговарящи на тези филтри.", + "clearFilters": "Изчистване на филтрите", + "searchModels": "Търсене на модели", + "searchModelsPlaceholder": "Търсене по модел, доставчик или възможност", + "searchCombos": "Търсене на комбота", + "searchCombosPlaceholder": "Търсене по име на комбо, модели или описание", + "modelCountSingle": "модел", + "modelCountPlural": "модели", + "comboCountSingle": "комбо", + "comboCountPlural": "комбота", + "provider": "Доставчик", + "allProviders": "Всички доставчици", + "type": "Тип", + "allTypes": "Всички типове", + "subtype": "Подтип", + "allSubtypes": "Всички подтипове", + "capability": "Възможност", + "allCapabilities": "Всички възможности", + "pricing": "Ценообразуване", + "allPricing": "Всички цени", + "freeOnly": "Само безплатни", + "nonFree": "Стандартни / Платени", + "providerHealth": "Състояние на доставчика", + "allHealthStates": "Всички състояния", + "healthy": "Изправен", + "degraded": "Влошен", + "down": "Офлайн", + "testResult": "Резултат от теста", + "allResults": "Всички резултати", + "untested": "Нетестван", + "statusOk": "ОК", + "statusSlow": "Бавен", + "statusError": "Грешка", + "minContext": "Мин. контекст", + "minContextPlaceholder": "напр. 32000", + "strategy": "Стратегия", + "allStrategies": "Всички стратегии", + "status": "Статус", + "allStatuses": "Всички статуси", + "active": "Активен", + "paused": "На пауза", + "minMembers": "Мин. членове", + "minMembersPlaceholder": "напр. 1", + "maxMembers": "Макс. членове", + "maxMembersPlaceholder": "напр. 10", + "testSelected": "Тестване на избраните ({count})", + "testAllFiltered": "Тестване на всички филтрирани ({count})", + "cancel": "Отказ", + "clearResults": "Изчистване на резултатите", + "testing": "Тестване...", + "rateLimited": "Ограничен брой заявки", + "quotaExceeded": "Превишена квота", + "timeout": "Изтекло време", + "otherError": "Грешка", + "justNow": "Току-що", + "minutesAgo": "преди {count} мин.", + "hoursAgo": "преди {count} ч.", + "tableRegion": "Таблица с каталог на моделите", + "combosTableRegion": "Таблица с каталог на комбинациите", + "tableCaption": "Каталог на моделите при всички доставчици", + "combosTableCaption": "Каталог на комбинациите с резултати от тестове за изправност", + "selectAllModels": "Избиране на всички модели на тази страница", + "selectAllCombos": "Избиране на всички комбинации на тази страница", + "selectModel": "Избиране на модел {name}", + "selectCombo": "Избиране на комбинация {name}", + "model": "Модел", + "capabilities": "Възможности", + "context": "Контекст", + "output": "Максимален изход", + "flags": "Флагове", + "healthTest": "Тест за изправност", + "actions": "Действия", + "test": "Тест", + "custom": "Персонализиран", + "free": "Безплатен", + "noFlags": "Няма отчетен флаг за цена или източник", + "noCapabilities": "Няма отчетени метаданни за възможности", + "showingModels": "Показване на {first}–{last} от {total} модела", + "showingCombos": "Показване на {first}–{last} от {total} комбинации", + "refreshing": "Опресняване…", + "refreshFailed": "Неуспешно опресняване. Показва се последният зареден каталог.", + "page": "Страница {page} от {pageCount}", + "previous": "Предишна", + "next": "Следваща", + "combo": "Комбинация", + "members": "Членове", + "moreMembers": "+{count} още" + }, "combos": { "title": "Комбота", "description": "Създавайте комбинации от модели с претеглено маршрутизиране и резервна поддръжка", diff --git a/src/i18n/messages/bn.json b/src/i18n/messages/bn.json index f14e80d1bb5a..75eabcf94e75 100644 --- a/src/i18n/messages/bn.json +++ b/src/i18n/messages/bn.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "প্রোভাইডার ডিসপ্যাচের জন্য প্রতি-টেন্যান্ট অ্যাডাপ্টিভ ভার্চুয়াল অ্যাডমিশন লেন সক্ষম করুন (#9654): এক টেন্যান্টের বিস্ফোরণ আর অন্য টেন্যান্টে 503 ফেরায় না। OMNIROUTE_CHAT_VIRTUAL_LANES এনভায়রনমেন্ট ভেরিয়েবল এই ড্যাশবোর্ড সেটিংয়ের উপরে প্রাধান্য পায়; পরিবর্তনগুলি সার্ভার পুনরায় চালু হলে কার্যকর হয়।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ড্যাশবোর্ডের প্রোভাইডার পেজগুলো: প্রোভাইডার যে সংকেতগুলোকে স্বীকৃতি দেয়, শুধু সেগুলোর ভিত্তিতেই Free ব্যাজ দেখান — নথিভুক্ত ফ্রি টিয়ার নেই এমন নিবন্ধিত প্রোভাইডারগুলোর ক্ষেত্রে ডিসপ্লে-নেম হিউরিস্টিক, নন-বুলিয়ান ফ্রি ফিল্ড এবং :free সাফিক্স বাদ দেওয়া হয়। বন্ধ রাখলে আগের ব্যাজের নিয়ম বজায় থাকে।", "featureFlagProxySkipRecentlyFailedDescription": "প্রক্সি পুল এবং opencode-এর প্রতি-অ্যাকাউন্ট রোটেশন এমন কোনো প্রক্সিকে পুনরায় ব্যবহার করা বন্ধ রাখে, যা সদ্য ব্যর্থ হয়েছে (TCP প্রোব প্রত্যাখ্যাত হয়েছে অথবা সেটির মাধ্যমে 429 পাওয়া গেছে)। প্রতি-প্রসেসে এই বিরতির সময়কাল প্রতিবার পুনরাবৃত্তির সঙ্গে দ্বিগুণ হয়, সর্বোচ্চ সীমা পর্যন্ত। প্রক্সির কোনো স্ট্যাটাস লেখা হয় না; সব প্রার্থীকে সরিয়ে রাখলেও নির্বাচন অপরিবর্তিত থাকে। ডিফল্টভাবে চালু; `false` সাধারণ নির্বাচন ফিরিয়ে আনে।", - "featureFlagProxyPoolSharedEgressOrderDescription": "যেসকল প্রোভাইডারের কোটা egress address অনুসারে ভাগ করা হয়, তাদের ক্ষেত্রে সম্প্রতি প্রত্যাখ্যাত কোনো মেম্বারের পর্যবেক্ষিত egress address শেয়ার করা পুল মেম্বারকে সুস্থ মেম্বারদের ঠিক নিচে স্থান দিন। শুধুমাত্র ক্রম নির্ধারণের জন্য, কখনোই বাদ দেওয়া হয় না। এর জন্য PROXY_SKIP_RECENTLY_FAILED প্রয়োজন, যা এটি দ্বারা পঠিত প্রত্যাখ্যানের সংকেত তৈরি করে। ডিফল্টভাবে নিষ্ক্রিয়: নির্বাচনের ক্রম অবিকল সাধারণ রোটেশন অনুযায়ী হবে।", "featureFlagProxyPoolEgressObservationDescription": "ড্যাশবোর্ডে একটি প্রক্সি পুলের অধীনে দেখান, গত ২৪ ঘণ্টায় পর্যবেক্ষিত কতটি egress IP তার সদস্যদের সেবা দিয়েছে, কতটি সংযোগ সেগুলো ব্যবহার করেছে এবং একটি IP-এর পেছনে সর্বাধিক কতজন সদস্য দেখা গেছে। এটি শুধু পাঠযোগ্য, প্রক্সি লগ থেকে গণনা করা হয় এবং রাউটিংয়ে কখনো ব্যবহার করা হয় না। ডিফল্টভাবে বন্ধ: পুল এডিটর অপরিবর্তিত থাকে এবং পর্যবেক্ষণ রুট null প্রদান করে।", "featureFlagProxyHealthBlockedResetsStreakDescription": "প্রক্সি হেলথ সুইপে, টার্গেট প্রত্যাখ্যান করেছে এমন কোনো প্রোবকে (401/403/429: প্রক্সি রিলে করেছে, কিন্তু গন্তব্য এই egress IP প্রত্যাখ্যান করেছে) সফলভাবে পরিবেশিত প্রোবের মতো প্রক্সির ধারাবাহিক ব্যর্থতার ধারা রিসেট করতে দিন। ডিফল্টভাবে বন্ধ: প্রত্যাখ্যান নিরপেক্ষ থাকে এবং ধারাটি বজায় রাখে। উভয় ক্ষেত্রেই 5xx অনির্ণায়ক থাকে এবং কোনো প্রত্যাখ্যান কখনোই প্রক্সিকে সরায়, নিষ্ক্রিয় করে বা পুনরায় সক্রিয় করে না।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "স্বয়ংক্রিয় ক্লিনআপ সুইপকে OMNIROUTE_BATCH_RETENTION_DAYS-এর চেয়ে পুরোনো টার্মিনাল (সম্পন্ন/ব্যর্থ/বাতিল/মেয়াদোত্তীর্ণ) Batch API জবগুলো তাদের প্রতি-লাইনের চেকপয়েন্টসহ মুছে ফেলতে এবং আপলোড করা ফাইলগুলোর নিজস্ব expires_at পেরিয়ে গেলে সেগুলোর BLOB কনটেন্ট মুছে দিতে দিন। ডিফল্টভাবে বন্ধ: কোনো অপারেটর এটি চালু না করা পর্যন্ত প্রতিটি বিদ্যমান ইনস্টলেশন আগের মতোই এই ডেটা সংরক্ষণ করবে। অপারেটর-ট্রিগার করা DELETE /api/v1/batches/delete-completed রুট উভয় ক্ষেত্রেই অপরিবর্তিত থাকবে — এটি একটি পৃথক, নিঃশর্ত পাবলিক API চুক্তি।", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "আপডেট উপলব্ধ: v{current} → v{latest}", "cliproxyapiVersion": "সংস্করণ" }, + "modelCatalog": { + "title": "মডেল ও কম্বো", + "subtitle": "প্রতিটি প্রোভাইডারের মডেল এবং কম্বো রাউটিং পাইপলাইন ব্রাউজ ও হেলথ-টেস্ট করুন।", + "refresh": "রিফ্রেশ", + "modelsTab": "মডেল", + "combosTab": "কম্বো", + "catalogSections": "ক্যাটালগ বিভাগ", + "loading": "লোড হচ্ছে...", + "retry": "পুনরায় চেষ্টা করুন", + "unableToLoad": "মডেল ক্যাটালগ লোড করা যায়নি।", + "unableToLoadCombos": "কম্বো লোড করা যায়নি।", + "checkConnection": "সংযোগ পরীক্ষা করে আবার চেষ্টা করুন।", + "noModelsAvailable": "এখনও কোনো মডেল উপলব্ধ নেই।", + "noModelsMatch": "এই ফিল্টারগুলোর সাথে কোনো মডেল মিলছে না।", + "noCombosAvailable": "এখনও কোনো কম্বো উপলব্ধ নেই।", + "noCombosMatch": "এই ফিল্টারগুলোর সাথে কোনো কম্বো মিলছে না।", + "clearFilters": "ফিল্টার সাফ করুন", + "searchModels": "মডেল খুঁজুন", + "searchModelsPlaceholder": "মডেল, প্রোভাইডার বা সক্ষমতা অনুযায়ী খুঁজুন", + "searchCombos": "কম্বো খুঁজুন", + "searchCombosPlaceholder": "কম্বোর নাম, মডেল বা বিবরণ অনুযায়ী খুঁজুন", + "modelCountSingle": "মডেল", + "modelCountPlural": "মডেলগুলো", + "comboCountSingle": "কম্বো", + "comboCountPlural": "কম্বোগুলো", + "provider": "প্রোভাইডার", + "allProviders": "সকল প্রোভাইডার", + "type": "ধরন", + "allTypes": "সকল ধরন", + "subtype": "সাবটাইপ", + "allSubtypes": "সকল সাবটাইপ", + "capability": "সক্ষমতা", + "allCapabilities": "সকল সক্ষমতা", + "pricing": "মূল্য", + "allPricing": "সকল মূল্য", + "freeOnly": "শুধুমাত্র ফ্রি", + "nonFree": "স্ট্যান্ডার্ড / নন-ফ্রি", + "providerHealth": "প্রোভাইডার হেলথ", + "allHealthStates": "সকল হেলথ স্টেট", + "healthy": "হেলদি", + "degraded": "ডিগ্রেডেড", + "down": "ডাউন", + "testResult": "পরীক্ষার ফলাফল", + "allResults": "সব ফলাফল", + "untested": "অপরীক্ষিত", + "statusOk": "ঠিক আছে", + "statusSlow": "ধীরগতি", + "statusError": "ত্রুটি", + "minContext": "ন্যূনতম কনটেক্সট", + "minContextPlaceholder": "যেমন 32000", + "strategy": "কৌশল", + "allStrategies": "সব কৌশল", + "status": "স্ট্যাটাস", + "allStatuses": "সব স্ট্যাটাস", + "active": "সক্রিয়", + "paused": "স্থগিত", + "minMembers": "ন্যূনতম সদস্য", + "minMembersPlaceholder": "যেমন 1", + "maxMembers": "সর্বোচ্চ সদস্য", + "maxMembersPlaceholder": "যেমন 10", + "testSelected": "নির্বাচিতগুলো পরীক্ষা করুন ({count})", + "testAllFiltered": "ফিল্টার করা সব পরীক্ষা করুন ({count})", + "cancel": "বাতিল", + "clearResults": "ফলাফল মুছুন", + "testing": "পরীক্ষা করা হচ্ছে...", + "rateLimited": "রেট লিমিটেড", + "quotaExceeded": "কোটা অতিক্রান্ত", + "timeout": "টাইম আউট", + "otherError": "ত্রুটি", + "justNow": "এইমাত্র", + "minutesAgo": "{count}মি আগে", + "hoursAgo": "{count}ঘ আগে", + "tableRegion": "মডেল ক্যাটালগ টেবিল", + "combosTableRegion": "কম্বো ক্যাটালগ টেবিল", + "tableCaption": "সব প্রোভাইডারের মডেল ক্যাটালগ", + "combosTableCaption": "হেলথ টেস্ট ফলাফলসহ কম্বো ক্যাটালগ", + "selectAllModels": "এই পৃষ্ঠার সব মডেল নির্বাচন করুন", + "selectAllCombos": "এই পৃষ্ঠার সব কম্বো নির্বাচন করুন", + "selectModel": "মডেল {name} নির্বাচন করুন", + "selectCombo": "কম্বো {name} নির্বাচন করুন", + "model": "মডেল", + "capabilities": "সক্ষমতা", + "context": "কনটেক্সট", + "output": "সর্বোচ্চ আউটপুট", + "flags": "ফ্ল্যাগসমূহ", + "healthTest": "হেলথ টেস্ট", + "actions": "অ্যাকশনসমূহ", + "test": "টেস্ট", + "custom": "কাস্টম", + "free": "বিনামূল্যে", + "noFlags": "কোনো মূল্য বা উৎসের ফ্ল্যাগ রিপোর্ট করা হয়নি", + "noCapabilities": "কোনো সক্ষমতার মেটাডেটা রিপোর্ট করা হয়নি", + "showingModels": "{total}টি মডেলের মধ্যে {first}–{last}টি দেখানো হচ্ছে", + "showingCombos": "{total}টি কম্বোর মধ্যে {first}–{last}টি দেখানো হচ্ছে", + "refreshing": "রিফ্রেশ করা হচ্ছে…", + "refreshFailed": "রিফ্রেশ ব্যর্থ হয়েছে। সর্বশেষে লোড করা ক্যাটালগ দেখানো হচ্ছে।", + "page": "{pageCount} পৃষ্ঠার মধ্যে {page} নম্বর পৃষ্ঠা", + "previous": "পূর্ববর্তী", + "next": "পরবর্তী", + "combo": "কম্বো", + "members": "সদস্য", + "moreMembers": "+{count} আরও" + }, "combos": { "title": "কম্বোসমূহ", "description": "ওজনভিত্তিক রাউটিং ও ফলব্যাক সমর্থনসহ মডেল কম্বো তৈরি করুন", diff --git a/src/i18n/messages/bs.json b/src/i18n/messages/bs.json index a420c1659679..df30d91ec0e0 100644 --- a/src/i18n/messages/bs.json +++ b/src/i18n/messages/bs.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogući adaptivne virtualne trake prijema po tenantu za dispatch provajdera (#9654): burst jednog tenanta više ne uzrokuje 503 grešku drugom. Env varijabla OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost nad ovim override-om na dashboardu; promjene stupaju na snagu nakon ponovnog pokretanja servera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stranice provajdera na dashboardu: prikaži Free bedž samo na signalima koje provajder priznaje — uklanja heuristiku display-name-a, ne-boolean free polja i :free sufikse na registrovanim provajderima bez dokumentiranog besplatnog nivoa. Isključeno zadržava historijsko pravilo za bedževe.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pool-ovi i rotacija po računu za opencode prestaju ponovo posluživati proxy koji je upravo zakazao (odbijena TCP proba ili primljeni 429 kroz njega) za period po procesu koji se udvostručuje pri svakom ponavljanju, do određenog limita. Status proxy-ja se ne zapisuje; sa svakim odloženim kandidatom izbor ostaje nepromijenjen. Podrazumijevano uključeno; `false` vraća običnu selekciju.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Za provajdere čija je kvota grupisana prema egress adresi, rangirajte člana poola koji dijeli zabilježenu egress adresu nedavno odbijenog člana odmah ispod zdravih članova. Samo redoslijed, nikada isključeno. Zahtijeva PROXY_SKIP_RECENTLY_FAILED, koji generiše signal odbijanja koji se očitava. Podrazumijevano isključeno: redoslijed odabira je tačno obična rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Prikaži, unutar proxy pool-a na dashboardu, koliko je opaženih egress IP-ova poslužilo njegove članove u posljednjih 24 h, koliko je konekcija ih koristilo i najviše viđenih iza jednog IP-a. Samo za čitanje, izračunato iz proxy log-a, nikada ne koristi se za rutiranje. Podrazumijevano isključeno: editor pool-a ostaje nepromijenjen, a ruta za opažanje vraća null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "U skeniranju zdravlja proxy-ja, dopusti da proba koju je cilj odbio (401/403/429: proxy je proslijedio, destinacija je odbila ovaj egress IP) resetuje niz uzastopnih neuspjeha proxy-ja, kao i poslužena proba. Podrazumijevano isključeno: odbijanje ostaje neutralno i zadržava niz. 5xx ostaje neodređen u oba slučaja, a odbijanje nikada ne uklanja, onemogućuje ili ponovo aktivira proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dopusti automatskom skeniranju za čišćenje da obriše terminalne (završene/neuspjele/otkazane/istekle) Batch API poslove starije od OMNIROUTE_BATCH_RETENTION_DAYS, zajedno sa njihovim checkpointima po liniji, i očisti BLOB sadržaj uploadovanih datoteka nakon njihovog expires_at. Podrazumijevano isključeno: svaka postojeća instalacija čuva ove podatke tačno kao i ranije dok operator ne odobri. Ruta DELETE /api/v1/batches/delete-completed pokrenuta od strane operatora nije pogođena u oba slučaja -- to je zaseban, bezuvjetni javni API ugovor.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Dostupno ažuriranje: v{current} → v{latest}", "cliproxyapiVersion": "Verzija" }, + "modelCatalog": { + "title": "Modeli i kombinacije", + "subtitle": "Pregledajte i testirajte ispravnost modela i cjevovoda za usmjeravanje kombinacija kod svih provajdera.", + "refresh": "Osvježi", + "modelsTab": "Modeli", + "combosTab": "Kombinacije", + "catalogSections": "Sekcije kataloga", + "loading": "Učitavanje...", + "retry": "Pokušaj ponovo", + "unableToLoad": "Nije moguće učitati katalog modela.", + "unableToLoadCombos": "Nije moguće učitati kombinacije.", + "checkConnection": "Provjerite vezu i pokušajte ponovo.", + "noModelsAvailable": "Još nema dostupnih modela.", + "noModelsMatch": "Nijedan model ne odgovara ovim filterima.", + "noCombosAvailable": "Još nema dostupnih kombinacija.", + "noCombosMatch": "Nijedna kombinacija ne odgovara ovim filterima.", + "clearFilters": "Očisti filtere", + "searchModels": "Pretraži modele", + "searchModelsPlaceholder": "Pretraži po modelu, provajderu ili mogućnosti", + "searchCombos": "Pretraži kombinacije", + "searchCombosPlaceholder": "Pretraži po nazivu kombinacije, modelima ili opisu", + "modelCountSingle": "model", + "modelCountPlural": "modeli", + "comboCountSingle": "kombinacija", + "comboCountPlural": "kombinacije", + "provider": "Provajder", + "allProviders": "Svi provajderi", + "type": "Tip", + "allTypes": "Svi tipovi", + "subtype": "Podtip", + "allSubtypes": "Svi podtipovi", + "capability": "Mogućnost", + "allCapabilities": "Sve mogućnosti", + "pricing": "Cijene", + "allPricing": "Sve cijene", + "freeOnly": "Samo besplatno", + "nonFree": "Standardno / Nije besplatno", + "providerHealth": "Ispravnost provajdera", + "allHealthStates": "Sva stanja ispravnosti", + "healthy": "Ispravno", + "degraded": "Degradirano", + "down": "Nedostupan", + "testResult": "Rezultat testa", + "allResults": "Svi rezultati", + "untested": "Netestirano", + "statusOk": "U redu", + "statusSlow": "Sporo", + "statusError": "Greška", + "minContext": "Min. kontekst", + "minContextPlaceholder": "npr. 32000", + "strategy": "Strategija", + "allStrategies": "Sve strategije", + "status": "Status", + "allStatuses": "Svi statusi", + "active": "Aktivan", + "paused": "Pauziran", + "minMembers": "Min. članova", + "minMembersPlaceholder": "npr. 1", + "maxMembers": "Maks. članova", + "maxMembersPlaceholder": "npr. 10", + "testSelected": "Testiraj odabrano ({count})", + "testAllFiltered": "Testiraj sve filtrirano ({count})", + "cancel": "Otkaži", + "clearResults": "Očisti rezultate", + "testing": "Testiranje...", + "rateLimited": "Prekoračen limit zahtjeva", + "quotaExceeded": "Prekoračena kvota", + "timeout": "Isteklo vrijeme", + "otherError": "Greška", + "justNow": "Upravo sada", + "minutesAgo": "prije {count} min", + "hoursAgo": "prije {count} h", + "tableRegion": "Tabela kataloga modela", + "combosTableRegion": "Tabela kataloga kombinacija", + "tableCaption": "Katalog modela kod svih provajdera", + "combosTableCaption": "Katalog kombinacija s rezultatima testova ispravnosti", + "selectAllModels": "Odaberi sve modele na ovoj stranici", + "selectAllCombos": "Odaberi sve kombinacije na ovoj stranici", + "selectModel": "Odaberi model {name}", + "selectCombo": "Odaberi kombinaciju {name}", + "model": "Model", + "capabilities": "Mogućnosti", + "context": "Kontekst", + "output": "Maksimalni izlaz", + "flags": "Oznake", + "healthTest": "Test ispravnosti", + "actions": "Akcije", + "test": "Testiraj", + "custom": "Prilagođeno", + "free": "Besplatno", + "noFlags": "Nije prijavljena cijena niti oznaka izvora", + "noCapabilities": "Nisu prijavljeni metapodaci o mogućnostima", + "showingModels": "Prikaz {first}–{last} od {total} modela", + "showingCombos": "Prikaz {first}–{last} od {total} kombinacija", + "refreshing": "Osvježavanje…", + "refreshFailed": "Osvježavanje nije uspjelo. Prikazuje se posljednji učitani katalog.", + "page": "Stranica {page} od {pageCount}", + "previous": "Prethodna", + "next": "Sljedeća", + "combo": "Kombinacija", + "members": "Članovi", + "moreMembers": "+{count} više" + }, "combos": { "title": "Kombinacije", "description": "Kreirajte kombinacije modela sa ponderisanim rutiranjem i podrškom za fallback", diff --git a/src/i18n/messages/cs.json b/src/i18n/messages/cs.json index 87214ac8c15b..c6cd89ac2d95 100644 --- a/src/i18n/messages/cs.json +++ b/src/i18n/messages/cs.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Povolte adaptivní virtuální vstupní pruhy pro každého tenanta při odesílání poskytovatelům (#9654): špička jednoho tenanta už nezpůsobí 503 u jiného. Proměnná prostředí OMNIROUTE_CHAT_VIRTUAL_LANES má přednost před tímto nastavením na řídicím panelu; změny se projeví po restartu serveru.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stránky poskytovatelů na řídicím panelu: zobrazí odznak Zdarma pouze na základě příznaků, které poskytovatel podporuje — přestane používat heuristiku zobrazovaného názvu, nebooleovská pole free a přípony :free u registrovaných poskytovatelů bez zdokumentované bezplatné úrovně. Vypnutí zachová původní pravidlo pro odznak.", "featureFlagProxySkipRecentlyFailedDescription": "Fondy proxy serverů a rotace opencode pro jednotlivé účty dočasně přestanou znovu nabízet proxy server, který právě selhal (odmítnutá sonda TCP nebo odpověď 429 přijatá přes tento server), a to na dobu platnou pro daný proces, která se při každém opakování zdvojnásobí až do stanoveného maxima. Stav proxy serveru se nezapisuje; pokud jsou odloženi všichni kandidáti, volba se nemění. Ve výchozím nastavení zapnuto; `false` obnoví prostý výběr.", - "featureFlagProxyPoolSharedEgressOrderDescription": "U poskytovatelů, jejichž kvóta je seskupována podle odchozí adresy, zařadí člena fondu sdílejícího zjištěnou odchozí adresu nedávno odmítnutého člena těsně za zdravé členy. Pouze mění pořadí, nikdy nevylučuje. Vyžaduje PROXY_SKIP_RECENTLY_FAILED, který generuje signál odmítnutí, z něhož čte. Ve výchozím nastavení vypnuto: pořadí výběru přesně odpovídá běžné rotaci.", "featureFlagProxyPoolEgressObservationDescription": "Zobrazit pod fondem proxy serverů na řídicím panelu, kolik pozorovaných odchozích IP adres obsluhovalo jeho členy za posledních 24 h, kolik připojení je použilo a jaký byl nejvyšší počet připojení zaznamenaný za jednou IP adresou. Pouze pro čtení, vypočítáváno z protokolu proxy serveru a nikdy nepoužíváno ke směrování. Ve výchozím nastavení vypnuto: editor fondu zůstává beze změny a trasa pozorování vrací null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Při kontrole stavu proxy serveru umožnit, aby sonda odmítnutá cílem (401/403/429: proxy server požadavek předal, ale cíl odmítl tuto odchozí IP adresu) vynulovala řadu po sobě jdoucích selhání proxy serveru stejně jako úspěšně obsloužená sonda. Ve výchozím nastavení vypnuto: odmítnutí zůstává neutrální a řadu zachovává. Odpověď 5xx zůstává v obou případech neprůkazná a odmítnutí nikdy neodebere, nezakáže ani znovu neaktivuje proxy server.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Povolit automatickému čištění odstraňovat úlohy Batch API v koncovém stavu (dokončené/neúspěšné/zrušené/expirované), které jsou starší než OMNIROUTE_BATCH_RETENTION_DAYS, spolu s jejich kontrolními body pro jednotlivé řádky a mazat obsah BLOB nahraných souborů po uplynutí jejich vlastního expires_at. Ve výchozím nastavení vypnuto: každá stávající instalace uchovává tato data přesně jako dříve, dokud správce tuto funkci nepovolí. Trasa DELETE /api/v1/batches/delete-completed spouštěná správcem zůstává v obou případech beze změny – jde o samostatný, nepodmíněný veřejný kontrakt API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "K dispozici je aktualizace: v{current} → v{latest}", "cliproxyapiVersion": "Verze" }, + "modelCatalog": { + "title": "Modely a komba", + "subtitle": "Procházejte a testujte stav modelů a směrovacích pipeline komb napříč všemi poskytovateli.", + "refresh": "Obnovit", + "modelsTab": "Modely", + "combosTab": "Komba", + "catalogSections": "Sekce katalogu", + "loading": "Načítání...", + "retry": "Zkusit znovu", + "unableToLoad": "Katalog modelů se nepodařilo načíst.", + "unableToLoadCombos": "Komba se nepodařilo načíst.", + "checkConnection": "Zkontrolujte připojení a zkuste to znovu.", + "noModelsAvailable": "Zatím nejsou k dispozici žádné modely.", + "noModelsMatch": "Těmto filtrům neodpovídají žádné modely.", + "noCombosAvailable": "Zatím nejsou k dispozici žádná komba.", + "noCombosMatch": "Těmto filtrům neodpovídají žádná komba.", + "clearFilters": "Vymazat filtry", + "searchModels": "Hledat modely", + "searchModelsPlaceholder": "Hledat podle modelu, poskytovatele nebo schopnosti", + "searchCombos": "Hledat komba", + "searchCombosPlaceholder": "Hledat podle názvu komba, modelů nebo popisu", + "modelCountSingle": "model", + "modelCountPlural": "modely", + "comboCountSingle": "kombo", + "comboCountPlural": "komba", + "provider": "Poskytovatel", + "allProviders": "Všichni poskytovatelé", + "type": "Typ", + "allTypes": "Všechny typy", + "subtype": "Podtyp", + "allSubtypes": "Všechny podtypy", + "capability": "Schopnost", + "allCapabilities": "Všechny schopnosti", + "pricing": "Ceny", + "allPricing": "Všechny ceny", + "freeOnly": "Pouze zdarma", + "nonFree": "Standardní / placené", + "providerHealth": "Stav poskytovatele", + "allHealthStates": "Všechny stavy", + "healthy": "V pořádku", + "degraded": "Zhoršený stav", + "down": "Mimo provoz", + "testResult": "Výsledek testu", + "allResults": "Všechny výsledky", + "untested": "Netestováno", + "statusOk": "OK", + "statusSlow": "Pomalé", + "statusError": "Chyba", + "minContext": "Min. kontext", + "minContextPlaceholder": "např. 32000", + "strategy": "Strategie", + "allStrategies": "Všechny strategie", + "status": "Stav", + "allStatuses": "Všechny stavy", + "active": "Aktivní", + "paused": "Pozastaveno", + "minMembers": "Min. členů", + "minMembersPlaceholder": "např. 1", + "maxMembers": "Max. členů", + "maxMembersPlaceholder": "např. 10", + "testSelected": "Otestovat vybrané ({count})", + "testAllFiltered": "Otestovat všechny filtrované ({count})", + "cancel": "Zrušit", + "clearResults": "Vymazat výsledky", + "testing": "Testování...", + "rateLimited": "Překročen limit požadavků", + "quotaExceeded": "Kvóta překročena", + "timeout": "Vypršel časový limit", + "otherError": "Chyba", + "justNow": "Právě teď", + "minutesAgo": "před {count} min", + "hoursAgo": "před {count} h", + "tableRegion": "Tabulka katalogu modelů", + "combosTableRegion": "Tabulka katalogu kombinací", + "tableCaption": "Katalog modelů napříč všemi poskytovateli", + "combosTableCaption": "Katalog kombinací s výsledky testů stavu", + "selectAllModels": "Vybrat všechny modely na této stránce", + "selectAllCombos": "Vybrat všechny kombinace na této stránce", + "selectModel": "Vybrat model {name}", + "selectCombo": "Vybrat kombinaci {name}", + "model": "Model", + "capabilities": "Schopnosti", + "context": "Kontext", + "output": "Maximální výstup", + "flags": "Příznaky", + "healthTest": "Test stavu", + "actions": "Akce", + "test": "Otestovat", + "custom": "Vlastní", + "free": "Zdarma", + "noFlags": "Nebyla nahlášena žádná cena ani příznak zdroje", + "noCapabilities": "Nebyla nahlášena žádná metadata schopností", + "showingModels": "Zobrazeno {first}–{last} z {total} modelů", + "showingCombos": "Zobrazeno {first}–{last} z {total} kombinací", + "refreshing": "Obnovování…", + "refreshFailed": "Obnovení se nezdařilo. Zobrazuje se naposledy načtený katalog.", + "page": "Stránka {page} z {pageCount}", + "previous": "Předchozí", + "next": "Další", + "combo": "Kombinace", + "members": "Členové", + "moreMembers": "+{count} dalších" + }, "combos": { "title": "Komba", "description": "Vytvářejte kombinace modelů s váženým směrováním a podporou záloh", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index 2371c827cdf9..f4658112c841 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivér adaptive virtuelle adgangsbaner pr. tenant til providerudlevering (#9654): en tenants burst giver ikke længere en anden 503. Miljøvariablen OMNIROUTE_CHAT_VIRTUAL_LANES har forrang over denne dashboard-indstilling; ændringer træder i kraft ved genstart af serveren.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Udbydersider i dashboardet: Vis kun Gratis-mærket for signaler, som udbyderen respekterer — dette fjerner heuristikken for visningsnavne, ikke-booleske gratis-felter og :free-suffikser hos registrerede udbydere uden et dokumenteret gratis niveau. Deaktiveret bevarer den tidligere regel for mærket.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy-puljer og rotationen pr. konto for opencode undgår i en periode pr. proces, der fordobles ved hver gentagelse op til en øvre grænse, at genbruge en proxy, som netop har fejlet (afvist TCP-probe eller en 429 modtaget gennem den). Der skrives ingen proxy-status; hvis alle kandidater sættes til side, forbliver valget uændret. Aktiveret som standard; `false` gendanner det almindelige valg.", - "featureFlagProxyPoolSharedEgressOrderDescription": "For udbydere, hvis kvote er opdelt efter egress-adresse, rangeres et poolmedlem, der deler et nyligt afvist medlems observerede egress-adresse, lige under sunde medlemmer. Kun rækkefølge, udelukkes aldrig. Kræver PROXY_SKIP_RECENTLY_FAILED, som genererer det afvisningssignal, den aflæser. Deaktiveret som standard: udvælgelsesrækkefølgen er præcis den almindelige rotation.", "featureFlagProxyPoolEgressObservationDescription": "Vis under en proxy-pulje i dashboardet, hvor mange observerede udgående IP-adresser der har betjent dens medlemmer inden for de seneste 24 timer, hvor mange forbindelser der brugte dem, og det højeste antal observeret bag én IP-adresse. Skrivebeskyttet, beregnet ud fra proxy-loggen og aldrig brugt til routing. Deaktiveret som standard: puljeeditoren er uændret, og observationsruten returnerer null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Lad en probe, som målet afviste (401/403/429: proxyen videresendte anmodningen, men destinationen afviste denne udgående IP-adresse), nulstille proxyens række af fortløbende fejl i proxyens helbredskontrol, ligesom en besvaret probe. Deaktiveret som standard: En afvisning forbliver neutral og bevarer rækken. En 5xx forbliver uafklaret i begge tilfælde, og en afvisning fjerner, deaktiverer eller genaktiverer aldrig en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Lad den automatiske oprydningskørsel slette afsluttede (gennemførte/mislykkede/annullerede/udløbne) Batch API-job, der er ældre end OMNIROUTE_BATCH_RETENTION_DAYS, sammen med deres kontrolpunkter pr. linje, og rydde BLOB-indholdet i uploadede filer, hvis deres expires_at er overskredet. Slået fra som standard: Alle eksisterende installationer beholder disse data præcis som før, indtil en operatør aktivt slår funktionen til. Den operatørudløste rute DELETE /api/v1/batches/delete-completed påvirkes ikke uanset indstillingen – den er en separat, ubetinget offentlig API-kontrakt.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Opdatering tilgængelig: v{current} → v{latest}", "cliproxyapiVersion": "Version" }, + "modelCatalog": { + "title": "Models & Combos", + "subtitle": "Gennemse og sundhedstest modeller og combo-routing-pipelines på tværs af alle udbydere.", + "refresh": "Opdater", + "modelsTab": "Modeller", + "combosTab": "Combos", + "catalogSections": "Katalogsektioner", + "loading": "Indlæser...", + "retry": "Prøv igen", + "unableToLoad": "Kunne ikke indlæse modelkataloget.", + "unableToLoadCombos": "Kunne ikke indlæse combos.", + "checkConnection": "Tjek forbindelsen, og prøv igen.", + "noModelsAvailable": "Ingen modeller er tilgængelige endnu.", + "noModelsMatch": "Ingen modeller matcher disse filtre.", + "noCombosAvailable": "Ingen combos er tilgængelige endnu.", + "noCombosMatch": "Ingen combos matcher disse filtre.", + "clearFilters": "Ryd filtre", + "searchModels": "Søg i modeller", + "searchModelsPlaceholder": "Søg efter model, udbyder eller funktion", + "searchCombos": "Søg i combos", + "searchCombosPlaceholder": "Søg efter combonavn, modeller eller beskrivelse", + "modelCountSingle": "model", + "modelCountPlural": "modeller", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Udbyder", + "allProviders": "Alle udbydere", + "type": "Type", + "allTypes": "Alle typer", + "subtype": "Undertype", + "allSubtypes": "Alle undertyper", + "capability": "Funktion", + "allCapabilities": "Alle funktioner", + "pricing": "Priser", + "allPricing": "Alle priser", + "freeOnly": "Kun gratis", + "nonFree": "Standard / Ikke-gratis", + "providerHealth": "Udbydersundhed", + "allHealthStates": "Alle sundhedstilstande", + "healthy": "Sund", + "degraded": "Forringet", + "down": "Nede", + "testResult": "Testresultat", + "allResults": "Alle resultater", + "untested": "Ikke testet", + "statusOk": "OK", + "statusSlow": "Langsom", + "statusError": "Fejl", + "minContext": "Min. kontekst", + "minContextPlaceholder": "f.eks. 32000", + "strategy": "Strategi", + "allStrategies": "Alle strategier", + "status": "Status", + "allStatuses": "Alle statusser", + "active": "Aktiv", + "paused": "Pauset", + "minMembers": "Min. medlemmer", + "minMembersPlaceholder": "f.eks. 1", + "maxMembers": "Maks. medlemmer", + "maxMembersPlaceholder": "f.eks. 10", + "testSelected": "Test valgte ({count})", + "testAllFiltered": "Test alle filtrerede ({count})", + "cancel": "Annuller", + "clearResults": "Ryd resultater", + "testing": "Tester...", + "rateLimited": "Hastighedsbegrænset", + "quotaExceeded": "Kvote overskredet", + "timeout": "Timeout", + "otherError": "Fejl", + "justNow": "Lige nu", + "minutesAgo": "{count}m siden", + "hoursAgo": "{count}t siden", + "tableRegion": "Modelkatalogtabel", + "combosTableRegion": "Combos-katalogtabel", + "tableCaption": "Modelkatalog på tværs af alle udbydere", + "combosTableCaption": "Combos-katalog med sundhedstestresultater", + "selectAllModels": "Vælg alle modeller på denne side", + "selectAllCombos": "Vælg alle combos på denne side", + "selectModel": "Vælg model {name}", + "selectCombo": "Vælg combo {name}", + "model": "Model", + "capabilities": "Egenskaber", + "context": "Kontekst", + "output": "Maks. output", + "flags": "Flag", + "healthTest": "Sundhedstest", + "actions": "Handlinger", + "test": "Test", + "custom": "Brugerdefineret", + "free": "Gratis", + "noFlags": "Ingen pris eller kildeflag rapporteret", + "noCapabilities": "Ingen egenskabsmetadata rapporteret", + "showingModels": "Viser {first}–{last} af {total} modeller", + "showingCombos": "Viser {first}–{last} af {total} kombinationer", + "refreshing": "Opdaterer…", + "refreshFailed": "Opdatering mislykkedes. Viser det senest indlæste katalog.", + "page": "Side {page} af {pageCount}", + "previous": "Forrige", + "next": "Næste", + "combo": "Kombination", + "members": "Medlemmer", + "moreMembers": "+{count} flere" + }, "combos": { "title": "Kombinationer", "description": "Skab modelkombinationer med vægtet routing og fallback-understøttelse", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index a2804dd3a4fb..0644c626b113 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivieren Sie adaptive virtuelle Zulassungsspuren pro Tenant für die Provider-Zustellung (#9654): Ein Burst eines Tenants führt nicht mehr zu 503 bei einem anderen. Die Umgebungsvariable OMNIROUTE_CHAT_VIRTUAL_LANES hat Vorrang vor dieser Dashboard-Einstellung; Änderungen werden erst nach einem Serverneustart wirksam.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Dashboard-Anbieterseiten: Das Kostenlos-Badge wird nur bei Signalen angezeigt, die der Anbieter berücksichtigt — die Heuristik für Anzeigenamen, nicht boolesche Kostenlos-Felder und :free-Suffixe bei registrierten Anbietern ohne dokumentierten kostenlosen Tarif werden nicht mehr verwendet. Bei deaktivierter Option gilt weiterhin die bisherige Badge-Regel.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy-Pools und die kontobasierte Rotation von opencode verwenden einen Proxy, der gerade fehlgeschlagen ist (abgelehnte TCP-Prüfung oder darüber empfangener 429-Statuscode), für einen prozessbezogenen Zeitraum nicht erneut. Dieser Zeitraum verdoppelt sich bei jeder Wiederholung bis zu einer Obergrenze. Es wird kein Proxy-Status gespeichert; wenn alle Kandidaten zurückgestellt wurden, bleibt die Auswahl unverändert. Standardmäßig aktiviert; `false` stellt die einfache Auswahl wieder her.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Für Provider, deren Quota nach Egress-Adresse gebündelt ist: Stuft ein Pool-Mitglied, das die beobachtete Egress-Adresse eines kürzlich abgewiesenen Mitglieds teilt, direkt unter fehlerfreien Mitgliedern ein. Nur Sortierung, niemals ausgeschlossen. Erfordert PROXY_SKIP_RECENTLY_FAILED, welches das ausgelesene Ablehnungssignal erzeugt. Standardmäßig deaktiviert: Die Auswahlreihenfolge entspricht genau der einfachen Rotation.", "featureFlagProxyPoolEgressObservationDescription": "Zeigt im Dashboard unter einem Proxy-Pool an, wie viele beobachtete Egress-IPs dessen Mitglieder in den letzten 24 h genutzt haben, wie viele Verbindungen über sie liefen und wie viele Verbindungen maximal hinter einer einzelnen IP beobachtet wurden. Schreibgeschützt, aus dem Proxy-Protokoll berechnet und niemals für das Routing verwendet. Standardmäßig deaktiviert: Der Pool-Editor bleibt unverändert und die Beobachtungsroute gibt null zurück.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Ermöglicht bei der Proxy-Zustandsprüfung, dass eine vom Ziel abgelehnte Prüfung (401/403/429: Der Proxy hat die Anfrage weitergeleitet, das Ziel hat diese Egress-IP abgelehnt) die Serie aufeinanderfolgender Fehler des Proxys zurücksetzt, wie bei einer erfolgreich beantworteten Prüfung. Standardmäßig deaktiviert: Eine Ablehnung bleibt neutral und die Serie wird beibehalten. Ein 5xx-Status bleibt in beiden Fällen nicht aussagekräftig, und eine Ablehnung entfernt, deaktiviert oder reaktiviert niemals einen Proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Erlaubt dem automatischen Bereinigungslauf, beendete Batch-API-Aufträge (completed/failed/cancelled/expired), die älter als OMNIROUTE_BATCH_RETENTION_DAYS sind, zusammen mit ihren zeilenweisen Prüfpunkten zu löschen und den BLOB-Inhalt hochgeladener Dateien nach Ablauf ihres jeweiligen expires_at zu leeren. Standardmäßig deaktiviert: Jede bestehende Installation behält diese Daten genau wie bisher, bis ein Betreiber die Funktion aktiviert. Die vom Betreiber ausgelöste Route DELETE /api/v1/batches/delete-completed bleibt unabhängig davon unverändert – sie ist ein separater, bedingungslos geltender öffentlicher API-Vertrag.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Update verfügbar: v{current} → v{latest}", "cliproxyapiVersion": "Version" }, + "modelCatalog": { + "title": "Models & Combos", + "subtitle": "Modelle und Combo-Routing-Pipelines über alle Anbieter hinweg durchsuchen und auf Funktionsfähigkeit testen.", + "refresh": "Aktualisieren", + "modelsTab": "Modelle", + "combosTab": "Combos", + "catalogSections": "Katalogbereiche", + "loading": "Wird geladen...", + "retry": "Wiederholen", + "unableToLoad": "Der Modellkatalog konnte nicht geladen werden.", + "unableToLoadCombos": "Combos konnten nicht geladen werden.", + "checkConnection": "Überprüfen Sie die Verbindung und versuchen Sie es erneut.", + "noModelsAvailable": "Noch keine Modelle verfügbar.", + "noModelsMatch": "Keine Modelle entsprechen diesen Filtern.", + "noCombosAvailable": "Noch keine Combos verfügbar.", + "noCombosMatch": "Keine Combos entsprechen diesen Filtern.", + "clearFilters": "Filter zurücksetzen", + "searchModels": "Modelle suchen", + "searchModelsPlaceholder": "Nach Modell, Anbieter oder Fähigkeit suchen", + "searchCombos": "Combos suchen", + "searchCombosPlaceholder": "Nach Combo-Name, Modellen oder Beschreibung suchen", + "modelCountSingle": "Modell", + "modelCountPlural": "Modelle", + "comboCountSingle": "Combo", + "comboCountPlural": "Combos", + "provider": "Anbieter", + "allProviders": "Alle Anbieter", + "type": "Typ", + "allTypes": "Alle Typen", + "subtype": "Untertyp", + "allSubtypes": "Alle Untertypen", + "capability": "Fähigkeit", + "allCapabilities": "Alle Fähigkeiten", + "pricing": "Preise", + "allPricing": "Alle Preise", + "freeOnly": "Nur kostenlos", + "nonFree": "Standard / Kostenpflichtig", + "providerHealth": "Anbieter-Zustand", + "allHealthStates": "Alle Zustände", + "healthy": "Betriebsbereit", + "degraded": "Eingeschränkt", + "down": "Ausgefallen", + "testResult": "Testergebnis", + "allResults": "Alle Ergebnisse", + "untested": "Nicht getestet", + "statusOk": "OK", + "statusSlow": "Langsam", + "statusError": "Fehler", + "minContext": "Min. Kontext", + "minContextPlaceholder": "z. B. 32000", + "strategy": "Strategie", + "allStrategies": "Alle Strategien", + "status": "Status", + "allStatuses": "Alle Status", + "active": "Aktiv", + "paused": "Pausiert", + "minMembers": "Min. Mitglieder", + "minMembersPlaceholder": "z. B. 1", + "maxMembers": "Max. Mitglieder", + "maxMembersPlaceholder": "z. B. 10", + "testSelected": "Ausgewählte testen ({count})", + "testAllFiltered": "Alle gefilterten testen ({count})", + "cancel": "Abbrechen", + "clearResults": "Ergebnisse löschen", + "testing": "Wird getestet...", + "rateLimited": "Rate-Limit erreicht", + "quotaExceeded": "Kontingent überschritten", + "timeout": "Zeitüberschreitung", + "otherError": "Fehler", + "justNow": "Gerade eben", + "minutesAgo": "vor {count} Min.", + "hoursAgo": "vor {count} Std.", + "tableRegion": "Modellkatalog-Tabelle", + "combosTableRegion": "Combos-Katalog-Tabelle", + "tableCaption": "Modellkatalog über alle Anbieter", + "combosTableCaption": "Combos-Katalog mit Health-Testergebnissen", + "selectAllModels": "Alle Modelle auf dieser Seite auswählen", + "selectAllCombos": "Alle Combos auf dieser Seite auswählen", + "selectModel": "Modell {name} auswählen", + "selectCombo": "Combo {name} auswählen", + "model": "Modell", + "capabilities": "Fähigkeiten", + "context": "Kontext", + "output": "Maximale Ausgabe", + "flags": "Flags", + "healthTest": "Health-Test", + "actions": "Aktionen", + "test": "Testen", + "custom": "Benutzerdefiniert", + "free": "Kostenlos", + "noFlags": "Kein Preis- oder Quell-Flag gemeldet", + "noCapabilities": "Keine Fähigkeits-Metadaten gemeldet", + "showingModels": "Zeige {first}–{last} von {total} Modellen", + "showingCombos": "Zeige {first}–{last} von {total} Kombinationen", + "refreshing": "Wird aktualisiert…", + "refreshFailed": "Aktualisierung fehlgeschlagen. Der zuletzt geladene Katalog wird angezeigt.", + "page": "Seite {page} von {pageCount}", + "previous": "Zurück", + "next": "Weiter", + "combo": "Kombination", + "members": "Mitglieder", + "moreMembers": "+{count} weitere" + }, "combos": { "title": "Kombinationen", "description": "Erstellen Sie Modellkombinationen mit gewichtetem Routing und Fallback-Unterstützung", diff --git a/src/i18n/messages/el.json b/src/i18n/messages/el.json index 2cd37945cd06..a4397106ad13 100644 --- a/src/i18n/messages/el.json +++ b/src/i18n/messages/el.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ενεργοποίηση προσαρμοστικών εικονικών λωρίδων αποδοχής ανά μισθωτή για αποστολή παρόχου (#9654): η αιχμή κίνησης ενός μισθωτή δεν προκαλεί πλέον σφάλματα 503 σε άλλον. Η μεταβλητή περιβάλλοντος OMNIROUTE_CHAT_VIRTUAL_LANES υπερισχύει αυτής της παράκαμψης του πίνακα ελέγχου· οι αλλαγές τίθενται σε ισχύ κατά την επανεκκίνηση του διακομιστή.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Σελίδες παρόχων στον πίνακα ελέγχου: εμφάνιση του σήματος «Δωρεάν» μόνο για ενδείξεις που αναγνωρίζει ο πάροχος — καταργεί τη χρήση του εμφανιζόμενου ονόματος ως ευρετικής μεθόδου, τα μη δυαδικά πεδία δωρεάν χρήσης και τις καταλήξεις :free σε καταχωρισμένους παρόχους χωρίς τεκμηριωμένο δωρεάν επίπεδο. Όταν είναι ανενεργό, διατηρείται ο παλαιότερος κανόνας εμφάνισης του σήματος.", "featureFlagProxySkipRecentlyFailedDescription": "Οι ομάδες διακομιστών μεσολάβησης και η εναλλαγή ανά λογαριασμό του opencode παύουν να χρησιμοποιούν ξανά έναν διακομιστή μεσολάβησης που μόλις απέτυχε (απορρίφθηκε η δοκιμή TCP ή λήφθηκε απόκριση 429 μέσω αυτού) για ένα χρονικό διάστημα ανά διεργασία, το οποίο διπλασιάζεται σε κάθε επανάληψη, έως ένα ανώτατο όριο. Δεν καταγράφεται καμία κατάσταση διακομιστή μεσολάβησης· όταν όλοι οι υποψήφιοι παραμερίζονται, η επιλογή παραμένει αμετάβλητη. Ενεργοποιημένο από προεπιλογή· το `false` επαναφέρει την απλή επιλογή.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Για παρόχους των οποίων το quota ομαδοποιείται ανά διεύθυνση εξόδου, ταξινομήστε ένα μέλος του pool που μοιράζεται την παρατηρηθείσα διεύθυνση εξόδου ενός μέλους που απορρίφθηκε πρόσφατα ακριβώς κάτω από τα υγιή μέλη. Μόνο σειρά, ποτέ αποκλεισμός. Απαιτεί το PROXY_SKIP_RECENTLY_FAILED, το οποίο παράγει το σήμα απόρριψης που διαβάζει. Ανενεργό από προεπιλογή: η σειρά επιλογής είναι ακριβώς η απλή κυκλική εναλλαγή.", "featureFlagProxyPoolEgressObservationDescription": "Εμφάνιση, κάτω από μια ομάδα διακομιστών μεσολάβησης στον πίνακα ελέγχου, του αριθμού των παρατηρούμενων IP εξόδου που εξυπηρέτησαν τα μέλη της κατά τις τελευταίες 24 ώρες, του αριθμού των συνδέσεων που τις χρησιμοποίησαν και του μεγαλύτερου αριθμού συνδέσεων που παρατηρήθηκε πίσω από μία IP. Μόνο για ανάγνωση, υπολογίζεται από το αρχείο καταγραφής του διακομιστή μεσολάβησης και δεν χρησιμοποιείται ποτέ για δρομολόγηση. Απενεργοποιημένο από προεπιλογή: το πρόγραμμα επεξεργασίας της ομάδας παραμένει αμετάβλητο και η διαδρομή παρατήρησης επιστρέφει null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Κατά τον έλεγχο εύρυθμης λειτουργίας των διακομιστών μεσολάβησης, να επιτρέπεται σε μια δοκιμή που απορρίφθηκε από τον προορισμό (401/403/429: ο διακομιστής μεσολάβησης προώθησε το αίτημα, αλλά ο προορισμός απέρριψε αυτήν την IP εξόδου) να μηδενίζει το συνεχόμενο σερί αποτυχιών του διακομιστή μεσολάβησης, όπως μια δοκιμή που εξυπηρετήθηκε. Απενεργοποιημένο από προεπιλογή: μια απόρριψη παραμένει ουδέτερη και διατηρεί το σερί. Μια απόκριση 5xx παραμένει ασαφής και στις δύο περιπτώσεις, ενώ μια απόρριψη δεν αφαιρεί, δεν απενεργοποιεί και δεν επανενεργοποιεί ποτέ έναν διακομιστή μεσολάβησης.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Να επιτρέπεται στην αυτόματη εκκαθάριση να διαγράφει οριστικές (ολοκληρωμένες/αποτυχημένες/ακυρωμένες/ληγμένες) εργασίες Batch API παλαιότερες από OMNIROUTE_BATCH_RETENTION_DAYS, μαζί με τα σημεία ελέγχου ανά γραμμή, και να διαγράφει το περιεχόμενο BLOB των μεταφορτωμένων αρχείων μετά το δικό τους expires_at. Απενεργοποιημένο από προεπιλογή: κάθε υπάρχουσα εγκατάσταση διατηρεί αυτά τα δεδομένα ακριβώς όπως πριν, έως ότου ένας διαχειριστής ενεργοποιήσει τη λειτουργία. Η διαδρομή DELETE /api/v1/batches/delete-completed που ενεργοποιείται από τον διαχειριστή παραμένει ανεπηρέαστη σε κάθε περίπτωση — αποτελεί ξεχωριστή, άνευ όρων δημόσια σύμβαση API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Διαθέσιμη ενημέρωση: v{current} → v{latest}", "cliproxyapiVersion": "Έκδοση" }, + "modelCatalog": { + "title": "Μοντέλα & Συνδυασμοί", + "subtitle": "Περιηγηθείτε και ελέγξτε την κατάσταση υγείας μοντέλων και αγωγών δρομολόγησης συνδυασμών σε όλους τους παρόχους.", + "refresh": "Ανανέωση", + "modelsTab": "Μοντέλα", + "combosTab": "Συνδυασμοί", + "catalogSections": "Ενότητες καταλόγου", + "loading": "Φόρτωση...", + "retry": "Επανάληψη", + "unableToLoad": "Αδυναμία φόρτωσης του καταλόγου μοντέλων.", + "unableToLoadCombos": "Αδυναμία φόρτωσης συνδυασμών.", + "checkConnection": "Ελέγξτε τη σύνδεση και δοκιμάστε ξανά.", + "noModelsAvailable": "Δεν υπάρχουν διαθέσιμα μοντέλα ακόμα.", + "noModelsMatch": "Κανένα μοντέλο δεν ταιριάζει με αυτά τα φίλτρα.", + "noCombosAvailable": "Δεν υπάρχουν διαθέσιμοι συνδυασμοί ακόμα.", + "noCombosMatch": "Κανένας συνδυασμός δεν ταιριάζει με αυτά τα φίλτρα.", + "clearFilters": "Καθαρισμός φίλτρων", + "searchModels": "Αναζήτηση μοντέλων", + "searchModelsPlaceholder": "Αναζήτηση βάσει μοντέλου, παρόχου ή δυνατότητας", + "searchCombos": "Αναζήτηση συνδυασμών", + "searchCombosPlaceholder": "Αναζήτηση βάσει ονόματος συνδυασμού, μοντέλων ή περιγραφής", + "modelCountSingle": "μοντέλο", + "modelCountPlural": "μοντέλα", + "comboCountSingle": "συνδυασμός", + "comboCountPlural": "συνδυασμοί", + "provider": "Πάροχος", + "allProviders": "Όλοι οι πάροχοι", + "type": "Τύπος", + "allTypes": "Όλοι οι τύποι", + "subtype": "Υποτύπος", + "allSubtypes": "Όλοι οι υποτύποι", + "capability": "Δυνατότητα", + "allCapabilities": "Όλες οι δυνατότητες", + "pricing": "Τιμολόγηση", + "allPricing": "Όλες οι τιμολογήσεις", + "freeOnly": "Μόνο δωρεάν", + "nonFree": "Τυπικό / Μη δωρεάν", + "providerHealth": "Υγεία παρόχου", + "allHealthStates": "Όλες οι καταστάσεις υγείας", + "healthy": "Υγιές", + "degraded": "Υποβαθμισμένο", + "down": "Εκτός λειτουργίας", + "testResult": "Αποτέλεσμα δοκιμής", + "allResults": "Όλα τα αποτελέσματα", + "untested": "Μη δοκιμασμένο", + "statusOk": "OK", + "statusSlow": "Αργό", + "statusError": "Σφάλμα", + "minContext": "Ελάχιστο context", + "minContextPlaceholder": "π.χ. 32000", + "strategy": "Στρατηγική", + "allStrategies": "Όλες οι στρατηγικές", + "status": "Κατάσταση", + "allStatuses": "Όλες οι καταστάσεις", + "active": "Ενεργό", + "paused": "Σε παύση", + "minMembers": "Ελάχιστα μέλη", + "minMembersPlaceholder": "π.χ. 1", + "maxMembers": "Μέγιστα μέλη", + "maxMembersPlaceholder": "π.χ. 10", + "testSelected": "Δοκιμή επιλεγμένων ({count})", + "testAllFiltered": "Δοκιμή όλων των φιλτραρισμένων ({count})", + "cancel": "Ακύρωση", + "clearResults": "Εκκαθάριση αποτελεσμάτων", + "testing": "Γίνεται δοκιμή...", + "rateLimited": "Περιορισμός ρυθμού (Rate limited)", + "quotaExceeded": "Υπέρβαση ορίου χρήσης", + "timeout": "Λήξη χρονικού ορίου", + "otherError": "Σφάλμα", + "justNow": "Μόλις τώρα", + "minutesAgo": "{count}λ πριν", + "hoursAgo": "{count}ώ πριν", + "tableRegion": "Πίνακας καταλόγου μοντέλων", + "combosTableRegion": "Πίνακας καταλόγου συνδυασμών", + "tableCaption": "Κατάλογος μοντέλων σε όλους τους παρόχους", + "combosTableCaption": "Κατάλογος συνδυασμών με αποτελέσματα ελέγχων υγείας", + "selectAllModels": "Επιλογή όλων των μοντέλων σε αυτή τη σελίδα", + "selectAllCombos": "Επιλογή όλων των συνδυασμών σε αυτή τη σελίδα", + "selectModel": "Επιλογή μοντέλου {name}", + "selectCombo": "Επιλογή συνδυασμού {name}", + "model": "Μοντέλο", + "capabilities": "Δυνατότητες", + "context": "Πλαίσιο", + "output": "Μέγιστη έξοδος", + "flags": "Σημαίες", + "healthTest": "Έλεγχος υγείας", + "actions": "Ενέργειες", + "test": "Δοκιμή", + "custom": "Προσαρμοσμένο", + "free": "Δωρεάν", + "noFlags": "Δεν αναφέρθηκε σημαία τιμής ή πηγής", + "noCapabilities": "Δεν αναφέρθηκαν μεταδεδομένα δυνατοτήτων", + "showingModels": "Εμφάνιση {first}–{last} από {total} μοντέλα", + "showingCombos": "Εμφάνιση {first}–{last} από {total} συνδυασμούς", + "refreshing": "Ανανέωση…", + "refreshFailed": "Η ανανέωση απέτυχε. Εμφάνιση του τελευταίου καταλόγου που φορτώθηκε.", + "page": "Σελίδα {page} από {pageCount}", + "previous": "Προηγούμενο", + "next": "Επόμενο", + "combo": "Συνδυασμός", + "members": "Μέλη", + "moreMembers": "+{count} ακόμη" + }, "combos": { "title": "Συνδυασμοί", "description": "Δημιουργήστε συνδυασμούς μοντέλων με σταθμισμένη δρομολόγηση και υποστήριξη εφεδρικών επιλογών", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index fcdbecca8b21..ce3c1de396fb 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -3217,6 +3217,109 @@ "cliproxyapiUpdateAvailable": "Update available: v{current} → v{latest}", "cliproxyapiVersion": "Version" }, + "modelCatalog": { + "title": "Models & Combos", + "subtitle": "Browse and health-test models and combo routing pipelines across every provider.", + "refresh": "Refresh", + "modelsTab": "Models", + "combosTab": "Combos", + "catalogSections": "Catalog Sections", + "loading": "Loading...", + "retry": "Retry", + "unableToLoad": "Unable to load the model catalog.", + "unableToLoadCombos": "Unable to load combos.", + "checkConnection": "Check the connection and try again.", + "noModelsAvailable": "No models are available yet.", + "noModelsMatch": "No models match these filters.", + "noCombosAvailable": "No combos are available yet.", + "noCombosMatch": "No combos match these filters.", + "clearFilters": "Clear filters", + "searchModels": "Search models", + "searchModelsPlaceholder": "Search by model, provider, or capability", + "searchCombos": "Search combos", + "searchCombosPlaceholder": "Search by combo name, models, or description", + "modelCountSingle": "model", + "modelCountPlural": "models", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Provider", + "allProviders": "All providers", + "type": "Type", + "allTypes": "All types", + "subtype": "Subtype", + "allSubtypes": "All subtypes", + "capability": "Capability", + "allCapabilities": "All capabilities", + "pricing": "Pricing", + "allPricing": "All pricing", + "freeOnly": "Free only", + "nonFree": "Standard / Non-free", + "providerHealth": "Provider health", + "allHealthStates": "All health states", + "healthy": "Healthy", + "degraded": "Degraded", + "down": "Down", + "testResult": "Test result", + "allResults": "All results", + "untested": "Untested", + "statusOk": "OK", + "statusSlow": "Slow", + "statusError": "Error", + "minContext": "Min context", + "minContextPlaceholder": "e.g. 32000", + "strategy": "Strategy", + "allStrategies": "All strategies", + "status": "Status", + "allStatuses": "All statuses", + "active": "Active", + "paused": "Paused", + "minMembers": "Min members", + "minMembersPlaceholder": "e.g. 1", + "maxMembers": "Max members", + "maxMembersPlaceholder": "e.g. 10", + "testSelected": "Test selected ({count})", + "testAllFiltered": "Test all filtered ({count})", + "cancel": "Cancel", + "clearResults": "Clear results", + "testing": "Testing...", + "rateLimited": "Rate limited", + "quotaExceeded": "Quota exceeded", + "timeout": "Timed out", + "otherError": "Error", + "justNow": "Just now", + "minutesAgo": "{count}m ago", + "hoursAgo": "{count}h ago", + "tableRegion": "Model catalog table", + "combosTableRegion": "Combos catalog table", + "tableCaption": "Model catalog across all providers", + "combosTableCaption": "Combos catalog with health test results", + "selectAllModels": "Select all models on this page", + "selectAllCombos": "Select all combos on this page", + "selectModel": "Select model {name}", + "selectCombo": "Select combo {name}", + "model": "Model", + "capabilities": "Capabilities", + "context": "Context", + "output": "Max output", + "flags": "Flags", + "healthTest": "Health Test", + "actions": "Actions", + "test": "Test", + "custom": "Custom", + "free": "Free", + "noFlags": "No price or source flag reported", + "noCapabilities": "No capability metadata reported", + "showingModels": "Showing {first}–{last} of {total} models", + "showingCombos": "Showing {first}–{last} of {total} combos", + "refreshing": "Refreshing…", + "refreshFailed": "Refresh failed. Showing the last loaded catalog.", + "page": "Page {page} of {pageCount}", + "previous": "Previous", + "next": "Next", + "combo": "Combo", + "members": "Members", + "moreMembers": "+{count} more" + }, "combos": { "title": "Combos", "description": "Create model combos with weighted routing and fallback support", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index f9db1e57d523..445d52f001ff 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activa carriles de admisión virtuales adaptativos por tenant para el envío de proveedores (#9654): el pico de un tenant ya no devuelve 503 a otro. La variable de entorno OMNIROUTE_CHAT_VIRTUAL_LANES tiene prioridad sobre esta opción del panel; los cambios surten efecto al reiniciar el servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de proveedores del panel: muestra la insignia Gratis solo cuando haya indicios de que el proveedor la admite; descarta la heurística basada en el nombre para mostrar, los campos free no booleanos y los sufijos :free en proveedores registrados sin un nivel gratuito documentado. Si está desactivado, se mantiene la regla histórica de la insignia.", "featureFlagProxySkipRecentlyFailedDescription": "Los grupos de proxies y la rotación por cuenta de opencode dejan de reutilizar temporalmente un proxy que acaba de fallar (sondeo TCP rechazado o un 429 recibido a través de él) durante un período por proceso que se duplica con cada repetición, hasta alcanzar un límite. No se registra ningún estado del proxy; si se apartan todos los candidatos, la elección no cambia. Activado de forma predeterminada; `false` restaura la selección normal.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Para los proveedores cuya cuota se agrupa por dirección de salida, sitúa a un miembro del pool que comparta la dirección de salida observada de un miembro recientemente rechazado justo por debajo de los miembros en buen estado. Solo afecta al orden, nunca se excluye. Requiere PROXY_SKIP_RECENTLY_FAILED, que genera la señal de rechazo que lee. Desactivado por defecto: el orden de selección es exactamente la rotación habitual.", "featureFlagProxyPoolEgressObservationDescription": "Mostrar, debajo de un grupo de proxies en el panel, cuántas IP de salida observadas utilizaron sus miembros durante las últimas 24 h, cuántas conexiones las usaron y el máximo observado detrás de una sola IP. Es de solo lectura, se calcula a partir del registro del proxy y nunca se utiliza para el enrutamiento. Desactivado de forma predeterminada: el editor de grupos no cambia y la ruta de observación devuelve null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "En la comprobación periódica del estado de los proxies, permitir que un sondeo rechazado por el destino (401/403/429: el proxy lo retransmitió, pero el destino rechazó esta IP de salida) reinicie la racha de fallos consecutivos del proxy, como un sondeo atendido. Desactivado de forma predeterminada: un rechazo sigue siendo neutral y mantiene la racha. Un 5xx sigue sin ser concluyente en ambos casos, y un rechazo nunca elimina, desactiva ni reactiva un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permitir que la limpieza automática elimine los trabajos de la API de lotes en estado terminal (completados/fallidos/cancelados/caducados) con una antigüedad superior a OMNIROUTE_BATCH_RETENTION_DAYS, junto con sus puntos de control por línea, y borre el contenido BLOB de los archivos subidos que hayan superado su propio expires_at. Desactivado de forma predeterminada: todas las instalaciones existentes conservan estos datos exactamente como antes hasta que un operador active esta opción. La ruta DELETE /api/v1/batches/delete-completed, activada por el operador, no se ve afectada en ningún caso: es un contrato de API pública independiente e incondicional.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Actualización disponible: v{current} → v{latest}", "cliproxyapiVersion": "Versión" }, + "modelCatalog": { + "title": "Modelos y combos", + "subtitle": "Explora y prueba el estado de modelos y canalizaciones de enrutamiento de combos en todos los proveedores.", + "refresh": "Actualizar", + "modelsTab": "Modelos", + "combosTab": "Combos", + "catalogSections": "Secciones del catálogo", + "loading": "Cargando...", + "retry": "Reintentar", + "unableToLoad": "No se pudo cargar el catálogo de modelos.", + "unableToLoadCombos": "No se pudieron cargar los combos.", + "checkConnection": "Comprueba la conexión e inténtalo de nuevo.", + "noModelsAvailable": "Todavía no hay modelos disponibles.", + "noModelsMatch": "Ningún modelo coincide con estos filtros.", + "noCombosAvailable": "Todavía no hay combos disponibles.", + "noCombosMatch": "Ningún combo coincide con estos filtros.", + "clearFilters": "Borrar filtros", + "searchModels": "Buscar modelos", + "searchModelsPlaceholder": "Buscar por modelo, proveedor o capacidad", + "searchCombos": "Buscar combos", + "searchCombosPlaceholder": "Buscar por nombre de combo, modelos o descripción", + "modelCountSingle": "modelo", + "modelCountPlural": "modelos", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Proveedor", + "allProviders": "Todos los proveedores", + "type": "Tipo", + "allTypes": "Todos los tipos", + "subtype": "Subtipo", + "allSubtypes": "Todos los subtipos", + "capability": "Capacidad", + "allCapabilities": "Todas las capacidades", + "pricing": "Precios", + "allPricing": "Todos los precios", + "freeOnly": "Solo gratuitos", + "nonFree": "Estándar / De pago", + "providerHealth": "Estado del proveedor", + "allHealthStates": "Todos los estados", + "healthy": "Saludable", + "degraded": "Degradado", + "down": "Caído", + "testResult": "Resultado de la prueba", + "allResults": "Todos los resultados", + "untested": "Sin probar", + "statusOk": "OK", + "statusSlow": "Lento", + "statusError": "Error", + "minContext": "Contexto mínimo", + "minContextPlaceholder": "ej. 32000", + "strategy": "Estrategia", + "allStrategies": "Todas las estrategias", + "status": "Estado", + "allStatuses": "Todos los estados", + "active": "Activo", + "paused": "En pausa", + "minMembers": "Miembros mínimos", + "minMembersPlaceholder": "ej. 1", + "maxMembers": "Miembros máximos", + "maxMembersPlaceholder": "ej. 10", + "testSelected": "Probar seleccionados ({count})", + "testAllFiltered": "Probar todos los filtrados ({count})", + "cancel": "Cancelar", + "clearResults": "Limpiar resultados", + "testing": "Probando...", + "rateLimited": "Límite de peticiones alcanzado", + "quotaExceeded": "Cuota excedida", + "timeout": "Tiempo de espera agotado", + "otherError": "Error", + "justNow": "Hace un momento", + "minutesAgo": "Hace {count}m", + "hoursAgo": "Hace {count}h", + "tableRegion": "Tabla del catálogo de modelos", + "combosTableRegion": "Tabla del catálogo de combos", + "tableCaption": "Catálogo de modelos de todos los proveedores", + "combosTableCaption": "Catálogo de combos con resultados de pruebas de estado", + "selectAllModels": "Seleccionar todos los modelos de esta página", + "selectAllCombos": "Seleccionar todos los combos de esta página", + "selectModel": "Seleccionar modelo {name}", + "selectCombo": "Seleccionar combo {name}", + "model": "Modelo", + "capabilities": "Capacidades", + "context": "Contexto", + "output": "Salida máxima", + "flags": "Indicadores", + "healthTest": "Prueba de estado", + "actions": "Acciones", + "test": "Probar", + "custom": "Personalizado", + "free": "Gratis", + "noFlags": "No se reportó ningún precio ni indicador de origen", + "noCapabilities": "No se reportaron metadatos de capacidades", + "showingModels": "Mostrando {first}–{last} de {total} modelos", + "showingCombos": "Mostrando {first}–{last} de {total} combos", + "refreshing": "Actualizando…", + "refreshFailed": "Error al actualizar. Mostrando el último catálogo cargado.", + "page": "Página {page} de {pageCount}", + "previous": "Anterior", + "next": "Siguiente", + "combo": "Combo", + "members": "Miembros", + "moreMembers": "+{count} más" + }, "combos": { "title": "combos", "description": "Cree combinaciones de modelos con enrutamiento ponderado y soporte alternativo", diff --git a/src/i18n/messages/et.json b/src/i18n/messages/et.json index 5964c99d3a06..08dcc987dc72 100644 --- a/src/i18n/messages/et.json +++ b/src/i18n/messages/et.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Lubage pakkujale edastamiseks rentnikupõhised kohanduvad virtuaalsed vastuvõturajad (#9654): ühe rentniku koormushoog ei põhjusta enam teisele tõrget 503. Keskkonnamuutuja OMNIROUTE_CHAT_VIRTUAL_LANES alistab selle juhtpaneeli sätte; muudatused jõustuvad serveri taaskäivitamisel.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Juhtpaneeli teenusepakkujate lehed: kuva märk „Tasuta” ainult nende tunnuste puhul, mida teenusepakkuja arvestab — loobu kuvatava nime heuristikast, mitte-tõeväärtuslikest tasuta kasutust tähistavatest väljadest ja järelliidetest :free registreeritud teenusepakkujate puhul, kellel puudub dokumenteeritud tasuta pakett. Väljalülitamisel kasutatakse varasemat märgi kuvamise reeglit.", "featureFlagProxySkipRecentlyFailedDescription": "Puhverserverite kogumid ja opencode'i kontopõhine roteerimine väldivad äsja nurjunud puhverserveri (TCP-proovist keelduti või selle kaudu saadi vastus 429) uuesti kasutamist protsessipõhise ajavahemiku jooksul, mis iga korduva tõrke korral kahekordistub kuni ülempiirini. Puhverserveri olekut ei salvestata; kui kõik kandidaadid kõrvale jäetakse, valik ei muutu. Vaikimisi sees; `false` taastab tavalise valiku.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Pakkujate puhul, kelle kvoot on jaotatud väljuva aadressi alusel, reastatakse hiljuti tagasi lükatud liikme tuvastatud väljuvat aadressi jagav kogumi liige vahetult tervete liikmete järele. Ainult järjestus, ei välistata kunagi. Vajab sätet PROXY_SKIP_RECENTLY_FAILED, mis tekitab selle loetava keeldumissignaali. Vaikimisi väljas: valikujärjekord on täpselt tavapärane rotatsioon.", "featureFlagProxyPoolEgressObservationDescription": "Kuva juhtpaneelil puhverserverite kogumi all, mitu vaadeldud väljuvat IP-aadressi teenindas selle liikmeid viimase 24 tunni jooksul, mitu ühendust neid kasutas ja kui palju ühendusi täheldati enim ühe IP-aadressi taga. Kirjutuskaitstud, arvutatakse puhverserveri logist ja seda ei kasutata kunagi marsruutimiseks. Vaikimisi väljas: kogumi redaktor ei muutu ja vaatlusmarsruut tagastab null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Luba puhverserveri seisundi kontrollimisel sihtkoha poolt tagasi lükatud proovil (401/403/429: puhverserver vahendas päringu, sihtkoht keeldus sellest väljuvast IP-aadressist) lähtestada puhverserveri järjestikuste tõrgete jada nagu teenindatud proovi korral. Vaikimisi väljas: tagasilükkamine jääb neutraalseks ja säilitab jada. 5xx jääb mõlemal juhul ebaselgeks ning tagasilükkamine ei eemalda, keela ega taasaktiveeri kunagi puhverserverit.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Luba automaatsel puhastusel kustutada lõplikus olekus (lõpetatud/ebaõnnestunud/tühistatud/aegunud) Batch API tööd, mis on vanemad kui OMNIROUTE_BATCH_RETENTION_DAYS, koos nende reapõhiste kontrollpunktidega, ning kustutada oma expires_at tähtaja ületanud üleslaaditud failide BLOB-sisu. Vaikimisi väljas: kõik olemasolevad paigaldused säilitavad neid andmeid täpselt nagu varem, kuni operaator selle funktsiooni sisse lülitab. Operaatori käivitatavat marsruuti DELETE /api/v1/batches/delete-completed see valik ei mõjuta — tegemist on eraldiseisva ja tingimusteta avaliku API lepinguga.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Saadaval on värskendus: v{current} → v{latest}", "cliproxyapiVersion": "Versioon" }, + "modelCatalog": { + "title": "Mudelid ja kombod", + "subtitle": "Sirvige ja testige mudelite ning kombode marsruutimisahelate toimivust kõigi pakkujate lõikes.", + "refresh": "Värskenda", + "modelsTab": "Mudelid", + "combosTab": "Kombod", + "catalogSections": "Kataloogi jaotised", + "loading": "Laadimine...", + "retry": "Proovi uuesti", + "unableToLoad": "Mudelikataloogi laadimine ebaõnnestus.", + "unableToLoadCombos": "Kombode laadimine ebaõnnestus.", + "checkConnection": "Kontrollige ühendust ja proovige uuesti.", + "noModelsAvailable": "Ühtegi mudelit pole veel saadaval.", + "noModelsMatch": "Ükski mudel ei vasta neile filtritele.", + "noCombosAvailable": "Ühtegi kombot pole veel saadaval.", + "noCombosMatch": "Ükski kombo ei vasta neile filtritele.", + "clearFilters": "Tühjenda filtrid", + "searchModels": "Otsi mudeleid", + "searchModelsPlaceholder": "Otsi mudeli, pakkuja või võimekuse järgi", + "searchCombos": "Otsi kombosid", + "searchCombosPlaceholder": "Otsi kombo nime, mudelite või kirjelduse järgi", + "modelCountSingle": "mudel", + "modelCountPlural": "mudelid", + "comboCountSingle": "kombo", + "comboCountPlural": "kombod", + "provider": "Pakkuja", + "allProviders": "Kõik pakkujad", + "type": "Tüüp", + "allTypes": "Kõik tüübid", + "subtype": "Alamtüüp", + "allSubtypes": "Kõik alamtüübid", + "capability": "Võimekus", + "allCapabilities": "Kõik võimekused", + "pricing": "Hinnakujundus", + "allPricing": "Kõik hinnad", + "freeOnly": "Ainult tasuta", + "nonFree": "Standardne / Tasuline", + "providerHealth": "Pakkuja seisund", + "allHealthStates": "Kõik seisundid", + "healthy": "Töökorras", + "degraded": "Häiritud", + "down": "Maas", + "testResult": "Testi tulemus", + "allResults": "Kõik tulemused", + "untested": "Testimata", + "statusOk": "OK", + "statusSlow": "Aeglane", + "statusError": "Viga", + "minContext": "Min kontekst", + "minContextPlaceholder": "nt 32000", + "strategy": "Strateegia", + "allStrategies": "Kõik strateegiad", + "status": "Olek", + "allStatuses": "Kõik olekud", + "active": "Aktiivne", + "paused": "Peatatud", + "minMembers": "Min liikmed", + "minMembersPlaceholder": "nt 1", + "maxMembers": "Max liikmed", + "maxMembersPlaceholder": "nt 10", + "testSelected": "Testi valitud ({count})", + "testAllFiltered": "Testi kõiki filtreerituid ({count})", + "cancel": "Tühista", + "clearResults": "Tühjenda tulemused", + "testing": "Testimine...", + "rateLimited": "Päringulimiit ületatud", + "quotaExceeded": "Kvoot ületatud", + "timeout": "Aegus", + "otherError": "Viga", + "justNow": "Just praegu", + "minutesAgo": "{count}m tagasi", + "hoursAgo": "{count}h tagasi", + "tableRegion": "Mudelikataloogi tabel", + "combosTableRegion": "Kombode kataloogi tabel", + "tableCaption": "Mudelikataloog kõigi pakkujate lõikes", + "combosTableCaption": "Kombode kataloog toimivustestide tulemustega", + "selectAllModels": "Vali sellel lehel kõik mudelid", + "selectAllCombos": "Vali sellel lehel kõik kombod", + "selectModel": "Vali mudel {name}", + "selectCombo": "Vali kombo {name}", + "model": "Mudel", + "capabilities": "Võimekused", + "context": "Kontekst", + "output": "Maksimaalne väljund", + "flags": "Lipud", + "healthTest": "Tervisetest", + "actions": "Toimingud", + "test": "Testi", + "custom": "Kohandatud", + "free": "Tasuta", + "noFlags": "Hinna ega allika lippu pole teatatud", + "noCapabilities": "Võimekuse metaandmeid pole teatatud", + "showingModels": "Kuvatakse {first}–{last} mudelit {total}-st", + "showingCombos": "Kuvatakse {first}–{last} kombot {total}-st", + "refreshing": "Värskendamine…", + "refreshFailed": "Värskendamine ebaõnnestus. Kuvatakse viimati laaditud kataloog.", + "page": "Lehekülg {page} / {pageCount}", + "previous": "Eelmine", + "next": "Järgmine", + "combo": "Kombo", + "members": "Liikmed", + "moreMembers": "+{count} veel" + }, "combos": { "title": "Kombinatsioonid", "description": "Loo kaalutud marsruutimise ja varuvalikute toega mudelikombinatsioone", diff --git a/src/i18n/messages/fa.json b/src/i18n/messages/fa.json index 303a4b0ae186..a7435baf52a1 100644 --- a/src/i18n/messages/fa.json +++ b/src/i18n/messages/fa.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "خط‌های پذیرش مجازی تطبیقی به‌ازای هر مستاجر (tenant) را برای ارسال به ارائه‌دهندگان فعال کنید (#9654): افزایش ناگهانی بار یک مستاجر دیگر خطای 503 را برای مستاجر دیگر ایجاد نمی‌کند. متغیر محیطی OMNIROUTE_CHAT_VIRTUAL_LANES بر این تنظیم داشبورد اولویت دارد؛ تغییرات پس از راه‌اندازی مجدد سرور اعمال می‌شوند.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "صفحههای ارائهدهندگان در داشبورد: نشان «رایگان» را فقط برای سیگنالهایی نمایش دهید که ارائهدهنده آنها را معتبر میداند — روش اکتشافی نام نمایشی، فیلدهای رایگانِ غیربولین و پسوندهای :free برای ارائهدهندگان ثبتشدهای که سطح رایگان مستندی ندارند، کنار گذاشته میشوند. در حالت خاموش، قاعده تاریخی نشان حفظ میشود.", "featureFlagProxySkipRecentlyFailedDescription": "مخزنهای پراکسی و چرخش بهازای هر حساب در opencode، پراکسیای را که بهتازگی ناموفق بوده است (کاوش TCP را رد کرده یا از طریق آن پاسخ 429 دریافت شده است)، برای مدتی مختص هر فرایند دوباره به کار نمیگیرند؛ این مدت با هر تکرار دو برابر میشود تا به سقف تعیینشده برسد. هیچ وضعیتی برای پراکسی ثبت نمیشود؛ اگر همه گزینهها کنار گذاشته شوند، انتخاب بدون تغییر میماند. به‌طور پیش‌فرض فعال است؛ `false` انتخاب ساده را بازمی‌گرداند.", - "featureFlagProxyPoolSharedEgressOrderDescription": "برای ارائه‌دهندگانی که سهمیه آن‌ها بر اساس آدرس خروجی دسته‌بندی می‌شود، عضوی از استخر که آدرس خروجی مشاهده‌شده آن با عضوی که اخیراً رد شده مشترک است، دقیقاً پس از اعضای سالم رتبه‌بندی می‌شود. فقط در اولویت‌بندی است و هرگز مستثنی نمی‌شود. نیازمند PROXY_SKIP_RECENTLY_FAILED است که سیگنال رد شدن را برای خواندن تولید می‌کند. به‌طور پیش‌فرض غیرفعال است: ترتیب انتخاب دقیقاً همان چرخش عادی است.", "featureFlagProxyPoolEgressObservationDescription": "در داشبورد، زیر هر مخزن پراکسی نشان دهید که طی ۲۴ ساعت گذشته چه تعداد IP خروجی مشاهدهشده به اعضای آن سرویس دادهاند، چه تعداد اتصال از آنها استفاده کردهاند و بیشترین تعداد اتصال مشاهدهشده پشت یک IP چقدر بوده است. این اطلاعات فقط خواندنی است، از گزارش پراکسی محاسبه میشود و هرگز برای مسیریابی استفاده نمیشود. بهطور پیشفرض غیرفعال است: ویرایشگر مخزن بدون تغییر میماند و مسیر مشاهده مقدار null را برمیگرداند.", "featureFlagProxyHealthBlockedResetsStreakDescription": "در پیمایش سلامت پراکسی، اجازه دهید کاوشی که هدف آن را رد کرده است (401/403/429: پراکسی درخواست را عبور داده، اما مقصد این IP خروجی را رد کرده است)، مانند یک کاوش پاسخدادهشده، شمارنده شکستهای متوالی پراکسی را بازنشانی کند. بهطور پیشفرض غیرفعال است: رد شدن همچنان خنثی باقی میماند و شمارنده را حفظ میکند. پاسخ 5xx در هر دو حالت نامشخص باقی میماند و رد شدن هرگز باعث حذف، غیرفعالسازی یا فعالسازی مجدد پراکسی نمیشود.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "به فرایند پاکسازی خودکار اجازه دهید کارهای نهاییشده Batch API (تکمیلشده/ناموفق/لغوشده/منقضیشده) را که بیش از OMNIROUTE_BATCH_RETENTION_DAYS از عمرشان گذشته است، بههمراه نقاط بررسی هر خط آنها حذف کند و محتوای BLOB فایلهای بارگذاریشدهای را که از expires_at خود گذشتهاند پاک کند. بهطور پیشفرض خاموش است: تا زمانی که اپراتور آن را فعال نکند، هر نصب موجود این دادهها را دقیقاً مانند قبل نگه میدارد. مسیر DELETE /api/v1/batches/delete-completed که توسط اپراتور فعال میشود، در هر دو حالت بدون تغییر باقی میماند — این مسیر یک قرارداد API عمومی، مستقل و بدون شرط است.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "به‌روزرسانی موجود است: v{current} → v{latest}", "cliproxyapiVersion": "نسخه" }, + "modelCatalog": { + "title": "مدل‌ها و ترکیب‌ها", + "subtitle": "مرور و ارزیابی سلامت مدل‌ها و خطوط لوله مسیریابی ترکیبی در تمام ارائه‌دهندگان.", + "refresh": "تازه‌سازی", + "modelsTab": "مدل‌ها", + "combosTab": "ترکیب‌ها", + "catalogSections": "بخش‌های کاتالوگ", + "loading": "در حال بارگذاری...", + "retry": "تلاش مجدد", + "unableToLoad": "بارگذاری کاتالوگ مدل‌ها امکان‌پذیر نیست.", + "unableToLoadCombos": "بارگذاری ترکیب‌ها امکان‌پذیر نیست.", + "checkConnection": "اتصال را بررسی کرده و دوباره امتحان کنید.", + "noModelsAvailable": "هنوز هیچ مدلی در دسترس نیست.", + "noModelsMatch": "هیچ مدلی با این فیلترها مطابقت ندارد.", + "noCombosAvailable": "هنوز هیچ ترکیبی در دسترس نیست.", + "noCombosMatch": "هیچ ترکیبی با این فیلترها مطابقت ندارد.", + "clearFilters": "پاک کردن فیلترها", + "searchModels": "جستجوی مدل‌ها", + "searchModelsPlaceholder": "جستجو بر اساس مدل، ارائه‌دهنده یا قابلیت", + "searchCombos": "جستجوی ترکیب‌ها", + "searchCombosPlaceholder": "جستجو بر اساس نام ترکیب، مدل‌ها یا توضیحات", + "modelCountSingle": "مدل", + "modelCountPlural": "مدل‌ها", + "comboCountSingle": "ترکیب", + "comboCountPlural": "ترکیب‌ها", + "provider": "ارائه‌دهنده", + "allProviders": "همه ارائه‌دهندگان", + "type": "نوع", + "allTypes": "همه انواع", + "subtype": "زیرنوع", + "allSubtypes": "همه زیرنوع‌ها", + "capability": "قابلیت", + "allCapabilities": "همه قابلیت‌ها", + "pricing": "قیمت‌گذاری", + "allPricing": "همه قیمت‌ها", + "freeOnly": "فقط رایگان", + "nonFree": "استاندارد / غیررایگان", + "providerHealth": "سلامت ارائه‌دهنده", + "allHealthStates": "همه وضعیت‌های سلامت", + "healthy": "سالم", + "degraded": "دچار اختلال", + "down": "از دسترس خارج", + "testResult": "نتیجه تست", + "allResults": "همه نتایج", + "untested": "تست‌نشده", + "statusOk": "سالم", + "statusSlow": "کند", + "statusError": "خطا", + "minContext": "حداقل کانتکست", + "minContextPlaceholder": "مثلاً 32000", + "strategy": "استراتژی", + "allStrategies": "همه استراتژی‌ها", + "status": "وضعیت", + "allStatuses": "همه وضعیت‌ها", + "active": "فعال", + "paused": "متوقف‌شده", + "minMembers": "حداقل اعضا", + "minMembersPlaceholder": "مثلاً 1", + "maxMembers": "حداکثر اعضا", + "maxMembersPlaceholder": "مثلاً 10", + "testSelected": "تست موارد انتخابی ({count})", + "testAllFiltered": "تست همه موارد فیلترشده ({count})", + "cancel": "لغو", + "clearResults": "پاک کردن نتایج", + "testing": "در حال تست...", + "rateLimited": "محدودیت نرخ درخواست", + "quotaExceeded": "اتمام سهمیه", + "timeout": "پایان مهلت زمانی", + "otherError": "خطا", + "justNow": "همین الان", + "minutesAgo": "{count} دقیقه پیش", + "hoursAgo": "{count} ساعت پیش", + "tableRegion": "جدول کاتالوگ مدل‌ها", + "combosTableRegion": "جدول کاتالوگ ترکیب‌ها", + "tableCaption": "کاتالوگ مدل‌ها در تمام ارائه‌دهندگان", + "combosTableCaption": "کاتالوگ ترکیب‌ها با نتایج تست سلامت", + "selectAllModels": "انتخاب همه مدل‌های این صفحه", + "selectAllCombos": "انتخاب همه ترکیب‌های این صفحه", + "selectModel": "انتخاب مدل {name}", + "selectCombo": "انتخاب ترکیب {name}", + "model": "مدل", + "capabilities": "قابلیت‌ها", + "context": "زمینه", + "output": "حداکثر خروجی", + "flags": "پرچم‌ها", + "healthTest": "تست سلامت", + "actions": "عملیات", + "test": "تست", + "custom": "سفارشی", + "free": "رایگان", + "noFlags": "هیچ پرچم قیمت یا منبعی گزارش نشده است", + "noCapabilities": "هیچ متاداده قابلیتی گزارش نشده است", + "showingModels": "نمایش {first}–{last} از {total} مدل", + "showingCombos": "نمایش {first}–{last} از {total} ترکیب", + "refreshing": "در حال به‌روزرسانی…", + "refreshFailed": "به‌روزرسانی ناموفق بود. آخرین کاتالوگ بارگذاری‌شده نمایش داده می‌شود.", + "page": "صفحه {page} از {pageCount}", + "previous": "قبلی", + "next": "بعدی", + "combo": "ترکیب", + "members": "اعضا", + "moreMembers": "+{count} مورد دیگر" + }, "combos": { "title": "ترکیبها", "description": "ایجاد ترکیبهای مدل با مسیریابی وزندار و پشتیبانی از جایگزین", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index 398ed241980f..2dd126b62874 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ota käyttöön mukautuvat virtuaaliset sisäänottokaistat vuokraajaa (tenant) kohti palveluntarjoajien välitystä varten (#9654): yhden vuokraajan kuormapiikki ei enää aiheuta 503-virhettä toiselle. Ympäristömuuttuja OMNIROUTE_CHAT_VIRTUAL_LANES ohittaa tämän hallintapaneelin asetuksen; muutokset tulevat voimaan palvelimen uudelleenkäynnistyksessä.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Palveluntarjoajien koontinäyttösivut: näytä Free-merkki vain niiden signaalien perusteella, joita palveluntarjoaja noudattaa — tämä poistaa näyttönimeen perustuvan heuristiikan, muut kuin totuusarvoiset free-kentät sekä :free-päätteet rekisteröidyiltä palveluntarjoajilta, joilla ei ole dokumentoitua ilmaistasoa. Pois käytöstä aiempi merkkisääntö säilyy.", "featureFlagProxySkipRecentlyFailedDescription": "Välityspalvelinpoolit ja opencoden tilikohtainen kierto estävät juuri epäonnistuneen välityspalvelimen (hylätty TCP-tarkistus tai sen kautta saatu 429-vastaus) tarjoamisen uudelleen prosessikohtaisen ajanjakson ajan. Ajanjakso kaksinkertaistuu jokaisen toistuvan epäonnistumisen myötä enimmäisrajaan asti. Välityspalvelimen tilaa ei kirjata; jos kaikki ehdokkaat on siirretty sivuun, valinta pysyy ennallaan. Oletusarvoisesti käytössä; `false` palauttaa tavallisen valinnan.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Palveluntarjoajille, joiden kiintiö jaotellaan egress-osoitteen perusteella: aseta poolin jäsen, jolla on äskettäin hylätyn jäsenen havaittu egress-osoite, juuri terveiden jäsenten alapuolelle. Vain järjestys, ei koskaan poissuljettu. Vaatii asetuksen PROXY_SKIP_RECENTLY_FAILED, joka tuottaa sen lukeman hylkäyssignaalin. Oletuksena pois päältä: valintajärjestys on täsmälleen tavallinen kierto.", "featureFlagProxyPoolEgressObservationDescription": "Näytä hallintapaneelissa välityspalvelinpoolin kohdalla, kuinka monta havaittua lähtevän liikenteen IP-osoitetta sen jäsenet käyttivät viimeisten 24 tunnin aikana, kuinka monta yhteyttä käytti niitä ja kuinka monta yhteyttä enimmillään havaittiin yhden IP-osoitteen takana. Vain luku -tieto, joka lasketaan välityspalvelinlokista ja jota ei koskaan käytetä reititykseen. Oletusarvoisesti poissa käytöstä: poolieditori säilyy ennallaan ja havaintoreitti palauttaa arvon null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Salli välityspalvelinten kuntotarkistuksessa sellaisen tarkistuksen, jonka kohde hylkäsi (401/403/429: välityspalvelin välitti pyynnön, mutta kohde hylkäsi tämän lähtevän liikenteen IP-osoitteen), nollata välityspalvelimen peräkkäisten epäonnistumisten sarja onnistuneesti palvellun tarkistuksen tavoin. Oletusarvoisesti poissa käytöstä: hylkäys pysyy neutraalina eikä katkaise sarjaa. 5xx-vastaus pysyy kummassakin tapauksessa tuloksettomana, eikä hylkäys koskaan poista välityspalvelinta, poista sitä käytöstä tai aktivoi sitä uudelleen.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Anna automaattisen puhdistuksen poistaa OMNIROUTE_BATCH_RETENTION_DAYS-arvoa vanhemmat päättyneet (valmistuneet/epäonnistuneet/peruutetut/vanhentuneet) Batch API -työt sekä niiden rivikohtaiset tarkistuspisteet ja tyhjentää niiden ladattujen tiedostojen BLOB-sisältö, joiden oma expires_at-ajankohta on ohitettu. Oletusarvoisesti poissa käytöstä: jokainen nykyinen asennus säilyttää nämä tiedot täsmälleen kuten ennenkin, kunnes ylläpitäjä ottaa toiminnon käyttöön. Ylläpitäjän käynnistämään DELETE /api/v1/batches/delete-completed -reittiin tällä ei ole vaikutusta — se on erillinen, ehdoton julkinen API-sopimus.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Päivitys saatavilla: v{current} → v{latest}", "cliproxyapiVersion": "Versio" }, + "modelCatalog": { + "title": "Mallit ja yhdistelmät", + "subtitle": "Selaa ja testaa mallien ja yhdistelmien reititysputkien tilaa kaikilta palveluntarjoajilta.", + "refresh": "Päivitä", + "modelsTab": "Mallit", + "combosTab": "Yhdistelmät", + "catalogSections": "Luettelon osiot", + "loading": "Ladataan...", + "retry": "Yritä uudelleen", + "unableToLoad": "Malliluettelon lataaminen epäonnistui.", + "unableToLoadCombos": "Yhdistelmien lataaminen epäonnistui.", + "checkConnection": "Tarkista yhteys ja yritä uudelleen.", + "noModelsAvailable": "Malleja ei ole vielä saatavilla.", + "noModelsMatch": "Yksikään malli ei vastaa näitä suodattimia.", + "noCombosAvailable": "Yhdistelmiä ei ole vielä saatavilla.", + "noCombosMatch": "Yksikään yhdistelmä ei vastaa näitä suodattimia.", + "clearFilters": "Tyhjennä suodattimet", + "searchModels": "Hae malleja", + "searchModelsPlaceholder": "Hae mallin, palveluntarjoajan tai ominaisuuden mukaan", + "searchCombos": "Hae yhdistelmiä", + "searchCombosPlaceholder": "Hae yhdistelmän nimen, mallien tai kuvauksen mukaan", + "modelCountSingle": "malli", + "modelCountPlural": "mallit", + "comboCountSingle": "yhdistelmä", + "comboCountPlural": "yhdistelmät", + "provider": "Palveluntarjoaja", + "allProviders": "Kaikki palveluntarjoajat", + "type": "Tyyppi", + "allTypes": "Kaikki tyypit", + "subtype": "Alatyyppi", + "allSubtypes": "Kaikki alatyypit", + "capability": "Ominaisuus", + "allCapabilities": "Kaikki ominaisuudet", + "pricing": "Hinnoittelu", + "allPricing": "Kaikki hinnoittelut", + "freeOnly": "Vain ilmaiset", + "nonFree": "Vakio / Maksullinen", + "providerHealth": "Palveluntarjoajan tila", + "allHealthStates": "Kaikki tilat", + "healthy": "Kunnossa", + "degraded": "Heikentynyt", + "down": "Alhaalla", + "testResult": "Testitulos", + "allResults": "Kaikki tulokset", + "untested": "Testaamaton", + "statusOk": "OK", + "statusSlow": "Hidas", + "statusError": "Virhe", + "minContext": "Vähimmäiskonteksti", + "minContextPlaceholder": "esim. 32000", + "strategy": "Strategia", + "allStrategies": "Kaikki strategiat", + "status": "Tila", + "allStatuses": "Kaikki tilat", + "active": "Aktiivinen", + "paused": "Tauotettu", + "minMembers": "Vähimmäisjäsenmäärä", + "minMembersPlaceholder": "esim. 1", + "maxMembers": "Enimmäisjäsenmäärä", + "maxMembersPlaceholder": "esim. 10", + "testSelected": "Testaa valitut ({count})", + "testAllFiltered": "Testaa kaikki suodatetut ({count})", + "cancel": "Peruuta", + "clearResults": "Tyhjennä tulokset", + "testing": "Testataan...", + "rateLimited": "Pyyntörajoitettu", + "quotaExceeded": "Kiintiö ylittynyt", + "timeout": "Aikakatkaistu", + "otherError": "Virhe", + "justNow": "Juuri nyt", + "minutesAgo": "{count} min sitten", + "hoursAgo": "{count} t sitten", + "tableRegion": "Malliluettelotaulukko", + "combosTableRegion": "Yhdistelmäluettelotaulukko", + "tableCaption": "Kaikkien palveluntarjoajien malliluettelo", + "combosTableCaption": "Yhdistelmäluettelo kuntotestien tuloksilla", + "selectAllModels": "Valitse kaikki tämän sivun mallit", + "selectAllCombos": "Valitse kaikki tämän sivun yhdistelmät", + "selectModel": "Valitse malli {name}", + "selectCombo": "Valitse yhdistelmä {name}", + "model": "Malli", + "capabilities": "Kyvyt", + "context": "Konteksti", + "output": "Enimmäistuloste", + "flags": "Liput", + "healthTest": "Kuntotesti", + "actions": "Toiminnot", + "test": "Testaa", + "custom": "Mukautettu", + "free": "Maksuton", + "noFlags": "Hinta- tai lähdelippua ei ole ilmoitettu", + "noCapabilities": "Kykyjen metatietoja ei ole ilmoitettu", + "showingModels": "Näytetään {first}–{last} yhteensä {total} mallista", + "showingCombos": "Näytetään {first}–{last} yhteensä {total} yhdistelmästä", + "refreshing": "Päivitetään…", + "refreshFailed": "Päivitys epäonnistui. Näytetään viimeksi ladattu luettelo.", + "page": "Sivu {page} / {pageCount}", + "previous": "Edellinen", + "next": "Seuraava", + "combo": "Yhdistelmä", + "members": "Jäsenet", + "moreMembers": "+{count} lisää" + }, "combos": { "title": "Yhdistelmät", "description": "Luo mallikomboja painotetulla reitityksellä ja varatuella", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index e20d3bba94c4..570b0a1c777b 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activez des voies d'admission virtuelles adaptatives par tenant pour la répartition des fournisseurs (#9654) : le pic d'un tenant ne renvoie plus 503 à un autre. La variable d'environnement OMNIROUTE_CHAT_VIRTUAL_LANES prime sur ce réglage du tableau de bord ; les modifications prennent effet au redémarrage du serveur.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pages des fournisseurs du tableau de bord : affiche le badge Gratuit uniquement pour les indicateurs reconnus par le fournisseur — abandonne l’heuristique basée sur le nom d’affichage, les champs free non booléens et les suffixes :free pour les fournisseurs enregistrés ne disposant pas d’une offre gratuite documentée. Lorsque cette option est désactivée, la règle historique du badge est conservée.", "featureFlagProxySkipRecentlyFailedDescription": "Les pools de proxys et la rotation par compte d’opencode cessent de réutiliser un proxy qui vient d’échouer (sonde TCP refusée ou réponse 429 reçue par son intermédiaire) pendant une durée propre au processus qui double à chaque nouvel échec, jusqu’à une limite maximale. Aucun état de proxy n’est enregistré ; lorsque tous les candidats sont écartés, le choix reste inchangé. Activé par défaut ; `false` rétablit la sélection simple.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Pour les fournisseurs dont le quota est compartimenté par adresse de sortie, classe un membre du pool partageant l'adresse de sortie observée d'un membre récemment refusé juste en dessous des membres sains. Changement d'ordre uniquement, jamais exclu. Nécessite PROXY_SKIP_RECENTLY_FAILED, qui produit le signal de refus qu'il lit. Désactivé par défaut : l'ordre de sélection correspond exactement à la rotation standard.", "featureFlagProxyPoolEgressObservationDescription": "Afficher, sous un pool de proxys dans le tableau de bord, combien d’adresses IP de sortie observées ont servi ses membres au cours des dernières 24 h, combien de connexions les ont utilisées et le nombre maximal observé derrière une même adresse IP. En lecture seule, calculé à partir du journal du proxy, jamais utilisé pour le routage. Désactivé par défaut : l’éditeur de pool reste inchangé et la route d’observation renvoie null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Lors du contrôle d’intégrité des proxys, permettez à une sonde refusée par la cible (401/403/429 : le proxy a relayé la requête, mais la destination a refusé cette adresse IP de sortie) de réinitialiser la série d’échecs consécutifs du proxy, comme une sonde traitée. Désactivé par défaut : un refus reste neutre et maintient la série. Une réponse 5xx reste non concluante dans les deux cas, et un refus ne supprime, ne désactive ni ne réactive jamais un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Autoriser le nettoyage automatique à supprimer les tâches Batch API dans un état terminal (terminées/échouées/annulées/expirées) datant de plus de OMNIROUTE_BATCH_RETENTION_DAYS, ainsi que leurs points de contrôle par ligne, et à effacer le contenu BLOB des fichiers téléversés dont la valeur expires_at est dépassée. Désactivé par défaut : chaque installation existante conserve ces données exactement comme auparavant jusqu’à ce qu’un opérateur active cette option. La route DELETE /api/v1/batches/delete-completed déclenchée par l’opérateur n’est affectée dans aucun des cas : il s’agit d’un contrat d’API publique distinct et inconditionnel.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Mise à jour disponible : v{current} → v{latest}", "cliproxyapiVersion": "Version" }, + "modelCatalog": { + "title": "Modèles & Combos", + "subtitle": "Parcourez et testez l'état des modèles et des pipelines de routage de combos auprès de chaque fournisseur.", + "refresh": "Actualiser", + "modelsTab": "Modèles", + "combosTab": "Combos", + "catalogSections": "Sections du catalogue", + "loading": "Chargement...", + "retry": "Réessayer", + "unableToLoad": "Impossible de charger le catalogue de modèles.", + "unableToLoadCombos": "Impossible de charger les combos.", + "checkConnection": "Vérifiez la connexion et réessayez.", + "noModelsAvailable": "Aucun modèle n'est disponible pour le moment.", + "noModelsMatch": "Aucun modèle ne correspond à ces filtres.", + "noCombosAvailable": "Aucun combo n'est disponible pour le moment.", + "noCombosMatch": "Aucun combo ne correspond à ces filtres.", + "clearFilters": "Effacer les filtres", + "searchModels": "Rechercher des modèles", + "searchModelsPlaceholder": "Rechercher par modèle, fournisseur ou capacité", + "searchCombos": "Rechercher des combos", + "searchCombosPlaceholder": "Rechercher par nom de combo, modèles ou description", + "modelCountSingle": "modèle", + "modelCountPlural": "modèles", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Fournisseur", + "allProviders": "Tous les fournisseurs", + "type": "Type", + "allTypes": "Tous les types", + "subtype": "Sous-type", + "allSubtypes": "Tous les sous-types", + "capability": "Capacité", + "allCapabilities": "Toutes les capacités", + "pricing": "Tarification", + "allPricing": "Tous les tarifs", + "freeOnly": "Gratuit uniquement", + "nonFree": "Standard / Payant", + "providerHealth": "État du fournisseur", + "allHealthStates": "Tous les états de santé", + "healthy": "Opérationnel", + "degraded": "Dégradé", + "down": "Hors service", + "testResult": "Résultat du test", + "allResults": "Tous les résultats", + "untested": "Non testé", + "statusOk": "OK", + "statusSlow": "Lent", + "statusError": "Erreur", + "minContext": "Contexte min.", + "minContextPlaceholder": "ex. 32000", + "strategy": "Stratégie", + "allStrategies": "Toutes les stratégies", + "status": "Statut", + "allStatuses": "Tous les statuts", + "active": "Actif", + "paused": "En pause", + "minMembers": "Membres min.", + "minMembersPlaceholder": "ex. 1", + "maxMembers": "Membres max.", + "maxMembersPlaceholder": "ex. 10", + "testSelected": "Tester la sélection ({count})", + "testAllFiltered": "Tester tous les éléments filtrés ({count})", + "cancel": "Annuler", + "clearResults": "Effacer les résultats", + "testing": "Test en cours...", + "rateLimited": "Limite de débit atteinte", + "quotaExceeded": "Quota dépassé", + "timeout": "Délai d'attente dépassé", + "otherError": "Erreur", + "justNow": "À l'instant", + "minutesAgo": "Il y a {count} min", + "hoursAgo": "Il y a {count} h", + "tableRegion": "Tableau du catalogue de modèles", + "combosTableRegion": "Tableau du catalogue de combos", + "tableCaption": "Catalogue de modèles pour tous les fournisseurs", + "combosTableCaption": "Catalogue de combos avec résultats des tests de santé", + "selectAllModels": "Sélectionner tous les modèles sur cette page", + "selectAllCombos": "Sélectionner tous les combos sur cette page", + "selectModel": "Sélectionner le modèle {name}", + "selectCombo": "Sélectionner le combo {name}", + "model": "Modèle", + "capabilities": "Capacités", + "context": "Contexte", + "output": "Sortie max", + "flags": "Indicateurs", + "healthTest": "Test d'état", + "actions": "Actions", + "test": "Tester", + "custom": "Personnalisé", + "free": "Gratuit", + "noFlags": "Aucun indicateur de prix ou de source signalé", + "noCapabilities": "Aucune métadonnée de capacité signalée", + "showingModels": "Affichage de {first}–{last} sur {total} modèles", + "showingCombos": "Affichage de {first}–{last} sur {total} combos", + "refreshing": "Actualisation…", + "refreshFailed": "Échec de l'actualisation. Affichage du dernier catalogue chargé.", + "page": "Page {page} sur {pageCount}", + "previous": "Précédent", + "next": "Suivant", + "combo": "Combo", + "members": "Membres", + "moreMembers": "+{count} autres" + }, "combos": { "title": "Combinaisons", "description": "Créez des combinaisons de modèles avec un routage pondéré et une prise en charge de secours", diff --git a/src/i18n/messages/ga.json b/src/i18n/messages/ga.json index f0fce35a437d..c52d808d8e78 100644 --- a/src/i18n/messages/ga.json +++ b/src/i18n/messages/ga.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Cumasaigh lánaí iontrála oiriúnaitheacha fíorúla in aghaidh an tionónta le haghaidh seolta soláthraí (#9654): ní chruthaíonn pléascadh tionónta amháin 503 do thionónta eile a thuilleadh. Tá an athróg timpeallachta OMNIROUTE_CHAT_VIRTUAL_LANES níos cumhachtaí ná an sárú deais seo; tagann athruithe i bhfeidhm ag atosú freastalaí.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leathanaigh soláthraithe na deaise: ná taispeáin an suaitheantas Saor in aisce ach amháin i gcás comharthaí a n-aithníonn an soláthraí iad — fágtar ar lár heorastach an ainm taispeána, réimsí free nach réimsí Boole iad agus iarmhíreanna :free ar sholáthraithe cláraithe nach bhfuil sraith shaor in aisce dhoiciméadaithe acu. Nuair atá sé múchta, coinnítear riail stairiúil an tsuaitheantais.", "featureFlagProxySkipRecentlyFailedDescription": "Cuireann linnte seachfhreastalaí agus rothlú opencode in aghaidh an chuntais cosc ar sheachfhreastalaí ar theip air díreach (diúltaíodh don tóireadóir TCP, nó fuarthas 429 tríd) a sheirbheáil arís ar feadh tréimhse in aghaidh an phróisis a dhúblaíonn le gach teip eile, suas le huasteorainn. Ní scríobhtar aon stádas seachfhreastalaí; má chuirtear gach iarrthóir ar leataobh, fanann an rogha gan athrú. Ar siúl de réir réamhshocraithe; athbhunaíonn `false` an gnáthroghnú.", - "featureFlagProxyPoolSharedEgressOrderDescription": "I gcás soláthraithe a bhfuil a gcóta grúpáilte de réir seoladh eislise, déan comhalta linne a roinneann seoladh eislise breathnaithe comhalta a diúltaíodh le déanaí a rangú díreach faoi bhun comhaltaí sláintiúla. Ord amháin, gan a bheith eisiata riamh. Teastaíonn PROXY_SKIP_RECENTLY_FAILED uaidh, a ghineann an comhartha diúltaithe a léann sé. Múchta de réir réamhshocraithe: is é an gnáthrothlú go díreach an t-ord roghnaithe.", "featureFlagProxyPoolEgressObservationDescription": "Taispeáin, faoi linn seachfhreastalaí sa deais, cé mhéad seoladh IP amach a breathnaíodh a d’fhreastail ar a bhaill le 24 h anuas, cé mhéad nasc a d’úsáid iad agus an líon is mó a chonacthas taobh thiar d’aon IP amháin. Inléite amháin, ríofa ón loga seachfhreastalaí, agus ní úsáidtear riamh é le haghaidh ródúcháin. As de réir réamhshocraithe: fanann eagarthóir na linne gan athrú agus freagraíonn bealach na breathnóireachta le null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "I scuabadh sláinte an tseachfhreastalaí, lig do thóraíocht ar dhiúltaigh an sprioc di (401/403/429: rinne an seachfhreastalaí athsheoladh, ach dhiúltaigh an ceann scríbe don seoladh IP amach seo) stríoc teipeanna comhleanúnacha an tseachfhreastalaí a athshocrú, amhail tóraíocht a seirbheáladh. As de réir réamhshocraithe: fanann diúltú neodrach agus coinníonn sé an stríoc. Fanann 5xx neamhchinntitheach sa dá chás, agus ní bhaineann diúltú seachfhreastalaí choíche, ní dhíchumasaíonn sé é ná ní athghníomhachtaíonn sé é.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Lig don ghlanadh uathoibríoch jabanna teirminéil (críochnaithe/teipthe/curtha ar ceal/éagtha) Batch API atá níos sine ná OMNIROUTE_BATCH_RETENTION_DAYS a scriosadh, mar aon lena seicphointí in aghaidh na líne, agus inneachar BLOB na gcomhad uaslódáilte atá thar a expires_at féin a ghlanadh. Díchumasaithe de réir réamhshocraithe: coimeádann gach suiteáil atá ann cheana na sonraí seo díreach mar a rinneadh roimhe seo go dtí go roghnaíonn oibreoir é seo a chumasú. Ní dhéantar aon difear don bhealach DELETE /api/v1/batches/delete-completed a spreagann oibreoir i gceachtar cás — is conradh API poiblí ar leith agus neamhchoinníollach é.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Nuashonrú ar fáil: v{current} → v{latest}", "cliproxyapiVersion": "Leagan" }, + "modelCatalog": { + "title": "Samhlacha & Teaglamaí", + "subtitle": "Brabhsáil agus tástáil sláinte a dhéanamh ar shamhlacha agus ar phíblínte ródaithe teaglaim thar gach soláthraí.", + "refresh": "Athnuaigh", + "modelsTab": "Samhlacha", + "combosTab": "Teaglamaí", + "catalogSections": "Rannóga Catalóige", + "loading": "Á lódáil...", + "retry": "Bain triail eile as", + "unableToLoad": "Níorbh fhéidir catalóg na samhlacha a lódáil.", + "unableToLoadCombos": "Níorbh fhéidir teaglamaí a lódáil.", + "checkConnection": "Seiceáil an nasc agus bain triail eile as.", + "noModelsAvailable": "Níl aon shamhlacha ar fáil go fóill.", + "noModelsMatch": "Ní mheaitseálann aon shamhlacha na scagairí seo.", + "noCombosAvailable": "Níl aon teaglamaí ar fáil go fóill.", + "noCombosMatch": "Ní mheaitseálann aon teaglamaí na scagairí seo.", + "clearFilters": "Glan na scagairí", + "searchModels": "Cuardaigh samhlacha", + "searchModelsPlaceholder": "Cuardaigh de réir samhla, soláthraí, nó cumais", + "searchCombos": "Cuardaigh teaglamaí", + "searchCombosPlaceholder": "Cuardaigh de réir ainm teaglaime, samhlacha, nó tuairisce", + "modelCountSingle": "samhail", + "modelCountPlural": "samhlacha", + "comboCountSingle": "teaglaim", + "comboCountPlural": "teaglamaí", + "provider": "Soláthraí", + "allProviders": "Gach soláthraí", + "type": "Cineál", + "allTypes": "Gach cineál", + "subtype": "Fochineál", + "allSubtypes": "Gach fochineál", + "capability": "Cumas", + "allCapabilities": "Gach cumas", + "pricing": "Praghsáil", + "allPricing": "Gach praghsáil", + "freeOnly": "Saor in aisce amháin", + "nonFree": "Caighdeánach / Neamh-saor", + "providerHealth": "Sláinte an tsoláthraí", + "allHealthStates": "Gach staid sláinte", + "healthy": "Sláintiúil", + "degraded": "Díghrádaithe", + "down": "Síos", + "testResult": "Toradh tástála", + "allResults": "Gach toradh", + "untested": "Gan tástáil", + "statusOk": "Ceart go leor", + "statusSlow": "Mall", + "statusError": "Earráid", + "minContext": "Comhthéacs íosta", + "minContextPlaceholder": "m.sh. 32000", + "strategy": "Straitéis", + "allStrategies": "Gach straitéis", + "status": "Stádas", + "allStatuses": "Gach stádas", + "active": "Gníomhach", + "paused": "Ar sos", + "minMembers": "Íosmhéid ball", + "minMembersPlaceholder": "m.sh. 1", + "maxMembers": "Uasmhéid ball", + "maxMembersPlaceholder": "m.sh. 10", + "testSelected": "Tástáil na cinn roghnaithe ({count})", + "testAllFiltered": "Tástáil gach ceann scagtha ({count})", + "cancel": "Cealaigh", + "clearResults": "Glan torthaí", + "testing": "Ag tástáil...", + "rateLimited": "Teorainn ráta sroichte", + "quotaExceeded": "Cuóta sáraithe", + "timeout": "Thar am", + "otherError": "Earráid", + "justNow": "Díreach anois", + "minutesAgo": "{count}m ó shin", + "hoursAgo": "{count}h ó shin", + "tableRegion": "Tábla catalóige samhlacha", + "combosTableRegion": "Tábla catalóige teaglamaí", + "tableCaption": "Catalóg samhlacha ar fud gach soláthraí", + "combosTableCaption": "Catalóg teaglamaí le torthaí tástála sláinte", + "selectAllModels": "Roghnaigh gach samhail ar an leathanach seo", + "selectAllCombos": "Roghnaigh gach teaglaim ar an leathanach seo", + "selectModel": "Roghnaigh samhail {name}", + "selectCombo": "Roghnaigh teaglaim {name}", + "model": "Samhail", + "capabilities": "Cumais", + "context": "Comhthéacs", + "output": "Uasmhéid aschuir", + "flags": "Bratacha", + "healthTest": "Tástáil Sláinte", + "actions": "Gníomhartha", + "test": "Tástáil", + "custom": "Saincheaptha", + "free": "Saor in aisce", + "noFlags": "Níor tuairiscíodh aon bhratach praghais nó foinse", + "noCapabilities": "Níor tuairiscíodh aon mheiteashonraí cumais", + "showingModels": "Ag taispeáint {first}–{last} as {total} múnla", + "showingCombos": "Ag taispeáint {first}–{last} as {total} teaglaim", + "refreshing": "Á athnuachan…", + "refreshFailed": "Theip ar an athnuachan. Ag taispeáint na catalóige deireanaí a lódáladh.", + "page": "Leathanach {page} de {pageCount}", + "previous": "Roimhe seo", + "next": "Ar aghaidh", + "combo": "Teaglaim", + "members": "Baill", + "moreMembers": "+{count} eile" + }, "combos": { "title": "Teaglamaí", "description": "Cruthaigh teaglamaí samhlacha le ródú ualaithe agus tacaíocht cúltaca", diff --git a/src/i18n/messages/gu.json b/src/i18n/messages/gu.json index 486cf8ca0427..8431589cb078 100644 --- a/src/i18n/messages/gu.json +++ b/src/i18n/messages/gu.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "પ્રોવાઇડર ડિસ્પેચ માટે પ્રતિ-ટેનન્ટ અનુકૂલનશીલ વર્ચ્યુઅલ એડમિશન લેન સક્ષમ કરો (#9654): એક ટેનન્ટનો બર્સ્ટ હવે બીજા ટેનન્ટને 503 આપતો નથી. OMNIROUTE_CHAT_VIRTUAL_LANES એન્વાયર્નમેન્ટ વેરિયેબલ આ ડેશબોર્ડ સેટિંગ કરતાં વધુ પ્રાધાન્ય ધરાવે છે; ફેરફારો સર્વર પુનઃપ્રારંભ પર અસરકારક થાય છે.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ડૅશબોર્ડના પ્રદાતા પૃષ્ઠો: ફક્ત પ્રદાતા માન્ય રાખે તેવા સંકેતો પર જ મફત બૅજ બતાવો — દસ્તાવેજીકૃત મફત સ્તર વિનાના નોંધાયેલા પ્રદાતાઓ માટે ડિસ્પ્લે-નામનું હ્યુરિસ્ટિક, બિન-બૂલિયન મફત ફીલ્ડ્સ અને :free પ્રત્યયો દૂર કરે છે. બંધ રાખવાથી ઐતિહાસિક બૅજ નિયમ જળવાઈ રહે છે.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pools અને opencodeનું પ્રતિ-એકાઉન્ટ રોટેશન, હમણાં જ નિષ્ફળ ગયેલા પ્રોક્સીને (TCP પ્રોબ નકારાયો હોય અથવા તેના મારફતે 429 મળ્યો હોય) દરેક પુનરાવર્તન સાથે બમણા થતા, મહત્તમ મર્યાદા સુધીના પ્રતિ-પ્રોસેસ સમયગાળા માટે ફરીથી સર્વ કરવાનું બંધ કરે છે. પ્રોક્સીની કોઈ સ્થિતિ લખવામાં આવતી નથી; દરેક ઉમેદવારને બાજુ પર રાખવામાં આવે તો પસંદગી યથાવત્ રહે છે. ડિફૉલ્ટ રૂપે ચાલુ; `false` સાદી પસંદગી પાછી લાવે છે.", - "featureFlagProxyPoolSharedEgressOrderDescription": "જે પ્રદાતાઓનો ક્વોટા ઇગ્રેસ એડ્રેસ દ્વારા બકેટ કરેલ છે, તેમના માટે તાજેતરમાં નકારેલા સભ્યના અવલોકિત ઇગ્રેસ એડ્રેસને શેર કરતા પૂલ સભ્યને સ્વસ્થ સભ્યોની બરાબર નીચે ક્રમ આપો. ફક્ત ક્રમ બદલાશે, ક્યારેય બાકાત રાખવામાં આવશે નહીં. PROXY_SKIP_RECENTLY_FAILED જરૂરી છે, જે તે વાંચે છે તે રિફ્યુઝલ સિગ્નલ ઉત્પન્ન કરે છે. ડિફૉલ્ટ રૂપે બંધ: પસંદગીનો ક્રમ સામાન્ય રોટેશન મુજબ જ રહે છે.", "featureFlagProxyPoolEgressObservationDescription": "ડૅશબોર્ડમાં પ્રોક્સી પૂલ હેઠળ બતાવો કે છેલ્લા 24 કલાકમાં કેટલા નિરીક્ષિત એગ્રેસ IPએ તેના સભ્યોને સેવા આપી, કેટલાં કનેક્શનોએ તેમનો ઉપયોગ કર્યો અને એક IP પાછળ સૌથી વધુ કેટલાં કનેક્શન જોવા મળ્યાં. આ માહિતી ફક્ત વાંચવા માટે છે, પ્રોક્સી લૉગમાંથી ગણવામાં આવે છે અને રૂટિંગ માટે ક્યારેય ઉપયોગમાં લેવાતી નથી. ડિફૉલ્ટ રૂપે બંધ: પૂલ એડિટર યથાવત્ રહે છે અને નિરીક્ષણ રૂટ null પરત કરે છે.", "featureFlagProxyHealthBlockedResetsStreakDescription": "પ્રોક્સી હેલ્થ સ્વીપમાં, લક્ષ્ય દ્વારા નકારવામાં આવેલા પ્રોબને (401/403/429: પ્રોક્સીએ રિલે કર્યું, ગંતવ્યે આ એગ્રેસ IPને નકાર્યો) સર્વ કરાયેલા પ્રોબની જેમ પ્રોક્સીની સળંગ નિષ્ફળતાઓની શ્રેણી રીસેટ કરવાની મંજૂરી આપો. ડિફૉલ્ટ રૂપે બંધ: નકાર તટસ્થ રહે છે અને શ્રેણી જાળવી રાખે છે. બંને સ્થિતિમાં 5xx અનિર્ણાયક રહે છે, અને નકાર ક્યારેય પ્રોક્સીને દૂર, અક્ષમ અથવા ફરી સક્રિય કરતો નથી.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "સ્વચાલિત ક્લીનઅપ સ્વીપને OMNIROUTE_BATCH_RETENTION_DAYS કરતાં જૂની, અંતિમ સ્થિતિમાં રહેલી (પૂર્ણ/નિષ્ફળ/રદ કરેલી/સમાપ્ત) Batch API jobs ને તેમના પ્રત્યેક-લાઇન checkpoints સાથે કાઢી નાખવા દો અને તેમની પોતાની expires_at વીતી ગયેલી અપલોડ કરેલી ફાઇલોની BLOB સામગ્રી સાફ કરવા દો. ડિફૉલ્ટ રૂપે બંધ: ઑપરેટર તેને સક્રિય ન કરે ત્યાં સુધી દરેક હાલનું ઇન્સ્ટોલેશન આ ડેટાને પહેલાંની જેમ જ રાખે છે. ઑપરેટર દ્વારા ટ્રિગર થતો DELETE /api/v1/batches/delete-completed રૂટ કોઈપણ સ્થિતિમાં અપ્રભાવિત રહે છે — તે એક અલગ, બિનશરતી જાહેર API કરાર છે.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "અપડેટ ઉપલબ્ધ છે: v{current} → v{latest}", "cliproxyapiVersion": "આવૃત્તિ" }, + "modelCatalog": { + "title": "મોડલ્સ અને કોમ્બોઝ", + "subtitle": "દરેક પ્રદાતામાં મોડલ્સ અને કોમ્બો રૂટિંગ પાઇપલાઇન્સ બ્રાઉઝ કરો અને હેલ્થ-ટેસ્ટ કરો.", + "refresh": "રિફ્રેશ કરો", + "modelsTab": "મોડલ્સ", + "combosTab": "કોમ્બોઝ", + "catalogSections": "કેટેલોગ વિભાગો", + "loading": "લોડ થઈ રહ્યું છે...", + "retry": "ફરી પ્રયાસ કરો", + "unableToLoad": "મોડલ કેટેલોગ લોડ કરવામાં અસમર્થ.", + "unableToLoadCombos": "કોમ્બોઝ લોડ કરવામાં અસમર્થ.", + "checkConnection": "કનેક્શન તપાસો અને ફરી પ્રયાસ કરો.", + "noModelsAvailable": "હજી સુધી કોઈ મોડલ્સ ઉપલબ્ધ નથી.", + "noModelsMatch": "આ ફિલ્ટર્સ સાથે કોઈ મોડલ્સ મેળ ખાતા નથી.", + "noCombosAvailable": "હજી સુધી કોઈ કોમ્બોઝ ઉપલબ્ધ નથી.", + "noCombosMatch": "આ ફિલ્ટર્સ સાથે કોઈ કોમ્બોઝ મેળ ખાતા નથી.", + "clearFilters": "ફિલ્ટર્સ સાફ કરો", + "searchModels": "મોડલ્સ શોધો", + "searchModelsPlaceholder": "મોડલ, પ્રદાતા અથવા ક્ષમતા દ્વારા શોધો", + "searchCombos": "કોમ્બોઝ શોધો", + "searchCombosPlaceholder": "કોમ્બો નામ, મોડલ્સ અથવા વર્ણન દ્વારા શોધો", + "modelCountSingle": "મોડલ", + "modelCountPlural": "મોડલ્સ", + "comboCountSingle": "કોમ્બો", + "comboCountPlural": "કોમ્બોઝ", + "provider": "પ્રદાતા", + "allProviders": "બધા પ્રદાતાઓ", + "type": "પ્રકાર", + "allTypes": "બધા પ્રકારો", + "subtype": "પેટાપ્રકાર", + "allSubtypes": "બધા પેટાપ્રકારો", + "capability": "ક્ષમતા", + "allCapabilities": "બધી ક્ષમતાઓ", + "pricing": "કિંમત", + "allPricing": "બધી કિંમતો", + "freeOnly": "માત્ર મફત", + "nonFree": "સ્ટાન્ડર્ડ / નોન-ફ્રી", + "providerHealth": "પ્રદાતા હેલ્થ", + "allHealthStates": "બધી હેલ્થ સ્થિતિઓ", + "healthy": "હેલ્ધી", + "degraded": "ડિગ્રેડેડ", + "down": "ડાઉન", + "testResult": "પરીક્ષણ પરિણામ", + "allResults": "બધા પરિણામો", + "untested": "ચકાસાયેલ નથી", + "statusOk": "બરાબર", + "statusSlow": "ધીમું", + "statusError": "ભૂલ", + "minContext": "ન્યૂનતમ સંદર્ભ", + "minContextPlaceholder": "દા.ત. 32000", + "strategy": "વ્યૂહરચના", + "allStrategies": "બધી વ્યૂહરચનાઓ", + "status": "સ્થિતિ", + "allStatuses": "બધી સ્થિતિઓ", + "active": "સક્રિય", + "paused": "થોભાવેલ", + "minMembers": "ન્યૂનતમ સભ્યો", + "minMembersPlaceholder": "દા.ત. 1", + "maxMembers": "મહત્તમ સભ્યો", + "maxMembersPlaceholder": "દા.ત. 10", + "testSelected": "પસંદ કરેલ પરીક્ષણ કરો ({count})", + "testAllFiltered": "બધા ફિલ્ટર કરેલા પરીક્ષણ કરો ({count})", + "cancel": "રદ કરો", + "clearResults": "પરિણામો સાફ કરો", + "testing": "પરીક્ષણ થઈ રહ્યું છે...", + "rateLimited": "દર મર્યાદિત", + "quotaExceeded": "ક્વોટા ઓળંગાઈ ગયો", + "timeout": "સમય સમાપ્ત થયો", + "otherError": "ભૂલ", + "justNow": "હમણાં જ", + "minutesAgo": "{count}m પહેલાં", + "hoursAgo": "{count}h પહેલાં", + "tableRegion": "મોડેલ કૅટેલૉગ કોષ્ટક", + "combosTableRegion": "કોમ્બોઝ કૅટેલૉગ કોષ્ટક", + "tableCaption": "બધા પ્રદાતાઓમાં મોડેલ કૅટેલૉગ", + "combosTableCaption": "હેલ્થ ટેસ્ટ પરિણામો સાથે કોમ્બોઝ કૅટેલૉગ", + "selectAllModels": "આ પૃષ્ઠ પરના બધા મોડેલ પસંદ કરો", + "selectAllCombos": "આ પૃષ્ઠ પરના બધા કોમ્બોઝ પસંદ કરો", + "selectModel": "મોડેલ {name} પસંદ કરો", + "selectCombo": "કોમ્બો {name} પસંદ કરો", + "model": "મોડેલ", + "capabilities": "ક્ષમતાઓ", + "context": "સંદર્ભ", + "output": "મહત્તમ આઉટપુટ", + "flags": "ફ્લેગ્સ", + "healthTest": "હેલ્થ ટેસ્ટ", + "actions": "ક્રિયાઓ", + "test": "ટેસ્ટ", + "custom": "કસ્ટમ", + "free": "મફત", + "noFlags": "કોઈ કિંમત અથવા સ્રોત ફ્લેગ નોંધાયેલ નથી", + "noCapabilities": "કોઈ ક્ષમતા મેટાડેટા નોંધાયેલ નથી", + "showingModels": "{total} માંથી {first}–{last} મૉડલ્સ દર્શાવી રહ્યું છે", + "showingCombos": "{total} માંથી {first}–{last} કૉમ્બો દર્શાવી રહ્યું છે", + "refreshing": "રિફ્રેશ થઈ રહ્યું છે…", + "refreshFailed": "રિફ્રેશ નિષ્ફળ થયું. છેલ્લે લોડ થયેલ કેટલોગ દર્શાવી રહ્યું છે.", + "page": "{pageCount} માંથી પૃષ્ઠ {page}", + "previous": "અગાઉનું", + "next": "આગળનું", + "combo": "કૉમ્બો", + "members": "સભ્યો", + "moreMembers": "+{count} વધુ" + }, "combos": { "title": "કોમ્બોઝ", "description": "ભારાંકિત રૂટિંગ અને ફૉલબૅક સપોર્ટ સાથે મોડેલ કોમ્બોઝ બનાવો", diff --git a/src/i18n/messages/ha.json b/src/i18n/messages/ha.json index 85946d49ae4f..5890767ad419 100644 --- a/src/i18n/messages/ha.json +++ b/src/i18n/messages/ha.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Kunna layukan karɓa na kama-da-wane masu daidaitawa ga kowane tenant domin aika buƙatu zuwa provider (#9654): yawaitar buƙatun tenant ɗaya ba za ta sake jawo wa wani kuskuren 503 ba. Env var na OMNIROUTE_CHAT_VIRTUAL_LANES yana da fifiko kan wannan sauyin dashboard; sauye-sauye za su fara aiki bayan sake kunna server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Shafukan masu samarwa na Dashboard: nuna alamar Kyauta kawai bisa alamomin da mai samarwar ya tabbatar — wannan yana watsi da dabarar hasashen sunan nuni, filayen kyauta marasa ƙimar boolean, da kari na :free a kan masu samarwa da aka yi wa rajista waɗanda ba su da matakin kyauta da aka rubuta. Idan an Kashe, ana ci gaba da amfani da tsohuwar ƙa’idar alamar.", "featureFlagProxySkipRecentlyFailedDescription": "Rukunin proxy da juyawar opencode ta kowane asusu suna daina sake amfani da proxy da ya gaza kwanan nan (ya ƙi gwajin TCP, ko aka karɓi 429 ta cikinsa) na wani lokaci na kowane tsari wanda ke ninkuwa a duk lokacin da gazawar ta sake faruwa, har zuwa iyaka. Ba a rubuta matsayin proxy; idan aka ware dukkan waɗanda za a iya zaɓa, zaɓin ba ya canzawa. A kunne yake ta tsohuwa; `false` yana dawo da zaɓi na yau da kullum.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Ga masu ba da sabis waɗanda aka tsara kasonsu ta adireshin egress, sanya memban pool mai raba adireshin egress ɗin da aka lura da shi na memban da aka ƙi kwanan nan a ƙasa kaɗan da membobi masu lafiya. Tsarin jeri kawai, ba a taɓa cirewa ba. Yana buƙatar PROXY_SKIP_RECENTLY_FAILED, wanda ke samar da siginar ƙin yarda da yake karantawa. A kashe yake a matsayin asali: tsarin zaɓi yana bin juyawa ta asali ce kawai.", "featureFlagProxyPoolEgressObservationDescription": "A ƙarƙashin rukunin proxy a dashboard, nuna adadin IPs na fita da aka lura sun yi wa membobinsa hidima a cikin awanni 24 da suka gabata, adadin haɗin da suka yi amfani da su, da mafi yawan adadin da aka gani a bayan IP guda. Na karantawa kawai ne, ana lissafa shi daga kundin proxy, kuma ba a taɓa amfani da shi wajen routing. A kashe yake ta tsohuwa: editan rukuni ba ya canzawa kuma hanyar lura tana amsa null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "A yayin binciken lafiyar proxy, bari gwajin da manufa ta ƙi (401/403/429: proxy ya isar, amma wurin da ake nufi ya ƙi wannan IP na fita) ya sake saita jerin gazawar proxy masu jere, kamar gwajin da aka yi wa hidima. A kashe yake ta tsohuwa: ƙin amincewa yana kasancewa tsaka-tsaki kuma yana riƙe da jerin gazawar. 5xx yana kasancewa mara tabbas a kowane hali, kuma ƙin amincewa ba ya taɓa cirewa, kashewa ko sake kunna proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Bari aikin sharewa ta atomatik ya goge ayyukan Batch API da suka ƙare (an kammala/an gaza/an soke/lokaci ya ƙare) waɗanda suka girmi OMNIROUTE_BATCH_RETENTION_DAYS, tare da wuraren ci-gaban kowane layinsu, sannan ya share abun cikin BLOB na fayilolin da aka ɗora waɗanda lokacinsu na expires_at ya wuce. A kashe yake ta tsohuwa: duk shigarwar da ake da ita za ta ci gaba da riƙe wannan bayanin daidai kamar da har sai mai gudanarwa ya kunna shi. Hanyar DELETE /api/v1/batches/delete-completed da mai gudanarwa ke jawowa ba ta canzawa a kowane hali — wata yarjejeniyar API ta jama'a ce daban wadda ba ta da sharaɗi.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Akwai sabuntawa: v{current} → v{latest}", "cliproxyapiVersion": "Siga" }, + "modelCatalog": { + "title": "Samfura da Haɗe-haɗe", + "subtitle": "Bincika kuma gwada lafiyar samfura da hanyoyin tafiyar da haɗe-haɗe a duk masu samarwa.", + "refresh": "Sabunta", + "modelsTab": "Samfura", + "combosTab": "Haɗe-haɗe", + "catalogSections": "Sassan Kundin Bayanai", + "loading": "Yana lodawa...", + "retry": "Sake gwadawa", + "unableToLoad": "An kasa loda kundin samfura.", + "unableToLoadCombos": "An kasa loda haɗe-haɗe.", + "checkConnection": "Duba haɗin intanet sannan ka sake gwadawa.", + "noModelsAvailable": "Babu samfuran da ake da su a yanzu.", + "noModelsMatch": "Babu samfuran da suka dace da waɗannan matatun.", + "noCombosAvailable": "Babu haɗe-haɗen da ake da su a yanzu.", + "noCombosMatch": "Babu haɗe-haɗen da suka dace da waɗannan matatun.", + "clearFilters": "Share matatun", + "searchModels": "Bincika samfura", + "searchModelsPlaceholder": "Bincika ta samfuri, mai samarwa, ko ƙwarewa", + "searchCombos": "Bincika haɗe-haɗe", + "searchCombosPlaceholder": "Bincika ta sunan haɗe-haɗe, samfura, ko bayani", + "modelCountSingle": "samfuri", + "modelCountPlural": "samfura", + "comboCountSingle": "haɗi", + "comboCountPlural": "haɗe-haɗe", + "provider": "Mai samarwa", + "allProviders": "Duk masu samarwa", + "type": "Nau'i", + "allTypes": "Duk nau'o'i", + "subtype": "Ƙaramin nau'i", + "allSubtypes": "Duk ƙananan nau'o'i", + "capability": "Ƙwarewa", + "allCapabilities": "Duk ƙwarewa", + "pricing": "Farashi", + "allPricing": "Duk farashi", + "freeOnly": "Na kyauta kawai", + "nonFree": "Na yau da kullum / Ba na kyauta ba", + "providerHealth": "Lafiyar mai samarwa", + "allHealthStates": "Duk yanayin lafiya", + "healthy": "Lafiyayye", + "degraded": "Ya samu matsala", + "down": "Ba ya aiki", + "testResult": "Sakamakon gwaji", + "allResults": "Duk sakamako", + "untested": "Ba a gwada ba", + "statusOk": "Lafiya", + "statusSlow": "Jinkiri", + "statusError": "Kuskure", + "minContext": "Mafi ƙarancin mahallin", + "minContextPlaceholder": "misali 32000", + "strategy": "Dabara", + "allStrategies": "Duk dabaru", + "status": "Matsayi", + "allStatuses": "Duk matsayi", + "active": "Mai aiki", + "paused": "An dakatar", + "minMembers": "Mafi ƙarancin mambobi", + "minMembersPlaceholder": "misali 1", + "maxMembers": "Mafi yawan mambobi", + "maxMembersPlaceholder": "misali 10", + "testSelected": "Gwada waɗanda aka zaɓa ({count})", + "testAllFiltered": "Gwada duk waɗanda aka tace ({count})", + "cancel": "Soke", + "clearResults": "Share sakamako", + "testing": "Ana gwadawa...", + "rateLimited": "An iyakance buƙatu", + "quotaExceeded": "An wuce kaso", + "timeout": "Lokaci ya ƙare", + "otherError": "Kuskure", + "justNow": "Yanzu nan", + "minutesAgo": "{count}m da suka wuce", + "hoursAgo": "{count}h da suka wuce", + "tableRegion": "Teburin kundin samfura", + "combosTableRegion": "Teburin kundin combos", + "tableCaption": "Kundin samfura a duk masu samarwa", + "combosTableCaption": "Kundin combos tare da sakamakon gwajin lafiya", + "selectAllModels": "Zaɓi duk samfura a wannan shafi", + "selectAllCombos": "Zaɓi duk combos a wannan shafi", + "selectModel": "Zaɓi samfurin {name}", + "selectCombo": "Zaɓi combo {name}", + "model": "Samfuri", + "capabilities": "Ƙwarewa", + "context": "Mahalli", + "output": "Mafi yawan fitarwa", + "flags": "Alamomi", + "healthTest": "Gwajin Lafiya", + "actions": "Ayyuka", + "test": "Gwaji", + "custom": "Na musamman", + "free": "Kyauta", + "noFlags": "Ba a bayar da rahoton farashi ko alamar tushe ba", + "noCapabilities": "Ba a bayar da rahoton bayanan ƙwarewa ba", + "showingModels": "Ana nuna {first}–{last} daga cikin samfura {total}", + "showingCombos": "Ana nuna {first}–{last} daga cikin haɗe-haɗe {total}", + "refreshing": "Ana sabuntawa…", + "refreshFailed": "Sabuntawa ta gaza. Ana nuna kundin da aka loda na ƙarshe.", + "page": "Shafi na {page} cikin {pageCount}", + "previous": "Na baya", + "next": "Na gaba", + "combo": "Haɗi", + "members": "Membobi", + "moreMembers": "+{count} ƙari" + }, "combos": { "title": "Haɗe-haɗe", "description": "Ƙirƙiri haɗe-haɗen samfura tare da rarrabawa bisa nauyi da goyon bayan madadin", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index 8b47487cccb5..4e56e6cc8b9c 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "הפעל נתיבי קבלה וירטואליים אדפטיביים לכל דייר (tenant) עבור שליחת ספקים (#9654): פרץ עומס של דייר אחד כבר לא מחזיר 503 לדייר אחר. משתנה הסביבה OMNIROUTE_CHAT_VIRTUAL_LANES גובר על הגדרה זו בלוח הבקרה; השינויים נכנסים לתוקף לאחר הפעלת השרת מחדש.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "דפי הספקים בלוח הבקרה: הצגת תג החינם רק על סמך סימנים שהספק מכיר בהם — ללא היוריסטיקת שם התצוגה, שדות חינמיים שאינם בוליאניים וסיומות :free אצל ספקים רשומים שאין להם שכבה חינמית מתועדת. במצב כבוי, כלל התג ההיסטורי נשמר.", "featureFlagProxySkipRecentlyFailedDescription": "מאגרי פרוקסי והתחלופה לפי חשבון של opencode מפסיקים להשתמש מחדש בפרוקסי שזה עתה נכשל (בדיקת TCP נדחתה, או שהתקבלה דרכו תגובת 429) למשך פרק זמן נפרד לכל תהליך, שמוכפל בכל הישנות עד לתקרה. לא נכתב סטטוס לפרוקסי; כאשר כל המועמדים מושהים, הבחירה נשארת ללא שינוי. מופעל כברירת מחדל; `false` מחזיר את הבחירה הרגילה.", - "featureFlagProxyPoolSharedEgressOrderDescription": "עבור ספקים שהמכסה שלהם מחולקת לפי כתובת יציאה (egress), דרג חבר pool שחולק את כתובת היציאה שנצפתה עבור חבר שנדחה לאחרונה ממש מתחת לחברים תקינים. קביעת סדר בלבד, ללא החרגה. דורש את PROXY_SKIP_RECENTLY_FAILED, המפיק את אות הסירוב שהוא קורא. מושבת כברירת מחדל: סדר הבחירה הוא בדיוק הרוטציה הרגילה.", "featureFlagProxyPoolEgressObservationDescription": "הצגת מספר כתובות ה-IP ליציאה שנצפו בקרב חברי מאגר הפרוקסי במהלך 24 השעות האחרונות, מספר החיבורים שהשתמשו בהן ומספר החיבורים המרבי שנצפה מאחורי כתובת IP אחת, מתחת למאגר בלוח הבקרה. לקריאה בלבד, מחושב מיומן הפרוקסי ולעולם אינו משמש לניתוב. מושבת כברירת מחדל: עורך המאגר נשאר ללא שינוי ונתיב התצפית מחזיר null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "בסריקת תקינות הפרוקסי, יש לאפשר לבדיקה שהיעד דחה (401/403/429: הפרוקסי העביר את הבקשה, והיעד דחה את כתובת ה-IP הזו ליציאה) לאפס את רצף הכשלים העוקבים של הפרוקסי, כמו בדיקה שנענתה. מושבת כברירת מחדל: דחייה נשארת ניטרלית ושומרת על הרצף. תגובת 5xx נשארת בלתי מכרעת בכל מקרה, ודחייה לעולם אינה מסירה, משביתה או מפעילה מחדש פרוקסי.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "לאפשר לסריקת הניקוי האוטומטית למחוק משימות Batch API במצב סופי (שהושלמו/נכשלו/בוטלו/פג תוקפן) שגילן עולה על OMNIROUTE_BATCH_RETENTION_DAYS, יחד עם נקודות הביקורת שלהן לכל שורה, ולנקות את תוכן ה-BLOB של קבצים שהועלו לאחר שעבר מועד ה-expires_at שלהם. האפשרות מושבתת כברירת מחדל: כל התקנה קיימת ממשיכה לשמור את הנתונים האלה בדיוק כמו קודם, עד שמפעיל המערכת בוחר להפעיל אותה. הנתיב DELETE /api/v1/batches/delete-completed, שמופעל על ידי מפעיל המערכת, אינו מושפע בכל מקרה — זהו חוזה API ציבורי נפרד ובלתי מותנה.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "עדכון זמין: v{current} → v{latest}", "cliproxyapiVersion": "גרסה" }, + "modelCatalog": { + "title": "מודלים ושילובים", + "subtitle": "עיון ובדיקת תקינות של מודלים וצינורות ניתוב של שילובים בכל הספקים.", + "refresh": "רענן", + "modelsTab": "מודלים", + "combosTab": "שילובים", + "catalogSections": "מדורי הקטלוג", + "loading": "טוען...", + "retry": "נסה שוב", + "unableToLoad": "לא ניתן לטעון את קטלוג המודלים.", + "unableToLoadCombos": "לא ניתן לטעון שילובים.", + "checkConnection": "בדוק את החיבור ונסה שוב.", + "noModelsAvailable": "אין עדיין מודלים זמינים.", + "noModelsMatch": "אין מודלים התואמים למסננים אלה.", + "noCombosAvailable": "אין עדיין שילובים זמינים.", + "noCombosMatch": "אין שילובים התואמים למסננים אלה.", + "clearFilters": "נקה מסננים", + "searchModels": "חיפוש מודלים", + "searchModelsPlaceholder": "חיפוש לפי מודל, ספק או יכולת", + "searchCombos": "חיפוש שילובים", + "searchCombosPlaceholder": "חיפוש לפי שם שילוב, מודלים או תיאור", + "modelCountSingle": "מודל", + "modelCountPlural": "מודלים", + "comboCountSingle": "שילוב", + "comboCountPlural": "שילובים", + "provider": "ספק", + "allProviders": "כל הספקים", + "type": "סוג", + "allTypes": "כל הסוגים", + "subtype": "סוג משנה", + "allSubtypes": "כל סוגי המשנה", + "capability": "יכולת", + "allCapabilities": "כל היכולות", + "pricing": "תמחור", + "allPricing": "כל התמחורים", + "freeOnly": "חינם בלבד", + "nonFree": "סטנדרטי / בתשלום", + "providerHealth": "תקינות ספק", + "allHealthStates": "כל מצבי התקינות", + "healthy": "תקין", + "degraded": "ירוד", + "down": "מושבת", + "testResult": "תוצאת בדיקה", + "allResults": "כל התוצאות", + "untested": "לא נבדק", + "statusOk": "תקין", + "statusSlow": "איטי", + "statusError": "שגיאה", + "minContext": "קונטקסט מינימלי", + "minContextPlaceholder": "למשל 32000", + "strategy": "אסטרטגיה", + "allStrategies": "כל האסטרטגיות", + "status": "סטטוס", + "allStatuses": "כל הסטטוסים", + "active": "פעיל", + "paused": "מושהה", + "minMembers": "מינימום חברים", + "minMembersPlaceholder": "למשל 1", + "maxMembers": "מקסימום חברים", + "maxMembersPlaceholder": "למשל 10", + "testSelected": "בדיקת הנבחרים ({count})", + "testAllFiltered": "בדיקת כל המסוננים ({count})", + "cancel": "ביטול", + "clearResults": "ניקוי תוצאות", + "testing": "בבדיקה...", + "rateLimited": "מגבלת קצב", + "quotaExceeded": "חריגה מהמכסה", + "timeout": "פסק זמן", + "otherError": "שגיאה", + "justNow": "זה עתה", + "minutesAgo": "לפני {count} דק'", + "hoursAgo": "לפני {count} שע'", + "tableRegion": "טבלת קטלוג מודלים", + "combosTableRegion": "טבלת קטלוג שילובים", + "tableCaption": "קטלוג מודלים בכל הספקים", + "combosTableCaption": "קטלוג שילובים עם תוצאות בדיקת תקינות", + "selectAllModels": "בחירת כל המודלים בעמוד זה", + "selectAllCombos": "בחירת כל השילובים בעמוד זה", + "selectModel": "בחירת מודל {name}", + "selectCombo": "בחירת שילוב {name}", + "model": "מודל", + "capabilities": "יכולות", + "context": "הקשר", + "output": "פלט מרבי", + "flags": "דגלים", + "healthTest": "בדיקת תקינות", + "actions": "פעולות", + "test": "בדיקה", + "custom": "מותאם אישית", + "free": "חינם", + "noFlags": "לא דווח מחיר או דגל מקור", + "noCapabilities": "לא דווחו מטא-נתונים של יכולות", + "showingModels": "מציג {first}–{last} מתוך {total} מודלים", + "showingCombos": "מציג {first}–{last} מתוך {total} שילובים", + "refreshing": "מרענן…", + "refreshFailed": "הרענון נכשל. מציג את הקטלוג האחרון שנטען.", + "page": "עמוד {page} מתוך {pageCount}", + "previous": "הקודם", + "next": "הבא", + "combo": "שילוב", + "members": "חברים", + "moreMembers": "+{count} נוספים" + }, "combos": { "title": "שילובים", "description": "צור שילובי דגמים עם ניתוב משוקלל ותמיכה ב-fallback", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index d79c8d5d1705..d08230af4506 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदाता डिस्पैच के लिए प्रति-टेनेंट अनुकूली वर्चुअल एडमिशन लेन सक्षम करें (#9654): एक टेनेंट का बर्स्ट अब दूसरे टेनेंट को 503 नहीं देता। OMNIROUTE_CHAT_VIRTUAL_LANES पर्यावरण चर इस डैशबोर्ड सेटिंग पर प्राथमिकता रखता है; परिवर्तन सर्वर पुनः आरंभ पर प्रभावी होते हैं।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "डैशबोर्ड प्रदाता पेज: Free बैज केवल उन संकेतों के आधार पर दिखाएँ जिन्हें प्रदाता मान्यता देता है — यह डिस्प्ले-नाम अनुमान, गैर-बूलियन free फ़ील्ड और बिना दस्तावेज़ीकृत मुफ़्त टियर वाले पंजीकृत प्रदाताओं पर :free प्रत्ययों को हटा देता है। बंद होने पर ऐतिहासिक बैज नियम लागू रहता है।", "featureFlagProxySkipRecentlyFailedDescription": "Proxy पूल और opencode का प्रति-अकाउंट रोटेशन, हाल ही में विफल हुए Proxy (अस्वीकृत TCP प्रोब या उसके माध्यम से प्राप्त 429) को प्रति-प्रोसेस अवधि तक दोबारा उपयोग नहीं करता है। यह अवधि हर बार विफलता दोहराए जाने पर दोगुनी होती है, एक अधिकतम सीमा तक। Proxy की कोई स्थिति लिखी नहीं जाती; प्रत्येक उम्मीदवार को अलग रखे जाने पर चयन अपरिवर्तित रहता है। डिफ़ॉल्ट रूप से चालू; `false` सामान्य चयन बहाल करता है।", - "featureFlagProxyPoolSharedEgressOrderDescription": "उन प्रदाताओं के लिए जिनका कोटा egress address के अनुसार बकेट किया जाता है, हाल ही में अस्वीकृत सदस्य के देखे गए egress address को साझा करने वाले पूल सदस्य को स्वस्थ सदस्यों के ठीक नीचे रैंक करें। केवल क्रमबद्ध किया जाता है, कभी बाहर नहीं किया जाता। इसके लिए PROXY_SKIP_RECENTLY_FAILED की आवश्यकता होती है, जो अस्वीकृति सिग्नल उत्पन्न करता है जिसे यह पढ़ता है। डिफ़ॉल्ट रूप से बंद: चयन क्रम पूरी तरह से सामान्य रोटेशन ही रहता है।", "featureFlagProxyPoolEgressObservationDescription": "डैशबोर्ड में किसी Proxy पूल के अंतर्गत दिखाएँ कि पिछले 24 घंटों में कितने देखे गए एग्रेस IP ने उसके सदस्यों को सेवा दी, कितने कनेक्शनों ने उनका उपयोग किया और एक IP के पीछे सबसे अधिक कितने कनेक्शन देखे गए। केवल पढ़ने योग्य, Proxy लॉग से परिकलित और रूटिंग के लिए कभी उपयोग नहीं किया जाता। डिफ़ॉल्ट रूप से बंद: पूल एडिटर अपरिवर्तित रहता है और ऑब्ज़र्वेशन रूट null लौटाता है।", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy हेल्थ स्वीप में, लक्ष्य द्वारा अस्वीकृत प्रोब (401/403/429: Proxy ने इसे रिले किया, लेकिन गंतव्य ने इस एग्रेस IP को अस्वीकार किया) को, सेवा दिए गए प्रोब की तरह, Proxy की लगातार-विफलता शृंखला रीसेट करने दें। डिफ़ॉल्ट रूप से बंद: अस्वीकृति तटस्थ रहती है और शृंखला को बनाए रखती है। 5xx दोनों ही स्थितियों में अनिर्णायक रहता है, और कोई अस्वीकृति कभी भी Proxy को हटाती, अक्षम या फिर से सक्रिय नहीं करती।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वचालित क्लीनअप स्वीप को OMNIROUTE_BATCH_RETENTION_DAYS से पुराने टर्मिनल (पूर्ण/विफल/रद्द/समय-सीमा समाप्त) Batch API जॉब्स को उनके प्रति-पंक्ति चेकपॉइंट्स सहित हटाने दें, और जिन अपलोड की गई फ़ाइलों का expires_at बीत चुका है उनकी BLOB सामग्री साफ़ करने दें। डिफ़ॉल्ट रूप से बंद: ऑपरेटर के इसे चालू करने तक प्रत्येक मौजूदा इंस्टॉलेशन इस डेटा को बिल्कुल पहले की तरह बनाए रखता है। ऑपरेटर द्वारा ट्रिगर किया गया DELETE /api/v1/batches/delete-completed रूट किसी भी स्थिति में अप्रभावित रहता है—यह एक अलग, बिना शर्त सार्वजनिक API अनुबंध है।", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "अपडेट उपलब्ध: v{current} → v{latest}", "cliproxyapiVersion": "संस्करण" }, + "modelCatalog": { + "title": "मॉडल और कॉम्बो", + "subtitle": "प्रत्येक प्रदाता में मॉडल और कॉम्बो रूटिंग पाइपलाइन ब्राउज़ करें और उनका स्वास्थ्य परीक्षण करें।", + "refresh": "रीफ़्रेश करें", + "modelsTab": "मॉडल", + "combosTab": "कॉम्बो", + "catalogSections": "कैटलॉग अनुभाग", + "loading": "लोड हो रहा है...", + "retry": "पुनः प्रयास करें", + "unableToLoad": "मॉडल कैटलॉग लोड करने में असमर्थ।", + "unableToLoadCombos": "कॉम्बो लोड करने में असमर्थ।", + "checkConnection": "कनेक्शन की जाँच करें और पुनः प्रयास करें।", + "noModelsAvailable": "अभी कोई मॉडल उपलब्ध नहीं है।", + "noModelsMatch": "इन फ़िल्टर से कोई मॉडल मेल नहीं खाता।", + "noCombosAvailable": "अभी कोई कॉम्बो उपलब्ध नहीं है।", + "noCombosMatch": "इन फ़िल्टर से कोई कॉम्बो मेल नहीं खाता।", + "clearFilters": "फ़िल्टर हटाएं", + "searchModels": "मॉडल खोजें", + "searchModelsPlaceholder": "मॉडल, प्रदाता या क्षमता द्वारा खोजें", + "searchCombos": "कॉम्बो खोजें", + "searchCombosPlaceholder": "कॉम्बो नाम, मॉडल या विवरण द्वारा खोजें", + "modelCountSingle": "मॉडल", + "modelCountPlural": "मॉडल", + "comboCountSingle": "कॉम्बो", + "comboCountPlural": "कॉम्बो", + "provider": "प्रदाता", + "allProviders": "सभी प्रदाता", + "type": "प्रकार", + "allTypes": "सभी प्रकार", + "subtype": "उप-प्रकार", + "allSubtypes": "सभी उप-प्रकार", + "capability": "क्षमता", + "allCapabilities": "सभी क्षमताएं", + "pricing": "मूल्य निर्धारण", + "allPricing": "सभी मूल्य निर्धारण", + "freeOnly": "केवल निःशुल्क", + "nonFree": "मानक / सशुल्क", + "providerHealth": "प्रदाता स्वास्थ्य", + "allHealthStates": "सभी स्वास्थ्य स्थितियां", + "healthy": "स्वस्थ", + "degraded": "निम्नीकृत", + "down": "डाउन", + "testResult": "परीक्षण परिणाम", + "allResults": "सभी परिणाम", + "untested": "अपरीक्षित", + "statusOk": "ठीक", + "statusSlow": "धीमा", + "statusError": "त्रुटि", + "minContext": "न्यूनतम संदर्भ", + "minContextPlaceholder": "उदा. 32000", + "strategy": "रणनीति", + "allStrategies": "सभी रणनीतियाँ", + "status": "स्थिति", + "allStatuses": "सभी स्थितियाँ", + "active": "सक्रिय", + "paused": "रोका गया", + "minMembers": "न्यूनतम सदस्य", + "minMembersPlaceholder": "उदा. 1", + "maxMembers": "अधिकतम सदस्य", + "maxMembersPlaceholder": "उदा. 10", + "testSelected": "चयनित का परीक्षण करें ({count})", + "testAllFiltered": "सभी फ़िल्टर किए गए का परीक्षण करें ({count})", + "cancel": "रद्द करें", + "clearResults": "परिणाम साफ़ करें", + "testing": "परीक्षण जारी है...", + "rateLimited": "दर सीमित", + "quotaExceeded": "कोटा समाप्त", + "timeout": "समय समाप्त", + "otherError": "त्रुटि", + "justNow": "अभी", + "minutesAgo": "{count} मिनट पहले", + "hoursAgo": "{count} घंटे पहले", + "tableRegion": "मॉडल कैटलॉग तालिका", + "combosTableRegion": "कॉम्बो कैटलॉग तालिका", + "tableCaption": "सभी प्रदाताओं का मॉडल कैटलॉग", + "combosTableCaption": "स्वास्थ्य परीक्षण परिणामों के साथ कॉम्बो कैटलॉग", + "selectAllModels": "इस पृष्ठ के सभी मॉडल चुनें", + "selectAllCombos": "इस पृष्ठ के सभी कॉम्बो चुनें", + "selectModel": "मॉडल {name} चुनें", + "selectCombo": "कॉम्बो {name} चुनें", + "model": "मॉडल", + "capabilities": "क्षमताएँ", + "context": "संदर्भ", + "output": "अधिकतम आउटपुट", + "flags": "फ़्लैग", + "healthTest": "हेल्थ टेस्ट", + "actions": "कार्रवाइयाँ", + "test": "टेस्ट", + "custom": "कस्टम", + "free": "निःशुल्क", + "noFlags": "कोई मूल्य या स्रोत फ़्लैग रिपोर्ट नहीं किया गया", + "noCapabilities": "कोई क्षमता मेटाडेटा रिपोर्ट नहीं किया गया", + "showingModels": "{total} मॉडल्स में से {first}–{last} दिखाए जा रहे हैं", + "showingCombos": "{total} कॉम्बो में से {first}–{last} दिखाए जा रहे हैं", + "refreshing": "रिफ्रेश हो रहा है…", + "refreshFailed": "रिफ्रेश विफल रहा। अंतिम लोड किया गया कैटलॉग दिखाया जा रहा है।", + "page": "{pageCount} में से पृष्ठ {page}", + "previous": "पिछला", + "next": "अगला", + "combo": "कॉम्बो", + "members": "सदस्य", + "moreMembers": "+{count} और" + }, "combos": { "title": "संयोजन", "description": "भारित रूटिंग और फ़ॉलबैक समर्थन के साथ मॉडल कॉम्बो बनाएं", diff --git a/src/i18n/messages/hr.json b/src/i18n/messages/hr.json index 6bae47fb458f..e722306039a0 100644 --- a/src/i18n/messages/hr.json +++ b/src/i18n/messages/hr.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogući adaptivne virtualne trake za prihvat po klijentu za slanje zahtjeva pružateljima (#9654): nagli porast zahtjeva jednog klijenta više neće uzrokovati pogrešku 503 drugom klijentu. Varijabla okruženja OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost nad ovom postavkom na nadzornoj ploči; promjene stupaju na snagu pri ponovnom pokretanju poslužitelja.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stranice pružatelja na nadzornoj ploči: prikazuj oznaku Besplatno samo na temelju signala koje pružatelj podržava — zanemaruju se heuristika naziva za prikaz, polja za besplatnu razinu koja nisu Booleove vrijednosti i sufiksi :free registriranih pružatelja bez dokumentirane besplatne razine. Kada je isključeno, zadržava se dosadašnje pravilo za oznaku.", "featureFlagProxySkipRecentlyFailedDescription": "Skupovi proxy poslužitelja i rotacija po računu za opencode privremeno prestaju ponovno posluživati proxy poslužitelj koji je upravo zakazao (odbijena TCP provjera ili odgovor 429 primljen preko njega) tijekom razdoblja po procesu koje se udvostručuje pri svakom ponavljanju, do zadanog maksimuma. Status proxy poslužitelja ne zapisuje se; kada se svi kandidati izuzmu, odabir ostaje nepromijenjen. Prema zadanim postavkama uključeno; `false` vraća običan odabir.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Za pružatelje čija je kvota grupirana prema izlaznoj adresi, rangira člana skupa koji dijeli zabilježenu izlaznu adresu nedavno odbijenog člana odmah ispod zdravih članova. Samo redoslijed, nikada se ne isključuje. Zahtijeva PROXY_SKIP_RECENTLY_FAILED, koji stvara signal odbijanja koji se očitava. Zadano isključeno: redoslijed odabira odgovara običnoj rotaciji.", "featureFlagProxyPoolEgressObservationDescription": "Na nadzornoj ploči, ispod skupa proxy poslužitelja, prikažite koliko je opaženih izlaznih IP adresa opsluživalo njegove članove tijekom posljednja 24 h, koliko ih je veza upotrebljavalo i najveći broj veza zabilježen iza jedne IP adrese. Samo za čitanje, izračunava se iz zapisnika proxy poslužitelja i nikada se ne upotrebljava za usmjeravanje. Prema zadanim postavkama isključeno: uređivač skupa ostaje nepromijenjen, a ruta za opažanja vraća null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Tijekom provjere stanja proxy poslužitelja omogućite da provjera koju je cilj odbio (401/403/429: proxy poslužitelj proslijedio je zahtjev, a odredište je odbilo ovu izlaznu IP adresu) poništi niz uzastopnih neuspjeha proxy poslužitelja, kao i uspješno poslužena provjera. Prema zadanim postavkama isključeno: odbijanje ostaje neutralno i zadržava niz. Odgovor 5xx u oba slučaja ostaje neodređen, a odbijanje nikada ne uklanja, onemogućuje niti ponovno aktivira proxy poslužitelj.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dopusti automatskom čišćenju brisanje završnih (dovršenih/neuspjelih/otkazanih/isteklih) Batch API zadataka starijih od OMNIROUTE_BATCH_RETENTION_DAYS, zajedno s njihovim kontrolnim točkama za svaki redak, te brisanje BLOB sadržaja prenesenih datoteka nakon njihova vlastitog expires_at. Prema zadanim postavkama isključeno: svaka postojeća instalacija zadržava te podatke kao i prije sve dok operater ne uključi ovu mogućnost. Ruta DELETE /api/v1/batches/delete-completed koju pokreće operater nije obuhvaćena ovom postavkom — ona je zaseban, bezuvjetan ugovor javnog API-ja.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Dostupno ažuriranje: v{current} → v{latest}", "cliproxyapiVersion": "Verzija" }, + "modelCatalog": { + "title": "Modeli i kombinacije", + "subtitle": "Pregledajte i testirajte ispravnost modela i cjevovoda usmjeravanja kombinacija kod svih pružatelja usluga.", + "refresh": "Osvježi", + "modelsTab": "Modeli", + "combosTab": "Kombinacije", + "catalogSections": "Odjeljci kataloga", + "loading": "Učitavanje...", + "retry": "Pokušaj ponovno", + "unableToLoad": "Nije moguće učitati katalog modela.", + "unableToLoadCombos": "Nije moguće učitati kombinacije.", + "checkConnection": "Provjerite vezu i pokušajte ponovno.", + "noModelsAvailable": "Još nema dostupnih modela.", + "noModelsMatch": "Nijedan model ne odgovara ovim filtrima.", + "noCombosAvailable": "Još nema dostupnih kombinacija.", + "noCombosMatch": "Nijedna kombinacija ne odgovara ovim filtrima.", + "clearFilters": "Očisti filtre", + "searchModels": "Pretraži modele", + "searchModelsPlaceholder": "Pretraži prema modelu, pružatelju ili mogućnosti", + "searchCombos": "Pretraži kombinacije", + "searchCombosPlaceholder": "Pretraži prema nazivu kombinacije, modelima ili opisu", + "modelCountSingle": "model", + "modelCountPlural": "modeli", + "comboCountSingle": "kombinacija", + "comboCountPlural": "kombinacije", + "provider": "Pružatelj", + "allProviders": "Svi pružatelji", + "type": "Vrsta", + "allTypes": "Sve vrste", + "subtype": "Podvrsta", + "allSubtypes": "Sve podvrste", + "capability": "Mogućnost", + "allCapabilities": "Sve mogućnosti", + "pricing": "Cijene", + "allPricing": "Sve cijene", + "freeOnly": "Samo besplatno", + "nonFree": "Standardno / Nije besplatno", + "providerHealth": "Ispravnost pružatelja", + "allHealthStates": "Sva stanja ispravnosti", + "healthy": "Ispravno", + "degraded": "Degradirano", + "down": "Nedostupno", + "testResult": "Rezultat testiranja", + "allResults": "Svi rezultati", + "untested": "Netestirano", + "statusOk": "U redu", + "statusSlow": "Sporo", + "statusError": "Pogreška", + "minContext": "Minimalni kontekst", + "minContextPlaceholder": "npr. 32000", + "strategy": "Strategija", + "allStrategies": "Sve strategije", + "status": "Status", + "allStatuses": "Svi statusi", + "active": "Aktivno", + "paused": "Pauzirano", + "minMembers": "Minimalno članova", + "minMembersPlaceholder": "npr. 1", + "maxMembers": "Maksimalno članova", + "maxMembersPlaceholder": "npr. 10", + "testSelected": "Testiraj odabrano ({count})", + "testAllFiltered": "Testiraj sve filtrirano ({count})", + "cancel": "Odustani", + "clearResults": "Očisti rezultate", + "testing": "Testiranje...", + "rateLimited": "Ograničenje zahtjeva", + "quotaExceeded": "Kvota prekoračena", + "timeout": "Isteklo vrijeme", + "otherError": "Pogreška", + "justNow": "Upravo sada", + "minutesAgo": "prije {count} min", + "hoursAgo": "prije {count} h", + "tableRegion": "Tablica kataloga modela", + "combosTableRegion": "Tablica kataloga kombinacija", + "tableCaption": "Katalog modela svih pružatelja", + "combosTableCaption": "Katalog kombinacija s rezultatima provjere ispravnosti", + "selectAllModels": "Odaberi sve modele na ovoj stranici", + "selectAllCombos": "Odaberi sve kombinacije na ovoj stranici", + "selectModel": "Odaberi model {name}", + "selectCombo": "Odaberi kombinaciju {name}", + "model": "Model", + "capabilities": "Mogućnosti", + "context": "Kontekst", + "output": "Maksimalni izlaz", + "flags": "Zastavice", + "healthTest": "Test ispravnosti", + "actions": "Radnje", + "test": "Test", + "custom": "Prilagođeno", + "free": "Besplatno", + "noFlags": "Nije prijavljena cijena niti zastavica izvora", + "noCapabilities": "Nisu prijavljeni metapodaci o mogućnostima", + "showingModels": "Prikaz {first}–{last} od {total} modela", + "showingCombos": "Prikaz {first}–{last} od {total} kombinacija", + "refreshing": "Osvježavanje…", + "refreshFailed": "Osvježavanje nije uspjelo. Prikazuje se zadnji učitani katalog.", + "page": "Stranica {page} od {pageCount}", + "previous": "Prethodno", + "next": "Sljedeće", + "combo": "Kombinacija", + "members": "Članovi", + "moreMembers": "+{count} više" + }, "combos": { "title": "Kombinacije", "description": "Stvorite kombinacije modela s ponderiranim usmjeravanjem i podrškom za rezervne opcije", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index 9bdc88dccf27..efa5d7d025d7 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Tegye lehetővé a bérlőnkénti adaptív virtuális beléptetősávokat a szolgáltatók felé történő továbbításhoz (#9654): az egyik bérlő kiugró terhelése már nem okoz 503-as hibát egy másiknál. Az OMNIROUTE_CHAT_VIRTUAL_LANES környezeti változó felülírja ezt a vezérlőpult-beállítást; a változtatások a szerver újraindításakor lépnek életbe.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Irányítópult szolgáltatói oldalai: az Ingyenes jelvény csak a szolgáltató által támogatott jelzések alapján jelenjen meg — figyelmen kívül hagyja a megjelenítési néven alapuló heurisztikát, a nem logikai típusú ingyenességi mezőket és a dokumentált ingyenes szinttel nem rendelkező regisztrált szolgáltatók :free utótagjait. Kikapcsolt állapotban a korábbi jelvényszabály marad érvényben.", "featureFlagProxySkipRecentlyFailedDescription": "A proxykészletek és az opencode fiókonkénti rotációja egy folyamatonként meghatározott időszakig nem választja újra az éppen meghibásodott proxyt (elutasított TCP-próba vagy rajta keresztül kapott 429-es válasz); ez az időszak minden ismétlődéskor megduplázódik egy felső korlátig. A proxy állapota nem kerül rögzítésre; ha minden jelölt félre van téve, a választás változatlan marad. Alapértelmezés szerint bekapcsolva; a `false` visszaállítja az egyszerű kiválasztást.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Olyan szolgáltatók esetén, amelyek kvótája kimenő cím szerint van csoportosítva, a nemrég elutasított tag észlelt kimenő címén osztozó pool-tagokat közvetlenül az egészséges tagok mögé rangsorolja. Csak a sorrendet módosítja, soha nem zárja ki. Szükséges hozzá a PROXY_SKIP_RECENTLY_FAILED, amely előállítja az általa beolvasott elutasítási jelet. Alapértelmezés szerint ki van kapcsolva: a kiválasztási sorrend pontosan megegyezik az egyszerű rotációval.", "featureFlagProxyPoolEgressObservationDescription": "A vezérlőpulton jelenjen meg egy proxykészlet alatt, hogy az elmúlt 24 órában hány megfigyelt kimenő IP-cím szolgálta ki a tagjait, hány kapcsolat használta ezeket, és legfeljebb hány kapcsolat volt megfigyelhető egyetlen IP-cím mögött. Csak olvasható, a proxynaplóból számított adat, amelyet a rendszer soha nem használ útválasztásra. Alapértelmezés szerint kikapcsolva: a készletszerkesztő változatlan, a megfigyelési útvonal pedig null értékkel válaszol.", "featureFlagProxyHealthBlockedResetsStreakDescription": "A proxyk állapotellenőrzése során a cél által elutasított próba (401/403/429: a proxy továbbította a kérést, a cél pedig elutasította ezt a kimenő IP-címet) a kiszolgált próbához hasonlóan nullázza a proxy egymást követő hibáinak számlálóját. Alapértelmezés szerint kikapcsolva: az elutasítás semleges marad, és nem változtatja meg a sorozatot. Az 5xx válasz mindkét esetben eldönthetetlen marad, és egy elutasítás soha nem távolít el, nem tilt le és nem aktivál újra proxyt.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Az automatikus tisztítás törölje az OMNIROUTE_BATCH_RETENTION_DAYS napnál régebbi, végleges állapotú (befejezett/sikertelen/megszakított/lejárt) Batch API-feladatokat a soronkénti ellenőrzőpontjaikkal együtt, valamint törölje a saját expires_at időpontjukon túli feltöltött fájlok BLOB-tartalmát. Alapértelmezés szerint kikapcsolva: minden meglévő telepítés pontosan ugyanúgy őrzi meg ezeket az adatokat, amíg egy üzemeltető be nem kapcsolja ezt a funkciót. Az üzemeltető által indított DELETE /api/v1/batches/delete-completed útvonal egyik esetben sem változik – ez egy különálló, feltétel nélküli nyilvános API-szerződés.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Frissítés elérhető: v{current} → v{latest}", "cliproxyapiVersion": "Verzió" }, + "modelCatalog": { + "title": "Modellek és kombinációk", + "subtitle": "Böngéssze és tesztelje a modellek és kombinációs útválasztási folyamatok állapotát az összes szolgáltatónál.", + "refresh": "Frissítés", + "modelsTab": "Modellek", + "combosTab": "Kombinációk", + "catalogSections": "Katalógusszakaszok", + "loading": "Betöltés...", + "retry": "Újrapróbálkozás", + "unableToLoad": "Nem sikerült betölteni a modellkatalógust.", + "unableToLoadCombos": "Nem sikerült betölteni a kombinációkat.", + "checkConnection": "Ellenőrizze a kapcsolatot, majd próbálja újra.", + "noModelsAvailable": "Még nem érhetők el modellek.", + "noModelsMatch": "Egyik modell sem felel meg ezeknek a szűrőknek.", + "noCombosAvailable": "Még nem érhetők el kombinációk.", + "noCombosMatch": "Egyik kombináció sem felel meg ezeknek a szűrőknek.", + "clearFilters": "Szűrők törlése", + "searchModels": "Modellek keresése", + "searchModelsPlaceholder": "Keresés modell, szolgáltató vagy képesség alapján", + "searchCombos": "Kombinációk keresése", + "searchCombosPlaceholder": "Keresés kombináció neve, modellek vagy leírás alapján", + "modelCountSingle": "modell", + "modelCountPlural": "modellek", + "comboCountSingle": "kombináció", + "comboCountPlural": "kombinációk", + "provider": "Szolgáltató", + "allProviders": "Összes szolgáltató", + "type": "Típus", + "allTypes": "Összes típus", + "subtype": "Altípus", + "allSubtypes": "Összes altípus", + "capability": "Képesség", + "allCapabilities": "Összes képesség", + "pricing": "Árazás", + "allPricing": "Összes árazás", + "freeOnly": "Csak ingyenes", + "nonFree": "Standard / Nem ingyenes", + "providerHealth": "Szolgáltató állapota", + "allHealthStates": "Összes állapot", + "healthy": "Megfelelő", + "degraded": "Csökkent teljesítményű", + "down": "Leállt", + "testResult": "Teszteredmény", + "allResults": "Összes eredmény", + "untested": "Nem tesztelt", + "statusOk": "OK", + "statusSlow": "Lassú", + "statusError": "Hiba", + "minContext": "Min. kontextus", + "minContextPlaceholder": "pl. 32000", + "strategy": "Stratégia", + "allStrategies": "Összes stratégia", + "status": "Állapot", + "allStatuses": "Összes állapot", + "active": "Aktív", + "paused": "Szüneteltetve", + "minMembers": "Min. tagok", + "minMembersPlaceholder": "pl. 1", + "maxMembers": "Max. tagok", + "maxMembersPlaceholder": "pl. 10", + "testSelected": "Kijelöltek tesztelése ({count})", + "testAllFiltered": "Összes szűrt tesztelése ({count})", + "cancel": "Mégse", + "clearResults": "Eredmények törlése", + "testing": "Tesztelés...", + "rateLimited": "Kérésszám korlátozva", + "quotaExceeded": "Kvóta túllépve", + "timeout": "Időtúllépés", + "otherError": "Hiba", + "justNow": "Épp most", + "minutesAgo": "{count} perce", + "hoursAgo": "{count} órája", + "tableRegion": "Modellkatalógus táblázat", + "combosTableRegion": "Kombinációkatalógus táblázat", + "tableCaption": "Modellkatalógus az összes szolgáltatóból", + "combosTableCaption": "Kombinációkatalógus állapotteszt-eredményekkel", + "selectAllModels": "Az összes modell kijelölése ezen az oldalon", + "selectAllCombos": "Az összes kombináció kijelölése ezen az oldalon", + "selectModel": "{name} modell kijelölése", + "selectCombo": "{name} kombináció kijelölése", + "model": "Modell", + "capabilities": "Képességek", + "context": "Kontextus", + "output": "Maximális kimenet", + "flags": "Jelzők", + "healthTest": "Állapotteszt", + "actions": "Műveletek", + "test": "Teszt", + "custom": "Egyéni", + "free": "Ingyenes", + "noFlags": "Nincs jelentett ár- vagy forrásjelző", + "noCapabilities": "Nincs jelentett képesség-metaadat", + "showingModels": "{first}–{last} megjelenítése {total} modellből", + "showingCombos": "{first}–{last} megjelenítése {total} kombinációból", + "refreshing": "Frissítés…", + "refreshFailed": "A frissítés sikertelen. A legutóbb betöltött katalógus látható.", + "page": "{page} / {pageCount} oldal", + "previous": "Előző", + "next": "Következő", + "combo": "Kombináció", + "members": "Tagok", + "moreMembers": "+{count} további" + }, "combos": { "title": "Kombók", "description": "Modellkombinációk létrehozása súlyozott útválasztással és tartalék támogatással", diff --git a/src/i18n/messages/hy.json b/src/i18n/messages/hy.json index 1a90948987de..f1f7466e848d 100644 --- a/src/i18n/messages/hy.json +++ b/src/i18n/messages/hy.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Միացնել ըստ վարձակալի հարմարվողական վիրտուալ ընդունման ուղիները մատակարարին ուղարկելու համար (#9654)․ մեկ վարձակալի հարցումների կտրուկ աճն այլևս չի առաջացնում 503 մեկ այլ վարձակալի համար։ OMNIROUTE_CHAT_VIRTUAL_LANES միջավայրի փոփոխականը գերակայում է կառավարման վահանակի այս վերասահմանմանը․ փոփոխություններն ուժի մեջ են մտնում սերվերը վերագործարկելիս։", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Վահանակի մատակարարների էջերում «Անվճար» նշանը ցուցադրել միայն մատակարարի կողմից հաստատված ազդանշանների դեպքում․ այլևս չօգտագործել ցուցադրվող անվան վրա հիմնված մոտավոր որոշումը, ոչ բուլյան free դաշտերը և փաստաթղթավորված անվճար մակարդակ չունեցող գրանցված մատակարարների :free վերջածանցները։ Անջատված լինելու դեպքում պահպանվում է նշանի ցուցադրման նախկին կանոնը։", "featureFlagProxySkipRecentlyFailedDescription": "Պրոքսի խմբերը և opencode-ի՝ ըստ հաշվի ռոտացիան դադարում են կրկին տրամադրել հենց նոր ձախողված պրոքսին (մերժված TCP ստուգում կամ դրա միջոցով ստացված 429)՝ յուրաքանչյուր գործընթացի համար սահմանված ժամանակահատվածով, որը յուրաքանչյուր կրկնության դեպքում կրկնապատկվում է՝ մինչև առավելագույն սահմանաչափը։ Պրոքսիի որևէ կարգավիճակ չի գրանցվում․ երբ բոլոր թեկնածուները մի կողմ են դրված, ընտրությունը մնում է անփոփոխ։ Լռելյայն միացված է․ `false`-ը վերականգնում է սովորական ընտրությունը։", - "featureFlagProxyPoolSharedEgressOrderDescription": "Այն մատակարարների համար, որոնց քվոտան բաշխվում է ըստ ելքային հասցեի, պուլի այն անդամին, որը կիսում է վերջերս մերժված անդամի նկատված ելքային հասցեն, դասակարգել անմիջապես առողջ անդամներից հետո: Միայն հերթականության փոփոխություն, երբեք չի բացառվում: Պահանջում է PROXY_SKIP_RECENTLY_FAILED, որն արտադրում է իր կողմից ընթերցվող մերժման ազդանշանը: Լռելյայն անջատված է. ընտրության հերթականությունը ճշգրտորեն համընկնում է սովորական ռոտացիայի հետ:", "featureFlagProxyPoolEgressObservationDescription": "Վահանակում՝ պրոքսի խմբի տակ, ցույց տալ, թե վերջին 24 ժ-ի ընթացքում քանի դիտարկված ելքային IP է սպասարկել դրա անդամներին, քանի միացում է օգտագործել դրանք, և մեկ IP-ի հետևում դիտված միացումների առավելագույն քանակը։ Միայն կարդալու համար է, հաշվարկվում է պրոքսիի մատյանից և երբեք չի օգտագործվում երթուղավորման համար։ Լռելյայն անջատված է․ խմբի խմբագրիչը մնում է անփոփոխ, իսկ դիտարկման երթուղին վերադարձնում է null։", "featureFlagProxyHealthBlockedResetsStreakDescription": "Պրոքսիի առողջական վիճակի ստուգման ընթացքում թույլ տալ, որ թիրախի կողմից մերժված ստուգումը (401/403/429․ պրոքսին փոխանցել է հարցումը, իսկ նպատակակետը մերժել է այս ելքային IP-ն) զրոյացնի պրոքսիի հաջորդական ձախողումների շարքը՝ ինչպես սպասարկված ստուգման դեպքում։ Լռելյայն անջատված է․ մերժումը մնում է չեզոք և պահպանում է շարքը։ 5xx-ը երկու դեպքում էլ մնում է անորոշ, իսկ մերժումը երբեք չի հեռացնում, անջատում կամ վերաակտիվացնում պրոքսին։", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Թույլատրել, որ ավտոմատ մաքրման գործընթացը ջնջի OMNIROUTE_BATCH_RETENTION_DAYS-ից ավելի հին վերջնական կարգավիճակով (completed/failed/cancelled/expired) Batch API առաջադրանքները՝ դրանց յուրաքանչյուր տողի ստուգակետերի հետ միասին, և մաքրի այն վերբեռնված ֆայլերի BLOB բովանդակությունը, որոնց expires_at-ն անցել է։ Լռելյայն անջատված է․ բոլոր առկա տեղադրումները շարունակում են պահպանել այս տվյալները ճիշտ այնպես, ինչպես նախկինում, մինչև օպերատորը միացնի այս գործառույթը։ Օպերատորի կողմից գործարկվող DELETE /api/v1/batches/delete-completed երթուղին որևէ դեպքում չի ազդվում․ այն առանձին, անվերապահ հանրային API պայմանագիր է։", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Հասանելի է թարմացում՝ v{current} → v{latest}", "cliproxyapiVersion": "Տարբերակ" }, + "modelCatalog": { + "title": "Մոդելներ և կոմբոներ", + "subtitle": "Դիտեք և ստուգեք մոդելների ու կոմբոների երթուղավորման փայփլայնների առողջությունը բոլոր պրովայդերների միջև:", + "refresh": "Թարմացնել", + "modelsTab": "Մոդելներ", + "combosTab": "Կոմբոներ", + "catalogSections": "Կատալոգի բաժիններ", + "loading": "Բեռնում...", + "retry": "Կրկնել", + "unableToLoad": "Չհաջողվեց բեռնել մոդելների կատալոգը:", + "unableToLoadCombos": "Չհաջողվեց բեռնել կոմբոները:", + "checkConnection": "Ստուգեք կապը և փորձեք կրկին:", + "noModelsAvailable": "Դեռևս հասանելի մոդելներ չկան:", + "noModelsMatch": "Այս ֆիլտրերին համապատասխանող մոդելներ չկան:", + "noCombosAvailable": "Դեռևս հասանելի կոմբոներ չկան:", + "noCombosMatch": "Այս ֆիլտրերին համապատասխանող կոմբոներ չկան:", + "clearFilters": "Մաքրել ֆիլտրերը", + "searchModels": "Որոնել մոդելներ", + "searchModelsPlaceholder": "Որոնել ըստ մոդելի, պրովայդերի կամ հնարավորության", + "searchCombos": "Որոնել կոմբոներ", + "searchCombosPlaceholder": "Որոնել ըստ կոմբոյի անվան, մոդելների կամ նկարագրության", + "modelCountSingle": "մոդել", + "modelCountPlural": "մոդելներ", + "comboCountSingle": "կոմբո", + "comboCountPlural": "կոմբոներ", + "provider": "Պրովայդեր", + "allProviders": "Բոլոր պրովայդերները", + "type": "Տեսակ", + "allTypes": "Բոլոր տեսակները", + "subtype": "Ենթատեսակ", + "allSubtypes": "Բոլոր ենթատեսակները", + "capability": "Հնարավորություն", + "allCapabilities": "Բոլոր հնարավորությունները", + "pricing": "Գնագոյացում", + "allPricing": "Բոլոր գները", + "freeOnly": "Միայն անվճար", + "nonFree": "Ստանդարտ / Վճարովի", + "providerHealth": "Պրովայդերի առողջություն", + "allHealthStates": "Բոլոր վիճակները", + "healthy": "Առողջ", + "degraded": "Վատթարացած", + "down": "Անհասանելի", + "testResult": "Թեստի արդյունք", + "allResults": "Բոլոր արդյունքները", + "untested": "Չստուգված", + "statusOk": "Նորմալ", + "statusSlow": "Դանդաղ", + "statusError": "Սխալ", + "minContext": "Նվազագույն կոնտեքստ", + "minContextPlaceholder": "օր.՝ 32000", + "strategy": "Ռազմավարություն", + "allStrategies": "Բոլոր ռազմավարությունները", + "status": "Կարգավիճակ", + "allStatuses": "Բոլոր կարգավիճակները", + "active": "Ակտիվ", + "paused": "Դադարեցված", + "minMembers": "Նվազագույն անդամներ", + "minMembersPlaceholder": "օր.՝ 1", + "maxMembers": "Առավելագույն անդամներ", + "maxMembersPlaceholder": "օր.՝ 10", + "testSelected": "Թեստավորել ընտրվածները ({count})", + "testAllFiltered": "Թեստավորել բոլոր ֆիլտրվածները ({count})", + "cancel": "Չեղարկել", + "clearResults": "Մաքրել արդյունքները", + "testing": "Թեստավորում...", + "rateLimited": "Հարցումների սահմանափակում", + "quotaExceeded": "Քվոտան գերազանցված է", + "timeout": "Ժամանակը սպառվեց", + "otherError": "Սխալ", + "justNow": "Հենց նոր", + "minutesAgo": "{count} ր առաջ", + "hoursAgo": "{count} ժ առաջ", + "tableRegion": "Մոդելների կատալոգի աղյուսակ", + "combosTableRegion": "Կոմբոների կատալոգի աղյուսակ", + "tableCaption": "Մոդելների կատալոգ բոլոր մատակարարներից", + "combosTableCaption": "Կոմբոների կատալոգ՝ առողջության թեստերի արդյունքներով", + "selectAllModels": "Ընտրել այս էջի բոլոր մոդելները", + "selectAllCombos": "Ընտրել այս էջի բոլոր կոմբոները", + "selectModel": "Ընտրել մոդելը՝ {name}", + "selectCombo": "Ընտրել կոմբոն՝ {name}", + "model": "Մոդել", + "capabilities": "Հնարավորություններ", + "context": "Կոնտեքստ", + "output": "Առավելագույն ելք", + "flags": "Դրոշակներ", + "healthTest": "Աշխատունակության թեստ", + "actions": "Գործողություններ", + "test": "Փորձարկել", + "custom": "Անհատական", + "free": "Անվճար", + "noFlags": "Գնի կամ աղբյուրի դրոշակ չի հաղորդվել", + "noCapabilities": "Հնարավորությունների մետատվյալներ չեն հաղորդվել", + "showingModels": "Ցուցադրվում է {first}–{last}-ը {total} մոդելներից", + "showingCombos": "Ցուցադրվում է {first}–{last}-ը {total} համադրություններից", + "refreshing": "Թարմացվում է…", + "refreshFailed": "Թարմացումը ձախողվեց: Ցուցադրվում է վերջին բեռնված գրացուցակը:", + "page": "Էջ {page}՝ {pageCount}-ից", + "previous": "Նախորդ", + "next": "Հաջորդ", + "combo": "Համադրություն", + "members": "Անդամներ", + "moreMembers": "+{count} ավելին" + }, "combos": { "title": "Կոմբինացիաներ", "description": "Ստեղծեք մոդելների կոմբինացիաներ՝ կշռված երթուղավորմամբ և պահուստային անցման աջակցությամբ", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index 4b3c74a35028..3ed745bf1f60 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktifkan jalur penerimaan virtual adaptif per-tenant untuk pengiriman penyedia (#9654): lonjakan satu tenant tidak lagi mengembalikan 503 ke tenant lain. Variabel lingkungan OMNIROUTE_CHAT_VIRTUAL_LANES menang atas pengaturan dasbor ini; perubahan berlaku setelah server dimulai ulang.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Halaman penyedia di dasbor: tampilkan lencana Gratis hanya berdasarkan sinyal yang dipenuhi oleh penyedia — abaikan heuristik nama tampilan, kolom gratis non-boolean, dan akhiran :free pada penyedia terdaftar tanpa tingkat gratis yang terdokumentasi. Jika dinonaktifkan, aturan lencana lama tetap digunakan.", "featureFlagProxySkipRecentlyFailedDescription": "Pool proxy dan rotasi per akun opencode berhenti menyajikan kembali proxy yang baru saja gagal (probe TCP ditolak atau respons 429 diterima melaluinya) selama periode per proses yang berlipat ganda setiap kali kegagalan berulang, hingga batas maksimum. Status proxy tidak ditulis; jika setiap kandidat disisihkan, pilihannya tetap tidak berubah. Aktif secara default; `false` memulihkan pemilihan biasa.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Untuk penyedia yang kuotanya dikelompokkan berdasarkan alamat egress, posisikan anggota pool yang memiliki alamat egress teramati yang sama dengan anggota yang baru saja ditolak tepat di bawah anggota yang sehat. Hanya urutan, tidak pernah dikecualikan. Memerlukan PROXY_SKIP_RECENTLY_FAILED, yang menghasilkan sinyal penolakan yang dibacanya. Nonaktif secara default: urutan pemilihan persis seperti rotasi biasa.", "featureFlagProxyPoolEgressObservationDescription": "Tampilkan, di bawah pool proxy pada dasbor, jumlah IP keluar yang teramati melayani anggotanya selama 24 jam terakhir, jumlah koneksi yang menggunakannya, dan jumlah koneksi terbanyak yang terlihat di balik satu IP. Hanya-baca, dihitung dari log proxy, dan tidak pernah digunakan untuk perutean. Nonaktif secara default: editor pool tidak berubah dan rute observasi memberikan jawaban null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Dalam pemeriksaan kesehatan proxy, izinkan probe yang ditolak oleh target (401/403/429: proxy meneruskan, tetapi tujuan menolak IP keluar ini) mereset rentetan kegagalan berturut-turut proxy, seperti probe yang berhasil dilayani. Nonaktif secara default: penolakan tetap netral dan mempertahankan rentetan tersebut. Respons 5xx tetap tidak meyakinkan dalam kedua kasus, dan penolakan tidak pernah menghapus, menonaktifkan, atau mengaktifkan kembali proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Izinkan pembersihan otomatis menghapus tugas Batch API berstatus akhir (selesai/gagal/dibatalkan/kedaluwarsa) yang lebih lama dari OMNIROUTE_BATCH_RETENTION_DAYS, beserta titik pemeriksaan per barisnya, serta menghapus konten BLOB dari file yang diunggah setelah melewati expires_at masing-masing. Nonaktif secara default: setiap instalasi yang ada tetap menyimpan data ini persis seperti sebelumnya hingga operator mengaktifkannya. Rute DELETE /api/v1/batches/delete-completed yang dipicu operator tidak terpengaruh dalam kondisi apa pun — rute tersebut merupakan kontrak API publik terpisah yang berlaku tanpa syarat.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Pembaruan tersedia: v{current} → v{latest}", "cliproxyapiVersion": "Versi" }, + "modelCatalog": { + "title": "Model & Kombo", + "subtitle": "Jelajahi dan uji kesehatan model serta pipeline perutean kombo di semua penyedia.", + "refresh": "Segarkan", + "modelsTab": "Model", + "combosTab": "Kombo", + "catalogSections": "Bagian Katalog", + "loading": "Memuat...", + "retry": "Coba lagi", + "unableToLoad": "Gagal memuat katalog model.", + "unableToLoadCombos": "Gagal memuat kombo.", + "checkConnection": "Periksa koneksi dan coba lagi.", + "noModelsAvailable": "Belum ada model yang tersedia.", + "noModelsMatch": "Tidak ada model yang cocok dengan filter ini.", + "noCombosAvailable": "Belum ada kombo yang tersedia.", + "noCombosMatch": "Tidak ada kombo yang cocok dengan filter ini.", + "clearFilters": "Hapus filter", + "searchModels": "Cari model", + "searchModelsPlaceholder": "Cari berdasarkan model, penyedia, atau kemampuan", + "searchCombos": "Cari kombo", + "searchCombosPlaceholder": "Cari berdasarkan nama kombo, model, atau deskripsi", + "modelCountSingle": "model", + "modelCountPlural": "model", + "comboCountSingle": "kombo", + "comboCountPlural": "kombo", + "provider": "Penyedia", + "allProviders": "Semua penyedia", + "type": "Tipe", + "allTypes": "Semua tipe", + "subtype": "Subtipe", + "allSubtypes": "Semua subtipe", + "capability": "Kemampuan", + "allCapabilities": "Semua kemampuan", + "pricing": "Harga", + "allPricing": "Semua harga", + "freeOnly": "Hanya gratis", + "nonFree": "Standar / Berbayar", + "providerHealth": "Kesehatan penyedia", + "allHealthStates": "Semua status kesehatan", + "healthy": "Sehat", + "degraded": "Terdegradasi", + "down": "Mati", + "testResult": "Hasil pengujian", + "allResults": "Semua hasil", + "untested": "Belum diuji", + "statusOk": "OK", + "statusSlow": "Lambat", + "statusError": "Kesalahan", + "minContext": "Konteks minimum", + "minContextPlaceholder": "mis. 32000", + "strategy": "Strategi", + "allStrategies": "Semua strategi", + "status": "Status", + "allStatuses": "Semua status", + "active": "Aktif", + "paused": "Dijeda", + "minMembers": "Anggota minimum", + "minMembersPlaceholder": "mis. 1", + "maxMembers": "Anggota maksimum", + "maxMembersPlaceholder": "mis. 10", + "testSelected": "Uji yang dipilih ({count})", + "testAllFiltered": "Uji semua yang difilter ({count})", + "cancel": "Batal", + "clearResults": "Hapus hasil", + "testing": "Menguji...", + "rateLimited": "Batas laju terlampaui", + "quotaExceeded": "Kuota terlampaui", + "timeout": "Waktu habis", + "otherError": "Kesalahan", + "justNow": "Baru saja", + "minutesAgo": "{count}m yang lalu", + "hoursAgo": "{count}j yang lalu", + "tableRegion": "Tabel katalog model", + "combosTableRegion": "Tabel katalog kombo", + "tableCaption": "Katalog model di semua penyedia", + "combosTableCaption": "Katalog kombo dengan hasil uji kesehatan", + "selectAllModels": "Pilih semua model di halaman ini", + "selectAllCombos": "Pilih semua kombo di halaman ini", + "selectModel": "Pilih model {name}", + "selectCombo": "Pilih kombo {name}", + "model": "Model", + "capabilities": "Kemampuan", + "context": "Konteks", + "output": "Output maks", + "flags": "Penanda", + "healthTest": "Uji Kesehatan", + "actions": "Tindakan", + "test": "Uji", + "custom": "Kustom", + "free": "Gratis", + "noFlags": "Tidak ada penanda harga atau sumber yang dilaporkan", + "noCapabilities": "Tidak ada metadata kemampuan yang dilaporkan", + "showingModels": "Menampilkan {first}–{last} dari {total} model", + "showingCombos": "Menampilkan {first}–{last} dari {total} kombo", + "refreshing": "Menyegarkan…", + "refreshFailed": "Gagal menyegarkan. Menampilkan katalog terakhir yang dimuat.", + "page": "Halaman {page} dari {pageCount}", + "previous": "Sebelumnya", + "next": "Berikutnya", + "combo": "Kombo", + "members": "Anggota", + "moreMembers": "+{count} lagi" + }, "combos": { "title": "kombo", "description": "Buat kombo model dengan perutean berbobot dan dukungan fallback", diff --git a/src/i18n/messages/ig.json b/src/i18n/messages/ig.json index 20705afd9226..e2c29628aff9 100644 --- a/src/i18n/messages/ig.json +++ b/src/i18n/messages/ig.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Gbanye lane nnabata virtual na-agbanwe onwe ya maka tenant ọ bụla maka iziga na provider (#9654): mgbawa arịrịọ nke otu tenant agaghịzi eme ka nke tenant ọzọ nweta 503. Env var OMNIROUTE_CHAT_VIRTUAL_LANES na-akarị mgbanwe dashboard a; mgbanwe ga-amalite ịrụ ọrụ mgbe e bidogharịrị server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Ibe ndị na-enye ọrụ na dashboard: gosi akara Free naanị na signal ndị onye na-enye ọrụ na-akwado — nke a na-ewepụ usoro ntule dabere n’aha ngosi, oghere free ndị na-abụghị boolean, na mgbakwunye :free n’aha ndị na-enye ọrụ e debanyere aha nke na-enweghị ọkwa efu edepụtara. Mgbe agbanyụrụ ya, a ga-edobe iwu akara e ji eme ihe kemgbe.", "featureFlagProxySkipRecentlyFailedDescription": "Ọdọ proxy na ntụgharị opencode nke akaụntụ ọ bụla na-akwụsị iji proxy dara ugbu a ọzọ (nnyocha TCP a jụrụ, ma ọ bụ nzaghachi 429 e nwetara site na ya) ruo oge nke usoro ọ bụla nke na-amụba okpukpu abụọ mgbe ọdịda ahụ megharịrị, ruo n'ókè kachasị. A naghị ede ọkwa proxy ọ bụla; mgbe e wepụrụ ndị niile a ga-ahọrọ n'akụkụ, nhọrọ ahụ anaghị agbanwe. A gbanyere ya na ndabara; `false` na-eweghachi nhọrọ nkịtị.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Maka ndị na-eweta ọrụ ndị e ji adreesị egress kee quota ha, dọba onye otu pool nke na-ekerịta adreesị egress a hụrụ nke onye otu a jụrụ na nso nso a n'okpuru ndị otu dị mma. Naanị usoro, a dịghị ewepụ ya ma ọlị. Chọrọ PROXY_SKIP_RECENTLY_FAILED, nke na-ewepụta akara ọjụjụ ọ na-agụ. Agbanyụrụ na ndabara: usoro nhọrọ bụ kpọmkwem ntụgharị nkịtị.", "featureFlagProxyPoolEgressObservationDescription": "Gosi, n'okpuru ọdọ proxy na dashboard, IP ọpụpụ ole a hụrụ jere ndị otu ya ozi n'ime awa 24 gara aga, njikọ ole jiri ha, na ọnụ ọgụgụ kachasị a hụrụ n'azụ otu IP. Ọ bụ naanị maka ọgụgụ, a na-agbakọ ya site na ndekọ proxy, a naghị eji ya eme routing. A gbanyụrụ ya na ndabara: editọ ọdọ ahụ anaghị agbanwe, route nlele ahụ na-azaghachi null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "N'oge nyocha ahụike proxy, kwe ka nyocha ebumnuche jụrụ (401/403/429: proxy ahụ zigara ya, ebe njedebe ahụ jụrụ IP ọpụpụ a) tọgharịa usoro ọdịda na-aga n'ihu nke proxy ahụ, dịka nyocha e jere ozi. A gbanyụrụ ya na ndabara: ọjụjụ na-anọpụ iche ma na-edobe usoro ahụ. 5xx ka na-enweghị nkwubi okwu n'ọnọdụ ọ bụla, ọjụjụ anaghị ewepụ, gbanyụọ, ma ọ bụ mee ka proxy rụọ ọrụ ọzọ.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Kwe ka nhichapụ akpaka hichapụ ọrụ Batch API ndị nọ n’ọnọdụ njedebe (completed/failed/cancelled/expired) ma gafee OMNIROUTE_BATCH_RETENTION_DAYS, tinyere checkpoints nke ahịrị nke ọ bụla, ma kpochapụ ọdịnaya BLOB nke faịlụ ebugoro nke gafere expires_at nke ha. Agbanyụrụ ya na ndabara: nrụnye niile dị ugbu a ga-edobe data a kpọmkwem dịka ọ dị na mbụ ruo mgbe onye njikwa họrọ ịgbanye ya. Ụzọ DELETE /api/v1/batches/delete-completed nke onye njikwa na-akpalite agaghị emetụta n’ụzọ ọ bụla -- ọ bụ nkwekọrịta API ọha dị iche nke na-arụ ọrụ mgbe niile.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Mmelite dị: v{current} → v{latest}", "cliproxyapiVersion": "Ụdị" }, + "modelCatalog": { + "title": "Ụdị & Combos", + "subtitle": "Chọgharịa ma nwalee ahụike nke ụdị na usoro ntụzịaka combo n'ofe ndị na-eweta niile.", + "refresh": "Megharịa", + "modelsTab": "Ụdị", + "combosTab": "Combos", + "catalogSections": "Ngalaba Katalọgụ", + "loading": "Na-ebudata...", + "retry": "Nwaa ọzọ", + "unableToLoad": "Enweghị ike ibudata katalọgụ ụdị.", + "unableToLoadCombos": "Enweghị ike ibudata combos.", + "checkConnection": "Lelee njikọ ahụ ma nwaa ọzọ.", + "noModelsAvailable": "Ọ dịghị ụdị ọ bụla dị ugbu a.", + "noModelsMatch": "Ọ dịghị ụdị dabara na nzacha ndị a.", + "noCombosAvailable": "Ọ dịghị combos ọ bụla dị ugbu a.", + "noCombosMatch": "Ọ dịghị combos dabara na nzacha ndị a.", + "clearFilters": "Kpochapụ nzacha", + "searchModels": "Chọọ ụdị", + "searchModelsPlaceholder": "Chọọ site na ụdị, onye na-eweta, ma ọ bụ ikike", + "searchCombos": "Chọọ combos", + "searchCombosPlaceholder": "Chọọ site na aha combo, ụdị, ma ọ bụ nkọwa", + "modelCountSingle": "ụdị", + "modelCountPlural": "ụdị", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Onye na-eweta", + "allProviders": "Ndị niile na-eweta", + "type": "Ụdị", + "allTypes": "Ụdị niile", + "subtype": "Obere ụdị", + "allSubtypes": "Obere ụdị niile", + "capability": "Ikike", + "allCapabilities": "Ikike niile", + "pricing": "Ọnụahịa", + "allPricing": "Ọnụahịa niile", + "freeOnly": "N'efu naanị", + "nonFree": "Ọkọlọtọ / Ọ bụghị n'efu", + "providerHealth": "Ahụike onye na-eweta", + "allHealthStates": "Ọnọdụ ahụike niile", + "healthy": "Dị mma", + "degraded": "Ebelatara", + "down": "Adaala", + "testResult": "Nsonaazụ ule", + "allResults": "Nsonaazụ niile", + "untested": "A nwalebeghị", + "statusOk": "Ọ dị mma", + "statusSlow": "Nwayọọ", + "statusError": "Mperi", + "minContext": "Opekempe gburugburu", + "minContextPlaceholder": "dịka 32000", + "strategy": "Atụmatụ", + "allStrategies": "Atụmatụ niile", + "status": "Ọnọdụ", + "allStatuses": "Ọnọdụ niile", + "active": "Na-arụ ọrụ", + "paused": "Kwụsịtụrụ", + "minMembers": "Opekempe ndị otu", + "minMembersPlaceholder": "dịka 1", + "maxMembers": "Kachasị ndị otu", + "maxMembersPlaceholder": "dịka 10", + "testSelected": "Nwalee ndị ahọpụtara ({count})", + "testAllFiltered": "Nwalee ndị niile a nyochara ({count})", + "cancel": "Kagbuo", + "clearResults": "Kpochapụ nsonaazụ", + "testing": "Na-anwale...", + "rateLimited": "E gbochiri oke ọsọ", + "quotaExceeded": "Oke agafeela", + "timeout": "Oge agwụla", + "otherError": "Mperi", + "justNow": "Ugbu a", + "minutesAgo": "{count}m gara aga", + "hoursAgo": "{count}h gara aga", + "tableRegion": "Tebụl katalọgụ model", + "combosTableRegion": "Tebụl katalọgụ combos", + "tableCaption": "Katalọgụ model n'ofe ndị na-enye ọrụ niile", + "combosTableCaption": "Katalọgụ combos nwere nsonaazụ ule ahụike", + "selectAllModels": "Họrọ model niile dị na peeji a", + "selectAllCombos": "Họrọ combos niile dị na peeji a", + "selectModel": "Họrọ model {name}", + "selectCombo": "Họrọ combo {name}", + "model": "Model", + "capabilities": "Ikike", + "context": "Gburugburu okwu", + "output": "Mpụta kachasị elu", + "flags": "Ọkọlọtọ", + "healthTest": "Nnwale Ahụike", + "actions": "Ihe omume", + "test": "Nwalee", + "custom": "Nke ahaziri iche", + "free": "N'efu", + "noFlags": "Enweghị ọnụahịa ma ọ bụ ọkọlọtọ ebe e si nweta a kọrọ", + "noCapabilities": "Enweghị metadata ikike a kọrọ", + "showingModels": "Na-egosi {first}–{last} n'ime ụdị {total}", + "showingCombos": "Na-egosi {first}–{last} n'ime ngwakọta {total}", + "refreshing": "Na-emegharị…", + "refreshFailed": "Imegharị agaghị nke ọma. Na-egosi katalọgụ ikpeazụ e bugoro.", + "page": "Peeji nke {page} n'ime {pageCount}", + "previous": "Nke gara aga", + "next": "Na-esote", + "combo": "Ngwakọta", + "members": "Ndị otu", + "moreMembers": "+{count} ọzọ" + }, "combos": { "title": "Ngwakọta", "description": "Mepụta ngwakọta model nwere ntụgharị ụzọ dabere n'ịdị arọ na nkwado fallback", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 2143c6976c0f..29cc1819c40b 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Attiva corsie di ammissione virtuali adattive per tenant per l'invio ai provider (#9654): il picco di un tenant non restituisce più 503 a un altro. La variabile d'ambiente OMNIROUTE_CHAT_VIRTUAL_LANES ha la precedenza su questa impostazione della dashboard; le modifiche hanno effetto al riavvio del server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pagine dei provider nella dashboard: mostra il badge Gratis solo in base agli indicatori riconosciuti dal provider — elimina l'euristica del nome visualizzato, i campi relativi alla gratuità non booleani e i suffissi :free per i provider registrati senza un piano gratuito documentato. Se disattivato, mantiene la regola storica del badge.", "featureFlagProxySkipRecentlyFailedDescription": "I pool di proxy e la rotazione per account di opencode smettono temporaneamente di riproporre un proxy che ha appena avuto un errore (sonda TCP rifiutata o risposta 429 ricevuta tramite il proxy) per un periodo per processo che raddoppia a ogni ripetizione, fino a un limite massimo. Non viene registrato alcuno stato del proxy; se tutti i candidati vengono messi da parte, la scelta rimane invariata. Attivato per impostazione predefinita; `false` ripristina la selezione normale.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Per i provider la cui quota è suddivisa per indirizzo di egress, posiziona un membro del pool che condivide l'indirizzo di egress rilevato di un membro rifiutato di recente subito sotto i membri integri. Solo ordinamento, mai escluso. Richiede PROXY_SKIP_RECENTLY_FAILED, che genera il segnale di rifiuto da esso letto. Disattivato per impostazione predefinita: l'ordine di selezione segue esattamente la semplice rotazione.", "featureFlagProxyPoolEgressObservationDescription": "Mostra, sotto un pool di proxy nella dashboard, quanti IP di uscita osservati hanno servito i suoi membri nelle ultime 24 ore, quante connessioni li hanno utilizzati e il numero massimo di connessioni osservate dietro un singolo IP. In sola lettura, calcolato dal log dei proxy e mai utilizzato per l'instradamento. Disattivato per impostazione predefinita: l'editor dei pool rimane invariato e la route di osservazione restituisce null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Durante la scansione dello stato dei proxy, consente a una sonda rifiutata dalla destinazione (401/403/429: il proxy ha inoltrato la richiesta, ma la destinazione ha rifiutato questo IP di uscita) di azzerare la serie di errori consecutivi del proxy, come una sonda completata con successo. Disattivato per impostazione predefinita: un rifiuto rimane neutro e mantiene la serie. Una risposta 5xx rimane inconcludente in entrambi i casi e un rifiuto non rimuove, disabilita o riattiva mai un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Consenti alla pulizia automatica di eliminare i processi Batch API terminati (completati/non riusciti/annullati/scaduti) più vecchi di OMNIROUTE_BATCH_RETENTION_DAYS, insieme ai relativi checkpoint per riga, e di cancellare il contenuto BLOB dei file caricati che hanno superato il proprio expires_at. Disattivata per impostazione predefinita: ogni installazione esistente conserva questi dati esattamente come prima finché un operatore non abilita l'opzione. La route DELETE /api/v1/batches/delete-completed attivata dall'operatore non è interessata in alcun caso: è un contratto API pubblico distinto e incondizionato.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Aggiornamento disponibile: v{current} → v{latest}", "cliproxyapiVersion": "Versione" }, + "modelCatalog": { + "title": "Modelli e combo", + "subtitle": "Esplora ed esegui test di integrità su modelli e pipeline di routing combo su ciascun provider.", + "refresh": "Aggiorna", + "modelsTab": "Modelli", + "combosTab": "Combo", + "catalogSections": "Sezioni del catalogo", + "loading": "Caricamento in corso...", + "retry": "Riprova", + "unableToLoad": "Impossibile caricare il catalogo dei modelli.", + "unableToLoadCombos": "Impossibile caricare le combo.", + "checkConnection": "Verifica la connessione e riprova.", + "noModelsAvailable": "Nessun modello ancora disponibile.", + "noModelsMatch": "Nessun modello corrisponde a questi filtri.", + "noCombosAvailable": "Nessuna combo ancora disponibile.", + "noCombosMatch": "Nessuna combo corrisponde a questi filtri.", + "clearFilters": "Cancella filtri", + "searchModels": "Cerca modelli", + "searchModelsPlaceholder": "Cerca per modello, provider o funzionalità", + "searchCombos": "Cerca combo", + "searchCombosPlaceholder": "Cerca per nome combo, modelli o descrizione", + "modelCountSingle": "modello", + "modelCountPlural": "modelli", + "comboCountSingle": "combo", + "comboCountPlural": "combo", + "provider": "Provider", + "allProviders": "Tutti i provider", + "type": "Tipo", + "allTypes": "Tutti i tipi", + "subtype": "Sottotipo", + "allSubtypes": "Tutti i sottotipi", + "capability": "Funzionalità", + "allCapabilities": "Tutte le funzionalità", + "pricing": "Prezzi", + "allPricing": "Tutti i prezzi", + "freeOnly": "Solo gratuiti", + "nonFree": "Standard / A pagamento", + "providerHealth": "Integrità del provider", + "allHealthStates": "Tutti gli stati di integrità", + "healthy": "Operativo", + "degraded": "Degradato", + "down": "Non disponibile", + "testResult": "Risultato del test", + "allResults": "Tutti i risultati", + "untested": "Non testato", + "statusOk": "OK", + "statusSlow": "Lento", + "statusError": "Errore", + "minContext": "Contesto minimo", + "minContextPlaceholder": "es. 32000", + "strategy": "Strategia", + "allStrategies": "Tutte le strategie", + "status": "Stato", + "allStatuses": "Tutti gli stati", + "active": "Attivo", + "paused": "In pausa", + "minMembers": "Membri minimi", + "minMembersPlaceholder": "es. 1", + "maxMembers": "Membri massimi", + "maxMembersPlaceholder": "es. 10", + "testSelected": "Testa selezionati ({count})", + "testAllFiltered": "Testa tutti i filtrati ({count})", + "cancel": "Annulla", + "clearResults": "Cancella risultati", + "testing": "Test in corso...", + "rateLimited": "Rate limit superato", + "quotaExceeded": "Quota superata", + "timeout": "Tempo scaduto", + "otherError": "Errore", + "justNow": "Proprio ora", + "minutesAgo": "{count}m fa", + "hoursAgo": "{count}h fa", + "tableRegion": "Tabella catalogo modelli", + "combosTableRegion": "Tabella catalogo combo", + "tableCaption": "Catalogo modelli di tutti i provider", + "combosTableCaption": "Catalogo combo con i risultati dei test di integrità", + "selectAllModels": "Seleziona tutti i modelli in questa pagina", + "selectAllCombos": "Seleziona tutte le combo in questa pagina", + "selectModel": "Seleziona il modello {name}", + "selectCombo": "Seleziona la combo {name}", + "model": "Modello", + "capabilities": "Capacità", + "context": "Contesto", + "output": "Output massimo", + "flags": "Flag", + "healthTest": "Test di integrità", + "actions": "Azioni", + "test": "Test", + "custom": "Personalizzato", + "free": "Gratuito", + "noFlags": "Nessun prezzo o flag di origine segnalato", + "noCapabilities": "Nessun metadato sulle capacità segnalato", + "showingModels": "Visualizzazione di {first}–{last} di {total} modelli", + "showingCombos": "Visualizzazione di {first}–{last} di {total} combo", + "refreshing": "Aggiornamento in corso…", + "refreshFailed": "Aggiornamento non riuscito. Viene mostrato l'ultimo catalogo caricato.", + "page": "Pagina {page} di {pageCount}", + "previous": "Precedente", + "next": "Successivo", + "combo": "Combo", + "members": "Membri", + "moreMembers": "+{count} altri" + }, "combos": { "title": "Combinazioni", "description": "Crea combinazioni di modelli con routing ponderato e supporto fallback", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 1209466c8034..3ba9d1a13a39 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "プロバイダーへのディスパッチ用に、テナントごとの適応型仮想受付レーンを有効にします(#9654):あるテナントのバーストが他のテナントに503を返さなくなります。OMNIROUTE_CHAT_VIRTUAL_LANES環境変数はこのダッシュボード設定より優先されます。変更はサーバー再起動時に反映されます。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ダッシュボードのプロバイダーページ:プロバイダーが正式に対応していることを示すシグナルに対してのみ「Free」バッジを表示します。表示名による推測、ブール値ではない無料フィールド、および無料枠が文書化されていない登録済みプロバイダーの「:free」サフィックスは使用しません。オフにすると、従来のバッジ判定ルールが適用されます。", "featureFlagProxySkipRecentlyFailedDescription": "プロキシプールと、アカウントごとのopencodeローテーションで、直前に失敗したプロキシ(TCPプローブが拒否された、またはそのプロキシ経由で429を受信したもの)の再使用を、同一プロセス内で一定期間停止します。この期間は失敗を繰り返すたびに倍増し、上限があります。プロキシのステータスは書き込まれません。すべての候補が除外された場合、選択は変更されません。デフォルトではオンです。`false` にすると通常の選択に戻ります。", - "featureFlagProxyPoolSharedEgressOrderDescription": "イグレスアドレス単位でクォータが管理されているプロバイダーにおいて、最近拒否されたメンバーと観測されたイグレスアドレスを共有するプールメンバーの優先度を、正常なメンバーの直下に下げます。順序の変更のみで、除外されることはありません。判定対象となる拒否シグナルを生成する PROXY_SKIP_RECENTLY_FAILED が必要です。デフォルトはオフ(選択順序は通常のローテーション通り)です。", "featureFlagProxyPoolEgressObservationDescription": "ダッシュボードのプロキシプールの下に、過去24時間にそのメンバーに使用されたことが観測された送信元IPの数、それらを使用した接続数、および1つのIPの背後で観測された最多のメンバー数を表示します。読み取り専用で、プロキシログから算出され、ルーティングには使用されません。デフォルトではオフです。プールエディターは変更されず、観測ルートはnullを返します。", "featureFlagProxyHealthBlockedResetsStreakDescription": "プロキシのヘルススイープで、ターゲットに拒否されたプローブ(401/403/429:プロキシは中継したが、宛先がこの送信元IPを拒否したもの)が、正常に処理されたプローブと同様に、プロキシの連続失敗回数をリセットできるようにします。デフォルトではオフです。拒否は中立のままで、連続失敗回数は維持されます。どちらの場合も5xxは判定不能のままであり、拒否によってプロキシが削除、無効化、または再有効化されることはありません。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "自動クリーンアップ処理で、OMNIROUTE_BATCH_RETENTION_DAYS より古い終了済み(完了/失敗/キャンセル/期限切れ)の Batch API ジョブを行ごとのチェックポイントとともに削除し、それぞれの expires_at を過ぎたアップロード済みファイルの BLOB コンテンツを消去します。デフォルトではオフです。オペレーターが明示的に有効化するまで、既存のすべてのインストール環境では従来どおりデータが保持されます。オペレーターが実行する DELETE /api/v1/batches/delete-completed ルートは、設定の有効/無効にかかわらず影響を受けません。これは独立した無条件の公開 API 契約です。", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "更新が利用可能です: v{current} → v{latest}", "cliproxyapiVersion": "バージョン" }, + "modelCatalog": { + "title": "モデルとコンボ", + "subtitle": "すべてのプロバイダーにわたるモデルやコンボルーティングパイプラインの閲覧およびヘルスチェックを行います。", + "refresh": "更新", + "modelsTab": "モデル", + "combosTab": "コンボ", + "catalogSections": "カタログセクション", + "loading": "読み込み中...", + "retry": "再試行", + "unableToLoad": "モデルカタログを読み込めません。", + "unableToLoadCombos": "コンボを読み込めません。", + "checkConnection": "接続を確認して再試行してください。", + "noModelsAvailable": "利用可能なモデルはまだありません。", + "noModelsMatch": "フィルターに一致するモデルはありません。", + "noCombosAvailable": "利用可能なコンボはまだありません。", + "noCombosMatch": "フィルターに一致するコンボはありません。", + "clearFilters": "フィルターをクリア", + "searchModels": "モデルを検索", + "searchModelsPlaceholder": "モデル、プロバイダー、または機能で検索", + "searchCombos": "コンボを検索", + "searchCombosPlaceholder": "コンボ名、モデル、または説明で検索", + "modelCountSingle": "モデル", + "modelCountPlural": "モデル", + "comboCountSingle": "コンボ", + "comboCountPlural": "コンボ", + "provider": "プロバイダー", + "allProviders": "すべてのプロバイダー", + "type": "タイプ", + "allTypes": "すべてのタイプ", + "subtype": "サブタイプ", + "allSubtypes": "すべてのサブタイプ", + "capability": "機能", + "allCapabilities": "すべての機能", + "pricing": "料金", + "allPricing": "すべての料金", + "freeOnly": "無料のみ", + "nonFree": "標準 / 有料", + "providerHealth": "プロバイダーのヘルス状態", + "allHealthStates": "すべてのヘルス状態", + "healthy": "正常", + "degraded": "低下", + "down": "ダウン", + "testResult": "テスト結果", + "allResults": "すべての結果", + "untested": "未テスト", + "statusOk": "OK", + "statusSlow": "遅延", + "statusError": "エラー", + "minContext": "最小コンテキスト", + "minContextPlaceholder": "例: 32000", + "strategy": "ストラテジー", + "allStrategies": "すべてのストラテジー", + "status": "ステータス", + "allStatuses": "すべてのステータス", + "active": "アクティブ", + "paused": "一時停止", + "minMembers": "最小メンバー数", + "minMembersPlaceholder": "例: 1", + "maxMembers": "最大メンバー数", + "maxMembersPlaceholder": "例: 10", + "testSelected": "選択した項目をテスト ({count})", + "testAllFiltered": "絞り込んだ項目をすべてテスト ({count})", + "cancel": "キャンセル", + "clearResults": "結果をクリア", + "testing": "テスト中...", + "rateLimited": "レート制限", + "quotaExceeded": "クォータ超過", + "timeout": "タイムアウト", + "otherError": "エラー", + "justNow": "たった今", + "minutesAgo": "{count}分前", + "hoursAgo": "{count}時間前", + "tableRegion": "モデルカタログテーブル", + "combosTableRegion": "コンボカタログテーブル", + "tableCaption": "全プロバイダーのモデルカタログ", + "combosTableCaption": "ヘルステスト結果付きコンボカタログ", + "selectAllModels": "このページのすべてのモデルを選択", + "selectAllCombos": "このページのすべてのコンボを選択", + "selectModel": "モデル {name} を選択", + "selectCombo": "コンボ {name} を選択", + "model": "モデル", + "capabilities": "機能", + "context": "コンテキスト", + "output": "最大出力", + "flags": "フラグ", + "healthTest": "ヘルステスト", + "actions": "アクション", + "test": "テスト", + "custom": "カスタム", + "free": "無料", + "noFlags": "価格またはソースフラグが報告されていません", + "noCapabilities": "機能メタデータが報告されていません", + "showingModels": "{total} 件中 {first}–{last} 件のモデルを表示中", + "showingCombos": "{total} 件中 {first}–{last} 件のコンボを表示中", + "refreshing": "更新中…", + "refreshFailed": "更新に失敗しました。最後に読み込まれたカタログを表示しています。", + "page": "{page} / {pageCount} ページ", + "previous": "前へ", + "next": "次へ", + "combo": "コンボ", + "members": "メンバー", + "moreMembers": "+{count} 件" + }, "combos": { "title": "コンボ", "description": "重み付けルーティングとフォールバックのサポートを備えたモデルのコンボを作成する", diff --git a/src/i18n/messages/ka.json b/src/i18n/messages/ka.json index e91be8c0a410..7303a0e8d65b 100644 --- a/src/i18n/messages/ka.json +++ b/src/i18n/messages/ka.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ჩართეთ თითოეული ტენანტისთვის ადაპტიური ვირტუალური დაშვების არხები პროვაიდერთან გადაგზავნისთვის (#9654): ერთი ტენანტის მოთხოვნების უეცარი მატება სხვას აღარ დაუბრუნებს 503 შეცდომას. OMNIROUTE_CHAT_VIRTUAL_LANES გარემოს ცვლადს უპირატესობა აქვს მართვის პანელის ამ პარამეტრთან შედარებით; ცვლილებები ძალაში შევა სერვერის გადატვირთვის შემდეგ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "პროვაიდერის გვერდები მართვის პანელში: „უფასო“ ნიშანი გამოჩნდეს მხოლოდ იმ სიგნალების საფუძველზე, რომლებსაც პროვაიდერი ითვალისწინებს — აღარ გამოიყენება საჩვენებელი სახელის ევრისტიკა, არაბულური free ველები და :free სუფიქსები რეგისტრირებული პროვაიდერებისთვის, რომლებსაც დოკუმენტირებული უფასო დონე არ აქვთ. გამორთვის შემთხვევაში შენარჩუნდება ნიშნის ჩვენების ისტორიული წესი.", "featureFlagProxySkipRecentlyFailedDescription": "პროქსი-პულები და opencode-ის თითოეულ ანგარიშზე როტაცია აღარ იყენებს ახლახან ჩავარდნილ პროქსის (უარყოფილი TCP შემოწმება ან მისი მეშვეობით მიღებული 429) თითოეული პროცესისთვის განსაზღვრული პერიოდით, რომელიც ყოველი განმეორებისას ორმაგდება მაქსიმალურ ზღვრამდე. პროქსის სტატუსი არ იწერება; ყველა კანდიდატის გვერდზე გადადების შემთხვევაში არჩევანი უცვლელი რჩება. ნაგულისხმევად ჩართულია; `false` აღადგენს ჩვეულებრივ არჩევას.", - "featureFlagProxyPoolSharedEgressOrderDescription": "პროვაიდერებისთვის, რომელთა ქვოტაც ჯგუფდება egress მისამართის მიხედვით, დაალაგეთ პულის ის წევრი, რომელიც იზიარებს ცოტა ხნის წინ უარყოფილი წევრის დაფიქსირებულ egress მისამართს, უშუალოდ ჯანსაღი წევრების შემდეგ. მხოლოდ რიგითობა, არასდროს გამოირიცხება. საჭიროებს PROXY_SKIP_RECENTLY_FAILED-ს, რომელიც წარმოქმნის მის მიერ წაკითხულ უარყოფის სიგნალს. ნაგულისხმევად გამორთულია: შერჩევის რიგითობა ზუსტად ემთხვევა ჩვეულებრივ როტაციას.", "featureFlagProxyPoolEgressObservationDescription": "დეშბორდზე, პროქსი-პულის ქვეშ, აჩვენეთ ბოლო 24 საათში რამდენი დაფიქსირებული გამავალი IP ემსახურებოდა მის წევრებს, რამდენმა კავშირმა გამოიყენა ისინი და ყველაზე მეტი რამდენი კავშირი დაფიქსირდა ერთი IP-ის უკან. მხოლოდ წაკითხვისთვისაა, გამოითვლება პროქსის ჟურნალიდან და არასოდეს გამოიყენება მარშრუტიზაციისთვის. ნაგულისხმევად გამორთულია: პულის რედაქტორი უცვლელია, ხოლო დაკვირვების მარშრუტი აბრუნებს null-ს.", "featureFlagProxyHealthBlockedResetsStreakDescription": "პროქსის მდგომარეობის შემოწმებისას, სამიზნის მიერ უარყოფილმა მოთხოვნამ (401/403/429: პროქსიმ გადააგზავნა მოთხოვნა, ხოლო დანიშნულების მხარემ უარყო ეს გამავალი IP) გაანულოს პროქსის ზედიზედ წარუმატებლობათა სერია, როგორც წარმატებით შესრულებული შემოწმებისას. ნაგულისხმევად გამორთულია: უარყოფა ნეიტრალური რჩება და სერიას ინარჩუნებს. 5xx ნებისმიერ შემთხვევაში გაურკვეველ შედეგად რჩება, ხოლო უარყოფა არასოდეს შლის, თიშავს ან ხელახლა ააქტიურებს პროქსის.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ავტომატურ გასუფთავებას მიეცით უფლება, წაშალოს OMNIROUTE_BATCH_RETENTION_DAYS-ზე ძველი, საბოლოო მდგომარეობაში მყოფი (დასრულებული/წარუმატებელი/გაუქმებული/ვადაგასული) Batch API დავალებები მათ თითოეულ სტრიქონთან დაკავშირებულ საკონტროლო წერტილებთან ერთად და გაასუფთაოს ატვირთული ფაილების BLOB-შიგთავსი მათი expires_at ვადის გასვლის შემდეგ. ნაგულისხმევად გამორთულია: ყველა არსებულ ინსტალაციაში ეს მონაცემები ზუსტად ისე დარჩება, როგორც აქამდე, სანამ ოპერატორი ფუნქციას არ ჩართავს. ოპერატორის მიერ გამოძახებულ DELETE /api/v1/batches/delete-completed მარშრუტზე ეს პარამეტრი გავლენას არ ახდენს — ის ცალკე, უპირობო საჯარო API-კონტრაქტია.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "ხელმისაწვდომია განახლება: v{current} → v{latest}", "cliproxyapiVersion": "ვერსია" }, + "modelCatalog": { + "title": "Models & Combos", + "subtitle": "დაათვალიერეთ და შეამოწმეთ მოდელები და კომბო მარშრუტიზაციის მილსადენები ყველა პროვაიდერში.", + "refresh": "განახლება", + "modelsTab": "მოდელები", + "combosTab": "კომბოები", + "catalogSections": "კატალოგის სექციები", + "loading": "იტვირთება...", + "retry": "ხელახლა ცდა", + "unableToLoad": "მოდელების კატალოგის ჩატვირთვა ვერ მოხერხდა.", + "unableToLoadCombos": "კომბოების ჩატვირთვა ვერ მოხერხდა.", + "checkConnection": "შეამოწმეთ კავშირი და სცადეთ ხელახლა.", + "noModelsAvailable": "მოდელები ჯერ ხელმისაწვდომი არ არის.", + "noModelsMatch": "ამ ფილტრებს არცერთი მოდელი არ ემთხვევა.", + "noCombosAvailable": "კომბოები ჯერ ხელმისაწვდომი არ არის.", + "noCombosMatch": "ამ ფილტრებს არცერთი კომბო არ ემთხვევა.", + "clearFilters": "ფილტრების გასუფთავება", + "searchModels": "მოდელების ძიება", + "searchModelsPlaceholder": "ძიება მოდელის, პროვაიდერის ან შესაძლებლობის მიხედვით", + "searchCombos": "კომბოების ძიება", + "searchCombosPlaceholder": "ძიება კომბოს სახელის, მოდელების ან აღწერის მიხედვით", + "modelCountSingle": "მოდელი", + "modelCountPlural": "მოდელები", + "comboCountSingle": "კომბო", + "comboCountPlural": "კომბოები", + "provider": "პროვაიდერი", + "allProviders": "ყველა პროვაიდერი", + "type": "ტიპი", + "allTypes": "ყველა ტიპი", + "subtype": "ქვეტიპი", + "allSubtypes": "ყველა ქვეტიპი", + "capability": "შესაძლებლობა", + "allCapabilities": "ყველა შესაძლებლობა", + "pricing": "ფასები", + "allPricing": "ყველა ფასი", + "freeOnly": "მხოლოდ უფასო", + "nonFree": "სტანდარტული / ფასიანი", + "providerHealth": "პროვაიდერის მდგომარეობა", + "allHealthStates": "ყველა მდგომარეობა", + "healthy": "გამართული", + "degraded": "შეფერხებული", + "down": "გათიშული", + "testResult": "ტესტის შედეგი", + "allResults": "ყველა შედეგი", + "untested": "შეუმოწმებელი", + "statusOk": "კარგი", + "statusSlow": "ნელი", + "statusError": "შეცდომა", + "minContext": "მინ. კონტექსტი", + "minContextPlaceholder": "მაგ. 32000", + "strategy": "სტრატეგია", + "allStrategies": "ყველა სტრატეგია", + "status": "სტატუსი", + "allStatuses": "ყველა სტატუსი", + "active": "აქტიური", + "paused": "შეჩერებული", + "minMembers": "მინ. წევრები", + "minMembersPlaceholder": "მაგ. 1", + "maxMembers": "მაქს. წევრები", + "maxMembersPlaceholder": "მაგ. 10", + "testSelected": "მონიშნულის ტესტირება ({count})", + "testAllFiltered": "ყველა გაფილტრულის ტესტირება ({count})", + "cancel": "გაუქმება", + "clearResults": "შედეგების გასუფთავება", + "testing": "იტესტება...", + "rateLimited": "ლიმიტი გადაჭარბებულია", + "quotaExceeded": "კვოტა ამოიწურა", + "timeout": "დრო ამოიწურა", + "otherError": "შეცდომა", + "justNow": "ახლახან", + "minutesAgo": "{count} წთ წინ", + "hoursAgo": "{count} სთ წინ", + "tableRegion": "მოდელების კატალოგის ცხრილი", + "combosTableRegion": "კომბინაციების კატალოგის ცხრილი", + "tableCaption": "მოდელების კატალოგი ყველა პროვაიდერში", + "combosTableCaption": "კომბინაციების კატალოგი მდგომარეობის ტესტის შედეგებით", + "selectAllModels": "ამ გვერდზე ყველა მოდელის მონიშვნა", + "selectAllCombos": "ამ გვერდზე ყველა კომბინაციის მონიშვნა", + "selectModel": "მოდელის მონიშვნა: {name}", + "selectCombo": "კომბინაციის მონიშვნა: {name}", + "model": "მოდელი", + "capabilities": "შესაძლებლობები", + "context": "კონტექსტი", + "output": "მაქსიმალური გამონატანი", + "flags": "დროშები", + "healthTest": "მდგომარეობის ტესტი", + "actions": "მოქმედებები", + "test": "ტესტირება", + "custom": "მორგებული", + "free": "უფასო", + "noFlags": "ფასის ან წყაროს დროშა მითითებული არ არის", + "noCapabilities": "შესაძლებლობების მეტამონაცემები მითითებული არ არის", + "showingModels": "ნაჩვენებია {first}–{last} {total} მოდელიდან", + "showingCombos": "ნაჩვენებია {first}–{last} {total} კომბინაციიდან", + "refreshing": "განახლება…", + "refreshFailed": "განახლება ვერ მოხერხდა. ნაჩვენებია ბოლოს ჩატვირთული კატალოგი.", + "page": "გვერდი {page} {pageCount}-დან", + "previous": "წინა", + "next": "შემდეგი", + "combo": "კომბინაცია", + "members": "წევრები", + "moreMembers": "კიდევ +{count}" + }, "combos": { "title": "კომბინაციები", "description": "შექმენით მოდელების კომბინაციები შეწონილი მარშრუტიზაციითა და სარეზერვო ვარიანტის მხარდაჭერით", diff --git a/src/i18n/messages/km.json b/src/i18n/messages/km.json index 38fbd4ec06da..fdb77e4287b8 100644 --- a/src/i18n/messages/km.json +++ b/src/i18n/messages/km.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "បើកផ្លូវចូលនិម្មិតដែលសម្របខ្លួនតាម tenant នីមួយៗ សម្រាប់ការបញ្ជូនទៅ provider (#9654)៖ ការកើនឡើងខ្លាំងភ្លាមៗរបស់ tenant មួយ នឹងលែងបណ្ដាលឱ្យ tenant មួយទៀតទទួល 503។ env var OMNIROUTE_CHAT_VIRTUAL_LANES មានអាទិភាពលើការកំណត់ជំនួសពី dashboard នេះ ហើយការផ្លាស់ប្ដូរនឹងមានប្រសិទ្ធភាពនៅពេលចាប់ផ្ដើម server ឡើងវិញ។", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ទំព័រអ្នកផ្តល់សេវានៅលើផ្ទាំងគ្រប់គ្រង៖ បង្ហាញស្លាក ឥតគិតថ្លៃ តែលើសញ្ញាដែលអ្នកផ្តល់សេវាទទួលស្គាល់ប៉ុណ្ណោះ — លុបចោលការសន្និដ្ឋានតាមឈ្មោះបង្ហាញ វាលឥតគិតថ្លៃដែលមិនមែនជាតម្លៃប៊ូលីន និងបច្ច័យ :free លើអ្នកផ្តល់សេវាដែលបានចុះបញ្ជី ប៉ុន្តែមិនមានកម្រិតសេវាឥតគិតថ្លៃដែលបានចងក្រងជាឯកសារ។ ការបិទនឹងរក្សាច្បាប់ស្លាកចាស់ដដែល។", "featureFlagProxySkipRecentlyFailedDescription": "ក្រុមប្រូកស៊ី និងការបង្វិលតាមគណនីនីមួយៗរបស់ opencode នឹងផ្អាកការប្រើប្រូកស៊ីដែលទើបតែបរាជ័យឡើងវិញ (ការស្ទង់ TCP ត្រូវបានបដិសេធ ឬទទួលបាន 429 តាមរយៈវា) ក្នុងរយៈពេលមួយសម្រាប់ដំណើរការនីមួយៗ ដែលកើនទ្វេដងរាល់ពេលកើតឡើងម្តងទៀត រហូតដល់កម្រិតអតិបរមា។ គ្មានស្ថានភាពប្រូកស៊ីត្រូវបានកត់ត្រាទេ ហើយនៅពេលបេក្ខភាពទាំងអស់ត្រូវបានទុកមួយឡែក ជម្រើសនៅតែមិនផ្លាស់ប្តូរ។ បើកតាមលំនាំដើម៖ `false` ស្ដារការជ្រើសរើសធម្មតាវិញ។", - "featureFlagProxyPoolSharedEgressOrderDescription": "សម្រាប់អ្នកផ្តល់សេវាដែលកូតាត្រូវបានបែងចែកតាមអាសយដ្ឋាន egress ចាត់ចំណាត់ថ្នាក់សមាជិក pool ដែលចែករំលែកអាសយដ្ឋាន egress របស់សមាជិកដែលទើបត្រូវបានបដិសេធឱ្យនៅខាងក្រោមសមាជិកល្អ (healthy) បន្តិច។ កែប្រែតែលំដាប់ប៉ុណ្ណោះ មិនដែលត្រូវបានដកចេញឡើយ។ ត្រូវការ PROXY_SKIP_RECENTLY_FAILED ដែលបង្កើតសញ្ញាបដិសេធដែលវាអាន។ បិទតាមលំនាំដើម៖ លំដាប់នៃការជ្រើសរើសគឺដូចគ្នាបេះបិទនឹងការបង្វិលធម្មតា។", "featureFlagProxyPoolEgressObservationDescription": "បង្ហាញនៅក្រោមក្រុមប្រូកស៊ីក្នុងផ្ទាំងគ្រប់គ្រងថា ក្នុងរយៈពេល 24 ម៉ោងចុងក្រោយ មាន IP ចេញក្រៅដែលបានសង្កេតឃើញចំនួនប៉ុន្មានបានបម្រើសមាជិករបស់ក្រុម មានការតភ្ជាប់ចំនួនប៉ុន្មានបានប្រើពួកវា និងចំនួនអតិបរមាដែលបានឃើញនៅពីក្រោយ IP តែមួយ។ សម្រាប់តែអានប៉ុណ្ណោះ គណនាពីកំណត់ហេតុប្រូកស៊ី និងមិនដែលប្រើសម្រាប់ការកំណត់ផ្លូវទេ។ បិទតាមលំនាំដើម៖ កម្មវិធីកែសម្រួលក្រុមមិនផ្លាស់ប្តូរ ហើយផ្លូវសង្កេតឆ្លើយតបជា null។", "featureFlagProxyHealthBlockedResetsStreakDescription": "ក្នុងការត្រួតពិនិត្យសុខភាពប្រូកស៊ី អនុញ្ញាតឱ្យការស្ទង់ដែលគោលដៅបានបដិសេធ (401/403/429៖ ប្រូកស៊ីបានបញ្ជូនបន្ត ប៉ុន្តែគោលដៅបានបដិសេធ IP ចេញក្រៅនេះ) កំណត់ចំនួនបរាជ័យជាប់ៗគ្នារបស់ប្រូកស៊ីឡើងវិញ ដូចការស្ទង់ដែលត្រូវបានបម្រើ។ បិទតាមលំនាំដើម៖ ការបដិសេធនៅតែអព្យាក្រឹត និងរក្សាចំនួនបរាជ័យជាប់ៗគ្នា។ 5xx នៅតែមិនអាចសន្និដ្ឋានបានក្នុងករណីទាំងពីរ ហើយការបដិសេធមិនដែលលុប បិទ ឬធ្វើឱ្យប្រូកស៊ីសកម្មឡើងវិញទេ។", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "អនុញ្ញាតឱ្យការសម្អាតដោយស្វ័យប្រវត្តិលុបកិច្ចការ Batch API ដែលស្ថិតក្នុងស្ថានភាពបញ្ចប់ (បានបញ្ចប់/បរាជ័យ/បានបោះបង់/ផុតកំណត់) និងចាស់ជាង OMNIROUTE_BATCH_RETENTION_DAYS រួមទាំងចំណុចត្រួតពិនិត្យតាមបន្ទាត់របស់កិច្ចការទាំងនោះ ព្រមទាំងសម្អាតខ្លឹមសារ BLOB របស់ឯកសារដែលបានផ្ទុកឡើង និងហួស expires_at របស់វា។ តាមលំនាំដើម មុខងារនេះត្រូវបានបិទ៖ ការដំឡើងដែលមានស្រាប់ទាំងអស់នឹងរក្សាទិន្នន័យនេះដូចមុនទាំងស្រុង រហូតដល់ប្រតិបត្តិករជ្រើសរើសបើកប្រើ។ Route DELETE /api/v1/batches/delete-completed ដែលប្រតិបត្តិករបើកដំណើរការ មិនរងផលប៉ះពាល់ទោះជាករណីណាក៏ដោយ — វាជាកិច្ចសន្យា public API ដាច់ដោយឡែក និងគ្មានលក្ខខណ្ឌ។", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "មានបច្ចុប្បន្នភាព៖ v{current} → v{latest}", "cliproxyapiVersion": "កំណែ" }, + "modelCatalog": { + "title": "ម៉ូឌែល និង បន្សំ", + "subtitle": "រុករក និងធ្វើតេស្តសុខភាពម៉ូឌែល ព្រមទាំង pipeline កំណត់ផ្លូវបន្សំនៅគ្រប់អ្នកផ្តល់សេវាទាំងអស់។", + "refresh": "ផ្ទុកឡើងវិញ", + "modelsTab": "ម៉ូឌែល", + "combosTab": "បន្សំ", + "catalogSections": "ផ្នែកកាតាឡុក", + "loading": "កំពុងផ្ទុក...", + "retry": "ព្យាយាមម្តងទៀត", + "unableToLoad": "មិនអាចផ្ទុកកាតាឡុកម៉ូឌែលបានទេ។", + "unableToLoadCombos": "មិនអាចផ្ទុកបន្សំបានទេ។", + "checkConnection": "សូមពិនិត្យមើលការតភ្ជាប់ ហើយព្យាយាមម្តងទៀត។", + "noModelsAvailable": "មិនទាន់មានម៉ូឌែលនៅឡើយទេ។", + "noModelsMatch": "គ្មានម៉ូឌែលណាដែលត្រូវនឹងតម្រងទាំងនេះទេ។", + "noCombosAvailable": "មិនទាន់មានបន្សំនៅឡើយទេ។", + "noCombosMatch": "គ្មានបន្សំណាដែលត្រូវនឹងតម្រងទាំងនេះទេ។", + "clearFilters": "សម្អាតតម្រង", + "searchModels": "ស្វែងរកម៉ូឌែល", + "searchModelsPlaceholder": "ស្វែងរកតាមម៉ូឌែល អ្នកផ្តល់សេវា ឬសមត្ថភាព", + "searchCombos": "ស្វែងរកបន្សំ", + "searchCombosPlaceholder": "ស្វែងរកតាមឈ្មោះបន្សំ ម៉ូឌែល ឬការពិពណ៌នា", + "modelCountSingle": "ម៉ូឌែល", + "modelCountPlural": "ម៉ូឌែល", + "comboCountSingle": "បន្សំ", + "comboCountPlural": "បន្សំ", + "provider": "អ្នកផ្តល់សេវា", + "allProviders": "អ្នកផ្តល់សេវាទាំងអស់", + "type": "ប្រភេទ", + "allTypes": "ប្រភេទទាំងអស់", + "subtype": "ប្រភេទរង", + "allSubtypes": "ប្រភេទរងទាំងអស់", + "capability": "សមត្ថភាព", + "allCapabilities": "សមត្ថភាពទាំងអស់", + "pricing": "តម្លៃ", + "allPricing": "តម្លៃទាំងអស់", + "freeOnly": "ឥតគិតថ្លៃប៉ុណ្ណោះ", + "nonFree": "ស្តង់ដារ / មិនឥតគិតថ្លៃ", + "providerHealth": "ស្ថានភាពសុខភាពអ្នកផ្តល់សេវា", + "allHealthStates": "ស្ថានភាពសុខភាពទាំងអស់", + "healthy": "ដំណើរការល្អ", + "degraded": "ដំណើរការធ្លាក់ចុះ", + "down": "មិនដំណើរការ", + "testResult": "លទ្ធផលតេស្ត", + "allResults": "លទ្ធផលទាំងអស់", + "untested": "មិនទាន់តេស្ត", + "statusOk": "ធម្មតា", + "statusSlow": "យឺត", + "statusError": "កំហុស", + "minContext": "បរិបទអប្បបរមា", + "minContextPlaceholder": "ឧ. 32000", + "strategy": "យុទ្ធសាស្ត្រ", + "allStrategies": "យុទ្ធសាស្ត្រទាំងអស់", + "status": "ស្ថានភាព", + "allStatuses": "ស្ថានភាពទាំងអស់", + "active": "សកម្ម", + "paused": "បានផ្អាក", + "minMembers": "សមាជិកអប្បបរមា", + "minMembersPlaceholder": "ឧ. 1", + "maxMembers": "សមាជិកអតិបរមា", + "maxMembersPlaceholder": "ឧ. 10", + "testSelected": "តេស្តធាតុដែលបានជ្រើសរើស ({count})", + "testAllFiltered": "តេស្តធាតុដែលបានចម្រាញ់ទាំងអស់ ({count})", + "cancel": "បោះបង់", + "clearResults": "សម្អាតលទ្ធផល", + "testing": "កំពុងតេស្ត...", + "rateLimited": "ជាប់កម្រិតអត្រា", + "quotaExceeded": "លើសកូតា", + "timeout": "អស់ពេល", + "otherError": "កំហុស", + "justNow": "ទើបតែឥឡូវ", + "minutesAgo": "{count} នាទីមុន", + "hoursAgo": "{count} ម៉ោងមុន", + "tableRegion": "តារាងកាតាឡុកម៉ូឌែល", + "combosTableRegion": "តារាងកាតាឡុកបន្សំ", + "tableCaption": "កាតាឡុកម៉ូឌែលនៅគ្រប់អ្នកផ្តល់សេវាទាំងអស់", + "combosTableCaption": "កាតាឡុកបន្សំជាមួយលទ្ធផលតេស្តសុខភាព", + "selectAllModels": "ជ្រើសរើសម៉ូឌែលទាំងអស់នៅលើទំព័រនេះ", + "selectAllCombos": "ជ្រើសរើសបន្សំទាំងអស់នៅលើទំព័រនេះ", + "selectModel": "ជ្រើសរើសម៉ូឌែល {name}", + "selectCombo": "ជ្រើសរើសបន្សំ {name}", + "model": "ម៉ូឌែល", + "capabilities": "សមត្ថភាព", + "context": "បរិបទ", + "output": "លទ្ធផលអតិបរមា", + "flags": "ទង់សម្គាល់", + "healthTest": "តេស្តសុខភាព", + "actions": "សកម្មភាព", + "test": "តេស្ត", + "custom": "ផ្ទាល់ខ្លួន", + "free": "ឥតគិតថ្លៃ", + "noFlags": "មិនមានតម្លៃ ឬទង់សម្គាល់ប្រភពត្រូវបានរាយការណ៍ទេ", + "noCapabilities": "មិនមានទិន្នន័យមេតានៃសមត្ថភាពត្រូវបានរាយការណ៍ទេ", + "showingModels": "កំពុងបង្ហាញ {first}–{last} នៃ {total} ម៉ូឌែល", + "showingCombos": "កំពុងបង្ហាញ {first}–{last} នៃ {total} បន្សំ", + "refreshing": "កំពុងផ្ទុកឡើងវិញ…", + "refreshFailed": "ការផ្ទុកឡើងវិញបានបរាជ័យ។ កំពុងបង្ហាញកាតាឡុកដែលបានផ្ទុកចុងក្រោយ។", + "page": "ទំព័រ {page} នៃ {pageCount}", + "previous": "មុន", + "next": "បន្ទាប់", + "combo": "បន្សំ", + "members": "សមាជិក", + "moreMembers": "+{count} ទៀត" + }, "combos": { "title": "បន្សំ", "description": "បង្កើតបន្សំម៉ូដែលដោយប្រើការបញ្ជូនតាមទម្ងន់ និងការគាំទ្រការបម្រុងទុក", diff --git a/src/i18n/messages/kn.json b/src/i18n/messages/kn.json index 15a7f11da421..ee1d2018d643 100644 --- a/src/i18n/messages/kn.json +++ b/src/i18n/messages/kn.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ಪ್ರೊವೈಡರ್ ಡಿಸ್ಪ್ಯಾಚ್ಗಾಗಿ ಪ್ರತಿ-ಟೆನಂಟ್ ಅಡಾಪ್ಟಿವ್ ವರ್ಚುವಲ್ ಅಡ್ಮಿಷನ್ ಲೇನ್ಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ (#9654): ಒಂದು ಟೆನಂಟ್ನ ಬರ್ಸ್ಟ್ನಿಂದ ಇನ್ನು ಮುಂದೆ ಮತ್ತೊಂದು ಟೆನಂಟ್ಗೆ 503 ದೋಷ ಉಂಟಾಗುವುದಿಲ್ಲ. ಈ ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಓವರ್ರೈಡ್ಗಿಂತ OMNIROUTE_CHAT_VIRTUAL_LANES env var ಗೆ ಆದ್ಯತೆ ಇರುತ್ತದೆ; ಸರ್ವರ್ ಮರುಪ್ರಾರಂಭವಾದಾಗ ಬದಲಾವಣೆಗಳು ಜಾರಿಗೆ ಬರುತ್ತವೆ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಪ್ರೊವೈಡರ್ ಪುಟಗಳು: ಪ್ರೊವೈಡರ್ ಮಾನ್ಯಗೊಳಿಸುವ ಸಂಕೇತಗಳ ಆಧಾರದ ಮೇಲೆ ಮಾತ್ರ Free ಬ್ಯಾಡ್ಜ್ ಅನ್ನು ತೋರಿಸಿ — ದಾಖಲಿತ ಉಚಿತ ಹಂತವಿಲ್ಲದ ನೋಂದಾಯಿತ ಪ್ರೊವೈಡರ್ಗಳಿಗೆ ಪ್ರದರ್ಶನ-ಹೆಸರು ಹ್ಯೂರಿಸ್ಟಿಕ್, ಬೂಲಿಯನ್ ಅಲ್ಲದ ಉಚಿತ ಕ್ಷೇತ್ರಗಳು ಮತ್ತು :free ಪ್ರತ್ಯಯಗಳನ್ನು ಪರಿಗಣಿಸುವುದಿಲ್ಲ. ಆಫ್ ಮಾಡಿದಾಗ ಹಿಂದಿನ ಬ್ಯಾಡ್ಜ್ ನಿಯಮವು ಉಳಿಯುತ್ತದೆ.", "featureFlagProxySkipRecentlyFailedDescription": "ಪ್ರಾಕ್ಸಿ ಪೂಲ್ಗಳು ಮತ್ತು opencode ನ ಪ್ರತಿ-ಖಾತೆ ರೊಟೇಶನ್, ಇತ್ತೀಚೆಗೆ ವಿಫಲವಾದ ಪ್ರಾಕ್ಸಿಯನ್ನು (TCP ಪ್ರೋಬ್ ನಿರಾಕರಿಸಲ್ಪಟ್ಟಿದ್ದರೆ ಅಥವಾ ಅದರ ಮೂಲಕ 429 ಬಂದಿದ್ದರೆ) ಪ್ರತಿ ಪ್ರಕ್ರಿಯೆಗೆ ಅನ್ವಯಿಸುವ ಅವಧಿಯವರೆಗೆ ಮತ್ತೆ ಬಳಸುವುದಿಲ್ಲ. ಪ್ರತಿ ಪುನರಾವರ್ತನೆಯಲ್ಲೂ ಈ ಅವಧಿ ದ್ವಿಗುಣಗೊಳ್ಳುತ್ತದೆ, ನಿಗದಿತ ಗರಿಷ್ಠ ಮಿತಿಯವರೆಗೆ. ಯಾವುದೇ ಪ್ರಾಕ್ಸಿ ಸ್ಥಿತಿಯನ್ನು ಬರೆಯಲಾಗುವುದಿಲ್ಲ; ಪ್ರತಿಯೊಂದು ಅಭ್ಯರ್ಥಿಯನ್ನೂ ಬದಿಗಿರಿಸಿದಾಗ ಆಯ್ಕೆಯು ಬದಲಾಗುವುದಿಲ್ಲ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆನ್; `false` ಸರಳ ಆಯ್ಕೆಯನ್ನು ಮರುಸ್ಥಾಪಿಸುತ್ತದೆ.", - "featureFlagProxyPoolSharedEgressOrderDescription": "ಯಾವ ಪೂರೈಕೆದಾರರ ಕೋಟಾವನ್ನು egress ವಿಳಾಸದ ಮೂಲಕ ನಿಗದಿಪಡಿಸಲಾಗಿದೆಯೋ, ಅವರಿಗೆ ಇತ್ತೀಚೆಗೆ ನಿರಾಕರಿಸಲಾದ ಸದಸ್ಯರ ಗಮನಿಸಲಾದ egress ವಿಳಾಸವನ್ನು ಹಂಚಿಕೊಳ್ಳುವ ಪೂಲ್ ಸದಸ್ಯರನ್ನು ಆರೋಗ್ಯಕರ ಸದಸ್ಯರ ಕೆಳಗೆ ಶ್ರೇಣೀಕರಿಸಿ. ಕೇವಲ ಆದ್ಯತಾ ಕ್ರಮ ಮಾತ್ರ, ಎಂದಿಗೂ ಹೊರಗಿಡಲಾಗುವುದಿಲ್ಲ. ಇದು ಓದುವ ನಿರಾಕರಣೆಯ ಸಿಗ್ನಲ್ ಅನ್ನು ಉತ್ಪಾದಿಸುವ PROXY_SKIP_RECENTLY_FAILED ನ ಅಗತ್ಯವಿದೆ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ನಿಷ್ಕ್ರಿಯವಾಗಿರುತ್ತದೆ: ಆಯ್ಕೆಯ ಕ್ರಮವು ನಿಖರವಾಗಿ ಸಾಮಾನ್ಯ ರೊಟೇಶನ್ ಆಗಿದೆ.", "featureFlagProxyPoolEgressObservationDescription": "ಡ್ಯಾಶ್ಬೋರ್ಡ್ನಲ್ಲಿ ಪ್ರಾಕ್ಸಿ ಪೂಲ್ನ ಅಡಿಯಲ್ಲಿ, ಕಳೆದ 24 ಗಂಟೆಗಳಲ್ಲಿ ಅದರ ಸದಸ್ಯರಿಗೆ ಸೇವೆ ನೀಡಿದ ಗಮನಿಸಲಾದ ಎಗ್ರೆಸ್ IPಗಳ ಸಂಖ್ಯೆ, ಅವುಗಳನ್ನು ಬಳಸಿದ ಸಂಪರ್ಕಗಳ ಸಂಖ್ಯೆ ಮತ್ತು ಒಂದೇ IPಯ ಹಿಂದೆ ಕಂಡುಬಂದ ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯನ್ನು ತೋರಿಸಿ. ಇದು ಓದಲು ಮಾತ್ರ; ಪ್ರಾಕ್ಸಿ ಲಾಗ್ನಿಂದ ಲೆಕ್ಕ ಹಾಕಲಾಗುತ್ತದೆ ಮತ್ತು ರೂಟಿಂಗ್ಗಾಗಿ ಎಂದಿಗೂ ಬಳಸಲಾಗುವುದಿಲ್ಲ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆಫ್: ಪೂಲ್ ಎಡಿಟರ್ ಬದಲಾಗುವುದಿಲ್ಲ ಮತ್ತು ವೀಕ್ಷಣಾ ರೂಟ್ null ಎಂದು ಉತ್ತರಿಸುತ್ತದೆ.", "featureFlagProxyHealthBlockedResetsStreakDescription": "ಪ್ರಾಕ್ಸಿ ಆರೋಗ್ಯ ಪರಿಶೀಲನೆಯಲ್ಲಿ, ಗುರಿಯು ನಿರಾಕರಿಸಿದ ಪ್ರೋಬ್ (401/403/429: ಪ್ರಾಕ್ಸಿಯು ರಿಲೇ ಮಾಡಿದೆ, ಆದರೆ ಗಮ್ಯಸ್ಥಾನವು ಈ ಎಗ್ರೆಸ್ IPಯನ್ನು ನಿರಾಕರಿಸಿದೆ) ಸೇವೆ ಸಲ್ಲಿಸಿದ ಪ್ರೋಬ್ನಂತೆಯೇ ಪ್ರಾಕ್ಸಿಯ ಸತತ-ವೈಫಲ್ಯ ಸರಣಿಯನ್ನು ಮರುಹೊಂದಿಸಲು ಅನುಮತಿಸಿ. ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ ಆಫ್: ನಿರಾಕರಣೆಯು ತಟಸ್ಥವಾಗಿಯೇ ಉಳಿದು ಸರಣಿಯನ್ನು ಹಾಗೆಯೇ ಇಡುತ್ತದೆ. ಎರಡೂ ಸಂದರ್ಭಗಳಲ್ಲಿ 5xx ಅನಿರ್ಣಾಯಕವಾಗಿಯೇ ಉಳಿಯುತ್ತದೆ ಮತ್ತು ನಿರಾಕರಣೆಯು ಪ್ರಾಕ್ಸಿಯನ್ನು ಎಂದಿಗೂ ತೆಗೆದುಹಾಕುವುದಿಲ್ಲ, ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುವುದಿಲ್ಲ ಅಥವಾ ಮರುಸಕ್ರಿಯಗೊಳಿಸುವುದಿಲ್ಲ.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ಸ್ವಯಂಚಾಲಿತ ಸ್ವಚ್ಛತಾ ಪ್ರಕ್ರಿಯೆಯು OMNIROUTE_BATCH_RETENTION_DAYS ಗಿಂತ ಹಳೆಯದಾದ ಅಂತಿಮ ಸ್ಥಿತಿಯ (ಪೂರ್ಣಗೊಂಡ/ವಿಫಲಗೊಂಡ/ರದ್ದುಗೊಂಡ/ಅವಧಿ ಮೀರಿದ) Batch API ಕೆಲಸಗಳನ್ನು, ಅವುಗಳ ಪ್ರತಿ-ಸಾಲಿನ ಚೆಕ್ಪಾಯಿಂಟ್ಗಳೊಂದಿಗೆ ಅಳಿಸಲು ಮತ್ತು ತಮ್ಮದೇ expires_at ಮೀರಿರುವ ಅಪ್ಲೋಡ್ ಮಾಡಿದ ಫೈಲ್ಗಳ BLOB ವಿಷಯವನ್ನು ತೆರವುಗೊಳಿಸಲು ಅನುಮತಿಸಿ. ಡೀಫಾಲ್ಟ್ ಆಗಿ ಆಫ್ ಆಗಿರುತ್ತದೆ: ನಿರ್ವಾಹಕರು ಆಯ್ಕೆಮಾಡಿ ಸಕ್ರಿಯಗೊಳಿಸುವವರೆಗೆ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ರತಿಯೊಂದು ಸ್ಥಾಪನೆಯೂ ಈ ಡೇಟಾವನ್ನು ಮೊದಲಿನಂತೆಯೇ ಉಳಿಸಿಕೊಳ್ಳುತ್ತದೆ. ನಿರ್ವಾಹಕರು ಪ್ರಚೋದಿಸುವ DELETE /api/v1/batches/delete-completed ಮಾರ್ಗವು ಯಾವುದೇ ಸಂದರ್ಭದಲ್ಲೂ ಪರಿಣಾಮಗೊಳ್ಳುವುದಿಲ್ಲ — ಅದು ಪ್ರತ್ಯೇಕವಾದ, ಷರತ್ತುರಹಿತ ಸಾರ್ವಜನಿಕ API ಒಪ್ಪಂದವಾಗಿದೆ.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "ನವೀಕರಣ ಲಭ್ಯವಿದೆ: v{current} → v{latest}", "cliproxyapiVersion": "ಆವೃತ್ತಿ" }, + "modelCatalog": { + "title": "ಮಾದರಿಗಳು ಮತ್ತು ಕಾಂಬೊಗಳು", + "subtitle": "ಪ್ರತಿಯೊಬ್ಬ ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾದರಿಗಳು ಮತ್ತು ಕಾಂಬೊ ರೂಟಿಂಗ್ ಪೈಪ್‌ಲೈನ್‌ಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ ಹಾಗೂ ಆರೋಗ್ಯ ತಪಾಸಣೆ ನಡೆಸಿ.", + "refresh": "ರಿಫ್ರೆಶ್ ಮಾಡಿ", + "modelsTab": "ಮಾದರಿಗಳು", + "combosTab": "ಕಾಂಬೊಗಳು", + "catalogSections": "ಕ್ಯಾಟಲಾಗ್ ವಿಭಾಗಗಳು", + "loading": "ಲೋಡ್ ಆಗುತ್ತಿದೆ...", + "retry": "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", + "unableToLoad": "ಮಾದರಿ ಕ್ಯಾಟಲಾಗ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ.", + "unableToLoadCombos": "ಕಾಂಬೊಗಳನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ.", + "checkConnection": "ಸಂಪರ್ಕವನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.", + "noModelsAvailable": "ಇನ್ನೂ ಯಾವುದೇ ಮಾದರಿಗಳು ಲಭ್ಯವಿಲ್ಲ.", + "noModelsMatch": "ಯಾವುದೇ ಮಾದರಿಗಳು ಈ ಫಿಲ್ಟರ್‌ಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗುತ್ತಿಲ್ಲ.", + "noCombosAvailable": "ಇನ್ನೂ ಯಾವುದೇ ಕಾಂಬೊಗಳು ಲಭ್ಯವಿಲ್ಲ.", + "noCombosMatch": "ಯಾವುದೇ ಕಾಂಬೊಗಳು ಈ ಫಿಲ್ಟರ್‌ಗಳಿಗೆ ಹೊಂದಿಕೆಯಾಗುತ್ತಿಲ್ಲ.", + "clearFilters": "ಫಿಲ್ಟರ್‌ಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", + "searchModels": "ಮಾದರಿಗಳನ್ನು ಹುಡುಕಿ", + "searchModelsPlaceholder": "ಮಾದರಿ, ಪೂರೈಕೆದಾರ ಅಥವಾ ಸಾಮರ್ಥ್ಯದ ಮೂಲಕ ಹುಡುಕಿ", + "searchCombos": "ಕಾಂಬೊಗಳನ್ನು ಹುಡುಕಿ", + "searchCombosPlaceholder": "ಕಾಂಬೊ ಹೆಸರು, ಮಾದರಿಗಳು ಅಥವಾ ವಿವರಣೆಯ ಮೂಲಕ ಹುಡುಕಿ", + "modelCountSingle": "ಮಾದರಿ", + "modelCountPlural": "ಮಾದರಿಗಳು", + "comboCountSingle": "ಕಾಂಬೊ", + "comboCountPlural": "ಕಾಂಬೊಗಳು", + "provider": "ಪೂರೈಕೆದಾರ", + "allProviders": "ಎಲ್ಲಾ ಪೂರೈಕೆದಾರರು", + "type": "ಪ್ರಕಾರ", + "allTypes": "ಎಲ್ಲಾ ಪ್ರಕಾರಗಳು", + "subtype": "ಉಪಪ್ರಕಾರ", + "allSubtypes": "ಎಲ್ಲಾ ಉಪಪ್ರಕಾರಗಳು", + "capability": "ಸಾಮರ್ಥ್ಯ", + "allCapabilities": "ಎಲ್ಲಾ ಸಾಮರ್ಥ್ಯಗಳು", + "pricing": "ಬೆಲೆ ನಿಗದಿ", + "allPricing": "ಎಲ್ಲಾ ಬೆಲೆಗಳು", + "freeOnly": "ಉಚಿತ ಮಾತ್ರ", + "nonFree": "ಪ್ರಮಾಣಿತ / ಉಚಿತವಲ್ಲದ", + "providerHealth": "ಪೂರೈಕೆದಾರರ ಆರೋಗ್ಯ", + "allHealthStates": "ಎಲ್ಲಾ ಆರೋಗ್ಯ ಸ್ಥಿತಿಗಳು", + "healthy": "ಆರೋಗ್ಯಕರ", + "degraded": "ಕ್ಷೀಣಿಸಿದೆ", + "down": "ಸ್ಥಗಿತಗೊಂಡಿದೆ", + "testResult": "ಪರೀಕ್ಷಾ ಫಲಿತಾಂಶ", + "allResults": "ಎಲ್ಲಾ ಫಲಿತಾಂಶಗಳು", + "untested": "ಪರೀಕ್ಷಿಸಲಾಗಿಲ್ಲ", + "statusOk": "ಸರಿ", + "statusSlow": "ನಿಧಾನ", + "statusError": "ದೋಷ", + "minContext": "ಕನಿಷ್ಠ ಸಂದರ್ಭ", + "minContextPlaceholder": "ಉದಾ. 32000", + "strategy": "ಕಾರ್ಯತಂತ್ರ", + "allStrategies": "ಎಲ್ಲಾ ಕಾರ್ಯತಂತ್ರಗಳು", + "status": "ಸ್ಥಿತಿ", + "allStatuses": "ಎಲ್ಲಾ ಸ್ಥಿತಿಗಳು", + "active": "ಸಕ್ರಿಯ", + "paused": "ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ", + "minMembers": "ಕನಿಷ್ಠ ಸದಸ್ಯರು", + "minMembersPlaceholder": "ಉದಾ. 1", + "maxMembers": "ಗರಿಷ್ಠ ಸದಸ್ಯರು", + "maxMembersPlaceholder": "ಉದಾ. 10", + "testSelected": "ಆಯ್ಕೆಮಾಡಿದ್ದನ್ನು ಪರೀಕ್ಷಿಸಿ ({count})", + "testAllFiltered": "ಫಿಲ್ಟರ್ ಮಾಡಿದ ಎಲ್ಲವನ್ನೂ ಪರೀಕ್ಷಿಸಿ ({count})", + "cancel": "ರದ್ದುಮಾಡಿ", + "clearResults": "ಫಲಿತಾಂಶಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", + "testing": "ಪರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ...", + "rateLimited": "ದರ ಮಿತಿ ಮೀರಿದೆ", + "quotaExceeded": "ಕೋಟಾ ಮೀರಿದೆ", + "timeout": "ಸಮಯ ಮೀರಿದೆ", + "otherError": "ದೋಷ", + "justNow": "ಈಗಷ್ಟೇ", + "minutesAgo": "{count} ನಿಮಿಷಗಳ ಹಿಂದೆ", + "hoursAgo": "{count} ಗಂಟೆಗಳ ಹಿಂದೆ", + "tableRegion": "ಮಾದರಿ ಕ್ಯಾಟಲಾಗ್ ಕೋಷ್ಟಕ", + "combosTableRegion": "ಕಾಂಬೊಗಳ ಕ್ಯಾಟಲಾಗ್ ಕೋಷ್ಟಕ", + "tableCaption": "ಎಲ್ಲಾ ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾದರಿ ಕ್ಯಾಟಲಾಗ್", + "combosTableCaption": "ಆರೋಗ್ಯ ಪರೀಕ್ಷಾ ಫಲಿತಾಂಶಗಳೊಂದಿಗೆ ಕಾಂಬೊಗಳ ಕ್ಯಾಟಲಾಗ್", + "selectAllModels": "ಈ ಪುಟದಲ್ಲಿರುವ ಎಲ್ಲಾ ಮಾದರಿಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "selectAllCombos": "ಈ ಪುಟದಲ್ಲಿರುವ ಎಲ್ಲಾ ಕಾಂಬೊಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "selectModel": "{name} ಮಾದರಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "selectCombo": "{name} ಕಾಂಬೊವನ್ನು ಆಯ್ಕೆಮಾಡಿ", + "model": "ಮಾದರಿ", + "capabilities": "ಸಾಮರ್ಥ್ಯಗಳು", + "context": "ಸಂದರ್ಭ", + "output": "ಗರಿಷ್ಠ ಔಟ್‌ಪುಟ್", + "flags": "ಫ್ಲ್ಯಾಗ್‌ಗಳು", + "healthTest": "ಆರೋಗ್ಯ ಪರೀಕ್ಷೆ", + "actions": "ಕ್ರಿಯೆಗಳು", + "test": "ಪರೀಕ್ಷೆ", + "custom": "ಕಸ್ಟಮ್", + "free": "ಉಚಿತ", + "noFlags": "ಯಾವುದೇ ಬೆಲೆ ಅಥವಾ ಮೂಲದ ಫ್ಲ್ಯಾಗ್ ವರದಿಯಾಗಿಲ್ಲ", + "noCapabilities": "ಯಾವುದೇ ಸಾಮರ್ಥ್ಯದ ಮೆಟಾಡೇಟಾ ವರದಿಯಾಗಿಲ್ಲ", + "showingModels": "{total} ಮಾಡೆಲ್‌ಗಳಲ್ಲಿ {first}–{last} ಅನ್ನು ತೋರಿಸಲಾಗುತ್ತಿದೆ", + "showingCombos": "{total} ಕಾಂಬೋಗಳಲ್ಲಿ {first}–{last} ಅನ್ನು ತೋರಿಸಲಾಗುತ್ತಿದೆ", + "refreshing": "ರಿಫ್ರೆಶ್ ಮಾಡಲಾಗುತ್ತಿದೆ…", + "refreshFailed": "ರಿಫ್ರೆಶ್ ವಿಫಲವಾಗಿದೆ. ಕೊನೆಯದಾಗಿ ಲೋಡ್ ಮಾಡಲಾದ ಕ್ಯಾಟಲಾಗ್ ಅನ್ನು ತೋರಿಸಲಾಗುತ್ತಿದೆ.", + "page": "{pageCount} ರಲ್ಲಿ {page} ನೇ ಪುಟ", + "previous": "ಹಿಂದಿನದು", + "next": "ಮುಂದಿನದು", + "combo": "ಕಾಂಬೋ", + "members": "ಸದಸ್ಯರು", + "moreMembers": "+{count} ಇನ್ನಷ್ಟು" + }, "combos": { "title": "ಸಂಯೋಜನೆಗಳು", "description": "ತೂಕಾಧಾರಿತ ರೌಟಿಂಗ್ ಮತ್ತು ಫಾಲ್ಬ್ಯಾಕ್ ಬೆಂಬಲದೊಂದಿಗೆ ಮಾದರಿ ಸಂಯೋಜನೆಗಳನ್ನು ರಚಿಸಿ", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index 15f1fb421fa4..a4e1c951a0dd 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "공급자 디스패치를 위해 테넌트별 적응형 가상 승인 레인을 활성화합니다(#9654): 한 테넌트의 폭증이 더 이상 다른 테넌트에 503을 반환하지 않습니다. OMNIROUTE_CHAT_VIRTUAL_LANES 환경 변수가 이 대시보드 설정보다 우선하며, 변경 사항은 서버 재시작 시 적용됩니다.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "대시보드 제공업체 페이지: 제공업체가 인정하는 신호에만 무료 배지를 표시합니다. 문서화된 무료 등급이 없는 등록된 제공업체의 표시 이름 추정 방식, 불리언이 아닌 무료 필드 및 :free 접미사는 사용하지 않습니다. 끄면 기존 배지 규칙이 유지됩니다.", "featureFlagProxySkipRecentlyFailedDescription": "프록시 풀과 opencode의 계정별 로테이션은 방금 실패한 프록시(TCP 프로브 거부 또는 해당 프록시를 통해 429 응답 수신)를 프로세스별 유예 기간 동안 다시 제공하지 않습니다. 이 기간은 실패가 반복될 때마다 두 배로 늘어나며 상한이 있습니다. 프록시 상태는 기록되지 않으며, 모든 후보가 제외되면 선택 결과는 변경되지 않습니다. 기본적으로 켜져 있으며, `false`로 설정하면 일반 선택으로 돌아갑니다.", - "featureFlagProxyPoolSharedEgressOrderDescription": "이그레스 주소 기준으로 쿼터가 분할되는 제공자의 경우, 최근 요청이 거부된 멤버와 동일한 이그레스 주소로 확인된 풀 멤버의 우선순위를 정상 멤버 바로 뒤로 배치합니다. 순서만 변경되며 풀에서 제외되지는 않습니다. 거부 신호를 감지하려면 해당 신호를 생성하는 PROXY_SKIP_RECENTLY_FAILED가 활성화되어 있어야 합니다. 기본값은 비활성화이며, 선택 순서는 일반 로테이션과 동일합니다.", "featureFlagProxyPoolEgressObservationDescription": "대시보드의 프록시 풀 아래에 지난 24시간 동안 해당 풀의 구성원에 사용된 것으로 관찰된 송신 IP 수, 해당 IP를 사용한 연결 수, 단일 IP에서 관찰된 최대 연결 수를 표시합니다. 읽기 전용이며 프록시 로그에서 계산되고 라우팅에는 절대 사용되지 않습니다. 기본적으로 꺼져 있으며, 풀 편집기는 변경되지 않고 관찰 라우트는 null을 반환합니다.", "featureFlagProxyHealthBlockedResetsStreakDescription": "프록시 상태 점검에서 대상이 거부한 프로브(401/403/429: 프록시는 전달했지만 대상이 이 송신 IP를 거부함)가 정상 처리된 프로브처럼 프록시의 연속 실패 횟수를 초기화하도록 합니다. 기본적으로 꺼져 있으며, 거부는 중립으로 유지되어 연속 실패 횟수에 영향을 주지 않습니다. 어느 경우든 5xx는 판단 불가로 유지되며, 거부로 인해 프록시가 제거, 비활성화 또는 재활성화되는 일은 없습니다.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "자동 정리 작업이 OMNIROUTE_BATCH_RETENTION_DAYS보다 오래된 종료 상태(완료/실패/취소/만료)의 Batch API 작업과 해당 작업의 줄별 체크포인트를 삭제하고, 자체 expires_at이 지난 업로드 파일의 BLOB 콘텐츠를 지우도록 합니다. 기본적으로 꺼져 있습니다. 운영자가 사용 설정하기 전까지 모든 기존 설치는 이 데이터를 이전과 정확히 동일하게 유지합니다. 운영자가 실행하는 DELETE /api/v1/batches/delete-completed 경로는 설정 여부와 관계없이 영향을 받지 않습니다. 이는 별도의 무조건적인 공개 API 계약입니다.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "업데이트 가능: v{current} → v{latest}", "cliproxyapiVersion": "버전" }, + "modelCatalog": { + "title": "모델 및 콤보", + "subtitle": "모든 제공업체에 걸친 모델 및 콤보 라우팅 파이프라인을 탐색하고 상태를 테스트하세요.", + "refresh": "새로고침", + "modelsTab": "모델", + "combosTab": "콤보", + "catalogSections": "카탈로그 섹션", + "loading": "로딩 중...", + "retry": "다시 시도", + "unableToLoad": "모델 카탈로그를 불러올 수 없습니다.", + "unableToLoadCombos": "콤보를 불러올 수 없습니다.", + "checkConnection": "연결을 확인하고 다시 시도하세요.", + "noModelsAvailable": "사용 가능한 모델이 아직 없습니다.", + "noModelsMatch": "해당 필터와 일치하는 모델이 없습니다.", + "noCombosAvailable": "사용 가능한 콤보가 아직 없습니다.", + "noCombosMatch": "해당 필터와 일치하는 콤보가 없습니다.", + "clearFilters": "필터 초기화", + "searchModels": "모델 검색", + "searchModelsPlaceholder": "모델, 제공업체 또는 기능으로 검색", + "searchCombos": "콤보 검색", + "searchCombosPlaceholder": "콤보 이름, 모델 또는 설명으로 검색", + "modelCountSingle": "모델", + "modelCountPlural": "모델", + "comboCountSingle": "콤보", + "comboCountPlural": "콤보", + "provider": "제공업체", + "allProviders": "모든 제공업체", + "type": "유형", + "allTypes": "모든 유형", + "subtype": "하위 유형", + "allSubtypes": "모든 하위 유형", + "capability": "기능", + "allCapabilities": "모든 기능", + "pricing": "가격", + "allPricing": "모든 가격", + "freeOnly": "무료 전용", + "nonFree": "표준 / 유료", + "providerHealth": "제공업체 상태", + "allHealthStates": "모든 상태", + "healthy": "정상", + "degraded": "성능 저하", + "down": "다운", + "testResult": "테스트 결과", + "allResults": "모든 결과", + "untested": "미테스트", + "statusOk": "정상", + "statusSlow": "지연", + "statusError": "오류", + "minContext": "최소 컨텍스트", + "minContextPlaceholder": "예: 32000", + "strategy": "전략", + "allStrategies": "모든 전략", + "status": "상태", + "allStatuses": "모든 상태", + "active": "활성", + "paused": "일시중지", + "minMembers": "최소 멤버", + "minMembersPlaceholder": "예: 1", + "maxMembers": "최대 멤버", + "maxMembersPlaceholder": "예: 10", + "testSelected": "선택 항목 테스트 ({count})", + "testAllFiltered": "필터링된 모든 항목 테스트 ({count})", + "cancel": "취소", + "clearResults": "결과 지우기", + "testing": "테스트 중...", + "rateLimited": "요청 한도 초과", + "quotaExceeded": "할당량 초과", + "timeout": "시간 초과", + "otherError": "오류", + "justNow": "방금 전", + "minutesAgo": "{count}분 전", + "hoursAgo": "{count}시간 전", + "tableRegion": "모델 카탈로그 테이블", + "combosTableRegion": "콤보 카탈로그 테이블", + "tableCaption": "모든 제공자의 모델 카탈로그", + "combosTableCaption": "상태 테스트 결과가 포함된 콤보 카탈로그", + "selectAllModels": "이 페이지의 모든 모델 선택", + "selectAllCombos": "이 페이지의 모든 콤보 선택", + "selectModel": "모델 {name} 선택", + "selectCombo": "콤보 {name} 선택", + "model": "모델", + "capabilities": "기능", + "context": "컨텍스트", + "output": "최대 출력", + "flags": "플래그", + "healthTest": "상태 테스트", + "actions": "작업", + "test": "테스트", + "custom": "커스텀", + "free": "무료", + "noFlags": "보고된 가격 또는 소스 플래그가 없습니다", + "noCapabilities": "보고된 기능 메타데이터가 없습니다", + "showingModels": "총 {total}개 모델 중 {first}–{last}개 표시", + "showingCombos": "총 {total}개 콤보 중 {first}–{last}개 표시", + "refreshing": "새로고침 중…", + "refreshFailed": "새로고침 실패. 마지막으로 불러온 카탈로그를 표시합니다.", + "page": "{pageCount}페이지 중 {page}페이지", + "previous": "이전", + "next": "다음", + "combo": "콤보", + "members": "멤버", + "moreMembers": "+{count}개 더 보기" + }, "combos": { "title": "콤보", "description": "가중치 기반 라우팅 및 폴백 지원을 통해 모델 콤보 생성", diff --git a/src/i18n/messages/lt.json b/src/i18n/messages/lt.json index e02495b320a5..fc2f8668a215 100644 --- a/src/i18n/messages/lt.json +++ b/src/i18n/messages/lt.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Įjungti kiekvienam nuomotojui pritaikomas adaptyvias virtualias priėmimo juostas teikėjų siuntimui (#9654): vieno nuomotojo srautas nebesukelia 503 klaidos kitam. Aplinkos kintamasis OMNIROUTE_CHAT_VIRTUAL_LANES turi pirmenybę prieš šį skydelio nustatymą; pakeitimai įsigalioja po serverio paleidimo iš naujo.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Teikėjų puslapiuose valdymo skydelyje ženklelį „Nemokama“ rodyti tik pagal tuos požymius, kuriuos teikėjas palaiko — nebenaudojama rodomo pavadinimo euristika, ne loginio tipo nemokamumo laukai ir :free priesagos registruotiems teikėjams, neturintiems dokumentuoto nemokamo plano. Išjungus taikoma ankstesnė ženklelio taisyklė.", "featureFlagProxySkipRecentlyFailedDescription": "Tarpinių serverių telkiniai ir kiekvienai paskyrai taikoma opencode rotacija pakartotinai nebenaudoja ką tik nesuveikusio tarpinio serverio (atmestas TCP patikrinimas arba per jį gautas 429 atsakymas) konkrečiam procesui taikomą laikotarpį, kuris po kiekvieno pasikartojimo padvigubėja iki nustatytos ribos. Tarpinio serverio būsena neįrašoma; atidėjus visus kandidatus, pasirinkimas nesikeičia. Pagal numatytąsias nuostatas įjungta; `false` atkuria įprastą pasirinkimą.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Teikėjams, kurių kvota skirstoma pagal egress adresą, telkinio narį, turintį tą patį stebėtą egress adresą kaip ir neseniai atmestas narys, reitinguoti iškart žemiau sveikų narių. Tik rikiavimas, niekada neišskiriama. Reikalingas PROXY_SKIP_RECENTLY_FAILED, kuris sugeneruoja nuskaitomą atmetimo signalą. Pagal numatytuosius nustatymus išjungta: pasirinkimo tvarka yra tiesiog įprasta rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Valdymo skydelyje po tarpinių serverių telkiniu rodyti, kiek stebėtų išeinančių IP adresų per pastarąsias 24 val. aptarnavo jo narius, kiek ryšių juos naudojo ir didžiausią ryšių skaičių, stebėtą už vieno IP adreso. Tik skaitymui, apskaičiuojama pagal tarpinių serverių žurnalą ir niekada nenaudojama maršrutizavimui. Pagal numatytąsias nuostatas išjungta: telkinio redagavimo priemonė nesikeičia, o stebėjimo maršrutas grąžina null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Atliekant tarpinių serverių būklės patikrą leisti paskirties vietos atmestam patikrinimui (401/403/429: tarpinis serveris persiuntė užklausą, o paskirties vieta atmetė šį išeinantį IP adresą) iš naujo nustatyti tarpinio serverio nuoseklių nesėkmių seką, kaip ir aptarnauto patikrinimo atveju. Pagal numatytąsias nuostatas išjungta: atmetimas lieka neutralus ir išsaugo seką. 5xx atsakymas abiem atvejais lieka neapibrėžtas, o atmetimas niekada nepašalina, neišjungia ir iš naujo nesuaktyvina tarpinio serverio.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Leisti automatiniam valymui pašalinti galutines būsenas pasiekusias (užbaigtas / nepavykusias / atšauktas / nebegaliojančias) Batch API užduotis, senesnes nei OMNIROUTE_BATCH_RETENTION_DAYS, kartu su kiekvienos jų eilutės kontroliniais taškais ir išvalyti įkeltų failų, kurių expires_at jau praėjo, BLOB turinį. Pagal numatytąsias nuostatas išjungta: visuose esamuose diegimuose šie duomenys išsaugomi lygiai taip pat kaip anksčiau, kol operatorius šios funkcijos neįjungia. Operatoriaus iškviečiamam maršrutui DELETE /api/v1/batches/delete-completed ši nuostata jokios įtakos neturi – tai atskira, besąlyginė viešosios API sutartis.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Yra atnaujinimas: v{current} → v{latest}", "cliproxyapiVersion": "Versija" }, + "modelCatalog": { + "title": "Modeliai ir deriniai", + "subtitle": "Naršykite ir tikrinkite modelių bei derinių maršrutizavimo kanalus visuose teikėjuose.", + "refresh": "Atnaujinti", + "modelsTab": "Modeliai", + "combosTab": "Deriniai", + "catalogSections": "Katalogo skiltys", + "loading": "Įkeliama...", + "retry": "Bandyti dar kartą", + "unableToLoad": "Nepavyko įkelti modelių katalogo.", + "unableToLoadCombos": "Nepavyko įkelti derinių.", + "checkConnection": "Patikrinkite ryšį ir bandykite dar kartą.", + "noModelsAvailable": "Modelių dar nėra.", + "noModelsMatch": "Nėra filtrus atitinkančių modelių.", + "noCombosAvailable": "Derinių dar nėra.", + "noCombosMatch": "Nėra filtrus atitinkančių derinių.", + "clearFilters": "Išvalyti filtrus", + "searchModels": "Ieškoti modelių", + "searchModelsPlaceholder": "Ieškokite pagal modelį, teikėją ar galimybę", + "searchCombos": "Ieškoti derinių", + "searchCombosPlaceholder": "Ieškokite pagal derinio pavadinimą, modelius ar aprašą", + "modelCountSingle": "modelis", + "modelCountPlural": "modeliai", + "comboCountSingle": "derinys", + "comboCountPlural": "deriniai", + "provider": "Teikėjas", + "allProviders": "Visi teikėjai", + "type": "Tipas", + "allTypes": "Visi tipai", + "subtype": "Potipis", + "allSubtypes": "Visi potipiai", + "capability": "Galimybė", + "allCapabilities": "Visos galimybės", + "pricing": "Kainodara", + "allPricing": "Visa kainodara", + "freeOnly": "Tik nemokami", + "nonFree": "Standartiniai / Mokami", + "providerHealth": "Teikėjo būsena", + "allHealthStates": "Visos būsenos", + "healthy": "Tvarkinga", + "degraded": "Pablogėjusi", + "down": "Neveikia", + "testResult": "Testo rezultatas", + "allResults": "Visi rezultatai", + "untested": "Netestuota", + "statusOk": "Gerai", + "statusSlow": "Lėta", + "statusError": "Klaida", + "minContext": "Min. kontekstas", + "minContextPlaceholder": "pvz., 32000", + "strategy": "Strategija", + "allStrategies": "Visos strategijos", + "status": "Būsena", + "allStatuses": "Visos būsenos", + "active": "Aktyvus", + "paused": "Pristabdytas", + "minMembers": "Min. narių skaičius", + "minMembersPlaceholder": "pvz., 1", + "maxMembers": "Maks. narių skaičius", + "maxMembersPlaceholder": "pvz., 10", + "testSelected": "Testuoti pasirinktus ({count})", + "testAllFiltered": "Testuoti visus atfiltruotus ({count})", + "cancel": "Atšaukti", + "clearResults": "Išvalyti rezultatus", + "testing": "Testuojama...", + "rateLimited": "Viršytas užklausų limitas", + "quotaExceeded": "Viršyta kvota", + "timeout": "Baigėsi laikas", + "otherError": "Klaida", + "justNow": "Ką tik", + "minutesAgo": "prieš {count} min.", + "hoursAgo": "prieš {count} val.", + "tableRegion": "Modelių katalogo lentelė", + "combosTableRegion": "Kombinacijų katalogo lentelė", + "tableCaption": "Visų teikėjų modelių katalogas", + "combosTableCaption": "Kombinacijų katalogas su būklės testų rezultatais", + "selectAllModels": "Pasirinkti visus modelius šiame puslapyje", + "selectAllCombos": "Pasirinkti visas kombinacijas šiame puslapyje", + "selectModel": "Pasirinkti modelį {name}", + "selectCombo": "Pasirinkti kombinaciją {name}", + "model": "Modelis", + "capabilities": "Galimybės", + "context": "Kontekstas", + "output": "Maks. išvestis", + "flags": "Požymiai", + "healthTest": "Būsenos patikra", + "actions": "Veiksmai", + "test": "Testuoti", + "custom": "Tinkintas", + "free": "Nemokamas", + "noFlags": "Nepateikta kainos ar šaltinio požymių", + "noCapabilities": "Nepateikta galimybių metaduomenų", + "showingModels": "Rodoma {first}–{last} iš {total} modelių", + "showingCombos": "Rodoma {first}–{last} iš {total} kombinacijų", + "refreshing": "Atnaujinama…", + "refreshFailed": "Atnaujinti nepavyko. Rodomas paskutinis įkeltas katalogas.", + "page": "{page} puslapis iš {pageCount}", + "previous": "Ankstesnis", + "next": "Kitas", + "combo": "Kombinacija", + "members": "Nariai", + "moreMembers": "+dar {count}" + }, "combos": { "title": "Kombinacijos", "description": "Kurkite modelių kombinacijas su svertiniu maršrutizavimu ir perėjimo prie atsarginio modelio palaikymu", diff --git a/src/i18n/messages/lv.json b/src/i18n/messages/lv.json index 808daec18abc..678c77f63bea 100644 --- a/src/i18n/messages/lv.json +++ b/src/i18n/messages/lv.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Iespējot katra nomnieka adaptīvas virtuālās uzņemšanas joslas nodrošinātāju izsūtīšanai (#9654): viena nomnieka slodzes lēciens vairs neizraisa 503 kļūdu citam. OMNIROUTE_CHAT_VIRTUAL_LANES vides mainīgais ir prioritārāks par šo paneļa iestatījumu; izmaiņas stājas spēkā pēc servera pārstartēšanas.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Pakalpojumu sniedzēju lapas informācijas panelī: rādīt emblēmu “Bezmaksas” tikai tad, ja to apliecina pakalpojumu sniedzēja atbalstītie signāli — netiek izmantota parādāmā nosaukuma heiristika, lauki par bezmaksas pieejamību, kuru vērtības nav Būla vērtības, un reģistrētu pakalpojumu sniedzēju sufiksi :free, ja tiem nav dokumentēta bezmaksas līmeņa. Izslēdzot šo opciju, tiek saglabāts iepriekšējais emblēmas rādīšanas noteikums.", "featureFlagProxySkipRecentlyFailedDescription": "Starpniekserveru pūli un opencode konta līmeņa rotācija uz katru procesu uz noteiktu laiku pārtrauc atkārtoti izmantot starpniekserveri, kas tikko cieta kļūmi (noraidīta TCP pārbaude vai caur to saņemts 429); šis laiks pēc katras atkārtotas kļūmes dubultojas līdz noteiktajam maksimumam. Starpniekservera statuss netiek ierakstīts; ja visi kandidāti ir atlikti malā, izvēle paliek nemainīga. Pēc noklusējuma ieslēgts; `false` atjauno parasto atlasi.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Pakalpojumu sniedzējiem, kuru kvota tiek grupēta pēc izejošās adreses, ierindot pūla dalībnieku, kuram ir tāda pati novērotā izejošā adrese kā nesen noraidītajam dalībniekam, tieši aiz veselajiem dalībniekiem. Tikai secība, nekad netiek izslēgts. Nepieciešams PROXY_SKIP_RECENTLY_FAILED, kas ģenerē noraidījuma signālu, ko tas nolasa. Pēc noklusējuma izslēgts: atlases secība precīzi atbilst parastajai rotācijai.", "featureFlagProxyPoolEgressObservationDescription": "Informācijas panelī zem starpniekserveru pūla rādīt, cik novēroto izejošo IP adrešu pēdējo 24 h laikā apkalpoja tā dalībniekus, cik savienojumu tās izmantoja un kāds bija lielākais aiz vienas IP adreses novērotais savienojumu skaits. Tikai lasāms, aprēķināts no starpniekserveru žurnāla un nekad netiek izmantots maršrutēšanai. Pēc noklusējuma izslēgts: pūla redaktors paliek nemainīgs, un novērojumu maršruts atgriež null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Starpniekserveru darbspējas pārbaudē ļaut mērķa noraidītai pārbaudei (401/403/429: starpniekserveris pārsūtīja pieprasījumu, bet galamērķis noraidīja šo izejošo IP adresi) atiestatīt starpniekservera secīgo kļūmju sēriju tāpat kā apkalpotai pārbaudei. Pēc noklusējuma izslēgts: noraidījums paliek neitrāls un saglabā kļūmju sēriju. 5xx jebkurā gadījumā paliek nepārliecinošs, un noraidījums nekad neizraisa starpniekservera noņemšanu, atspējošanu vai atkārtotu aktivizēšanu.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ļaut automātiskajai tīrīšanai dzēst pabeigtus, neizdevušos, atceltus vai beigušos Batch API uzdevumus, kas ir vecāki par OMNIROUTE_BATCH_RETENTION_DAYS, kopā ar to kontrolpunktiem katrai rindai, kā arī notīrīt BLOB saturu augšupielādētajiem failiem, kuru pašu expires_at termiņš ir beidzies. Pēc noklusējuma izslēgts: katra esošā instalācija turpina glabāt šos datus tieši tāpat kā iepriekš, līdz operators izvēlas šo funkciju ieslēgt. Operatora aktivizētais maršruts DELETE /api/v1/batches/delete-completed abos gadījumos netiek ietekmēts — tas ir atsevišķs, beznosacījumu publiskās API līgums.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Pieejams atjauninājums: v{current} → v{latest}", "cliproxyapiVersion": "Versija" }, + "modelCatalog": { + "title": "Modeļi un kombinācijas", + "subtitle": "Pārlūkojiet un pārbaudiet modeļu un kombināciju maršrutēšanas konveijeru darbspēju visiem pakalpojumu sniedzējiem.", + "refresh": "Atsvaidzināt", + "modelsTab": "Modeļi", + "combosTab": "Kombinācijas", + "catalogSections": "Kataloga sadaļas", + "loading": "Ielādē...", + "retry": "Mēģināt vēlreiz", + "unableToLoad": "Neizdevās ielādēt modeļu katalogu.", + "unableToLoadCombos": "Neizdevās ielādēt kombinācijas.", + "checkConnection": "Pārbaudiet savienojumu un mēģiniet vēlreiz.", + "noModelsAvailable": "Pagaidām nav pieejams neviens modelis.", + "noModelsMatch": "Neviens modelis neatbilst šiem filtriem.", + "noCombosAvailable": "Pagaidām nav pieejama neviena kombinācija.", + "noCombosMatch": "Neviena kombinācija neatbilst šiem filtriem.", + "clearFilters": "Notīrīt filtrus", + "searchModels": "Meklēt modeļus", + "searchModelsPlaceholder": "Meklēt pēc modeļa, pakalpojumu sniedzēja vai iespējas", + "searchCombos": "Meklēt kombinācijas", + "searchCombosPlaceholder": "Meklēt pēc kombinācijas nosaukuma, modeļiem vai apraksta", + "modelCountSingle": "modelis", + "modelCountPlural": "modeļi", + "comboCountSingle": "kombinācija", + "comboCountPlural": "kombinācijas", + "provider": "Pakalpojumu sniedzējs", + "allProviders": "Visi pakalpojumu sniedzēji", + "type": "Veids", + "allTypes": "Visi veidi", + "subtype": "Apakšveids", + "allSubtypes": "Visi apakšveidi", + "capability": "Iespēja", + "allCapabilities": "Visas iespējas", + "pricing": "Cenas", + "allPricing": "Visas cenas", + "freeOnly": "Tikai bezmaksas", + "nonFree": "Standarta / maksas", + "providerHealth": "Pakalpojumu sniedzēja darbspēja", + "allHealthStates": "Visi darbspējas stāvokļi", + "healthy": "Veselīgs", + "degraded": "Pasliktināts", + "down": "Nedarbojas", + "testResult": "Testa rezultāts", + "allResults": "Visi rezultāti", + "untested": "Netestēts", + "statusOk": "OK", + "statusSlow": "Lēns", + "statusError": "Kļūda", + "minContext": "Min. konteksts", + "minContextPlaceholder": "piem., 32000", + "strategy": "Stratēģija", + "allStrategies": "Visas stratēģijas", + "status": "Statuss", + "allStatuses": "Visi statusi", + "active": "Aktīvs", + "paused": "Pauzēts", + "minMembers": "Min. dalībnieki", + "minMembersPlaceholder": "piem., 1", + "maxMembers": "Maks. dalībnieki", + "maxMembersPlaceholder": "piem., 10", + "testSelected": "Testēt atlasītos ({count})", + "testAllFiltered": "Testēt visus filtrētos ({count})", + "cancel": "Atcelt", + "clearResults": "Notīrīt rezultātus", + "testing": "Testē...", + "rateLimited": "Pārsniegts pieprasījumu limits", + "quotaExceeded": "Kvota pārsniegta", + "timeout": "Noildze", + "otherError": "Kļūda", + "justNow": "Tikko", + "minutesAgo": "Pirms {count}m", + "hoursAgo": "Pirms {count}h", + "tableRegion": "Modeļu kataloga tabula", + "combosTableRegion": "Kombināciju kataloga tabula", + "tableCaption": "Modeļu katalogs no visiem pakalpojumu sniedzējiem", + "combosTableCaption": "Kombināciju katalogs ar darbspējas testa rezultātiem", + "selectAllModels": "Atlasīt visus modeļus šajā lapā", + "selectAllCombos": "Atlasīt visas kombinācijas šajā lapā", + "selectModel": "Atlasīt modeli {name}", + "selectCombo": "Atlasīt kombināciju {name}", + "model": "Modelis", + "capabilities": "Iespējas", + "context": "Konteksts", + "output": "Maksimālā izvade", + "flags": "Karodziņi", + "healthTest": "Darbspējas pārbaude", + "actions": "Darbības", + "test": "Testēt", + "custom": "Pielāgots", + "free": "Bezmaksas", + "noFlags": "Nav ziņots par cenu vai avota karodziņu", + "noCapabilities": "Nav ziņots par iespēju metadatiem", + "showingModels": "Rāda {first}–{last} no {total} modeļiem", + "showingCombos": "Rāda {first}–{last} no {total} kombinācijām", + "refreshing": "Atsvaidzina…", + "refreshFailed": "Atsvaidzināšana neizdevās. Tiek rādīts pēdējais ielādētais katalogs.", + "page": "Lapa {page} no {pageCount}", + "previous": "Iepriekšējā", + "next": "Nākamā", + "combo": "Kombinācija", + "members": "Dalībnieki", + "moreMembers": "+vēl {count}" + }, "combos": { "title": "Kombinācijas", "description": "Izveidojiet modeļu kombinācijas ar svērtu maršrutēšanu un rezerves variantu atbalstu", diff --git a/src/i18n/messages/ml.json b/src/i18n/messages/ml.json index 8209d02e6786..b6cb335739d5 100644 --- a/src/i18n/messages/ml.json +++ b/src/i18n/messages/ml.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "പ്രൊവൈഡർ ഡിസ്പാച്ചിനായി ഓരോ ടെനന്റിനും അനുയോജ്യമായി മാറുന്ന വെർച്വൽ അഡ്മിഷൻ ലെയിനുകൾ പ്രവർത്തനക്ഷമമാക്കുക (#9654): ഇനി ഒരു ടെനന്റിന്റെ പെട്ടെന്നുള്ള അഭ്യർത്ഥന വർധന മറ്റൊരാൾക്ക് 503 പിശക് സൃഷ്ടിക്കില്ല. ഈ ഡാഷ്ബോർഡ് ഓവർറൈഡിനേക്കാൾ OMNIROUTE_CHAT_VIRTUAL_LANES env var-ന് മുൻഗണനയുണ്ട്; സെർവർ പുനരാരംഭിക്കുമ്പോൾ മാറ്റങ്ങൾ പ്രാബല്യത്തിൽ വരും.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ഡാഷ്ബോർഡ് പ്രൊവൈഡർ പേജുകൾ: പ്രൊവൈഡർ അംഗീകരിക്കുന്ന സൂചനകളിൽ മാത്രം Free ബാഡ്ജ് കാണിക്കുക — രേഖപ്പെടുത്തിയ സൗജന്യ ടയർ ഇല്ലാത്ത രജിസ്റ്റർ ചെയ്ത പ്രൊവൈഡറുകളിൽ ഡിസ്പ്ലേ-നെയിം ഹ്യൂറിസ്റ്റിക്, ബൂളിയൻ അല്ലാത്ത free ഫീൽഡുകൾ, :free സഫിക്സുകൾ എന്നിവ ഒഴിവാക്കുന്നു. ഓഫാക്കിയാൽ പഴയ ബാഡ്ജ് നിയമം നിലനിർത്തും.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy പൂളുകളും opencode-ന്റെ ഓരോ അക്കൗണ്ടിലുമുള്ള റൊട്ടേഷനും, ഇപ്പോൾ പരാജയപ്പെട്ട ഒരു Proxy-യെ (നിരസിക്കപ്പെട്ട TCP പ്രോബ്, അല്ലെങ്കിൽ അതിലൂടെ ലഭിച്ച 429) ഓരോ ആവർത്തനത്തിലും ഇരട്ടിയാകുന്ന, ഒരു പരമാവധി പരിധിവരെയുള്ള ഓരോ പ്രോസസിനുമുള്ള കാലയളവിൽ വീണ്ടും ഉപയോഗിക്കുന്നത് നിർത്തുന്നു. Proxy നിലയൊന്നും രേഖപ്പെടുത്തില്ല; എല്ലാ സ്ഥാനാർഥികളെയും മാറ്റിവെച്ചാൽ തിരഞ്ഞെടുപ്പ് മാറ്റമില്ലാതെ തുടരും. ഡിഫോൾട്ടായി ഓണാണ്; `false` സാധാരണ തിരഞ്ഞെടുപ്പ് പുനഃസ്ഥാപിക്കുന്നു.", - "featureFlagProxyPoolSharedEgressOrderDescription": "egress address അനുസരിച്ച് ക്വാട്ട നിശ്ചയിച്ചിട്ടുള്ള പ്രൊവൈഡർമാർക്കായി, അടുത്തിടെ നിരസിക്കപ്പെട്ട ഒരു അംഗത്തിന്റെ egress address പങ്കിടുന്ന പൂൾ അംഗത്തെ ഹെൽത്തി ആയ അംഗങ്ങൾക്ക് തൊട്ടുതാഴെയായി റാങ്ക് ചെയ്യുക. ക്രമത്തിൽ മാറ്റം വരുത്താൻ മാത്രം, ഒരിക്കലും ഒഴിവാക്കപ്പെടില്ല. ഇത് വായിക്കുന്ന നിരസിക്കൽ സിഗ്നൽ നൽകുന്ന PROXY_SKIP_RECENTLY_FAILED ഇതിന് ആവശ്യമാണ്. ഡിഫോൾട്ടായി ഓഫാണ്: തിരഞ്ഞെടുക്കൽ ക്രമം കൃത്യമായി സാധാരണ റൊട്ടേഷൻ തന്നെയായിരിക്കും.", "featureFlagProxyPoolEgressObservationDescription": "ഡാഷ്ബോർഡിലെ ഒരു Proxy പൂളിന് കീഴിൽ, കഴിഞ്ഞ 24 മണിക്കൂറിനിടെ അതിലെ അംഗങ്ങൾക്ക് സേവനം നൽകിയതായി നിരീക്ഷിച്ച എത്ര എഗ്രസ് IP-കൾ ഉണ്ടായിരുന്നു, എത്ര കണക്ഷനുകൾ അവ ഉപയോഗിച്ചു, ഒരു IP-ക്ക് പിന്നിൽ കണ്ട ഏറ്റവും ഉയർന്ന എണ്ണം എത്ര എന്നിവ കാണിക്കുക. വായനയ്ക്ക് മാത്രം; Proxy ലോഗിൽനിന്ന് കണക്കാക്കുന്നതും റൂട്ടിംഗിനായി ഒരിക്കലും ഉപയോഗിക്കാത്തതുമാണ്. ഡിഫോൾട്ടായി ഓഫാണ്: പൂൾ എഡിറ്ററിൽ മാറ്റമില്ല, നിരീക്ഷണ റൂട്ട് null എന്ന് മറുപടി നൽകും.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ആരോഗ്യ പരിശോധനയിൽ, ലക്ഷ്യം നിരസിച്ച ഒരു പ്രോബ് (401/403/429: Proxy റിലേ ചെയ്തു, ലക്ഷ്യസ്ഥാനം ഈ എഗ്രസ് IP നിരസിച്ചു) സേവനം നൽകിയ പ്രോബിനെപ്പോലെ Proxy-യുടെ തുടർച്ചയായ പരാജയങ്ങളുടെ എണ്ണം പുനഃസജ്ജമാക്കാൻ അനുവദിക്കുക. ഡിഫോൾട്ടായി ഓഫാണ്: ഒരു നിരസിക്കൽ നിഷ്പക്ഷമായി തുടരുകയും പരാജയങ്ങളുടെ എണ്ണം നിലനിർത്തുകയും ചെയ്യും. ഏതുവിധമായാലും 5xx അനിശ്ചിതമായി തുടരും; ഒരു നിരസിക്കൽ ഒരിക്കലും Proxy-യെ നീക്കം ചെയ്യുകയോ പ്രവർത്തനരഹിതമാക്കുകയോ വീണ്ടും സജീവമാക്കുകയോ ചെയ്യില്ല.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS-നേക്കാൾ പഴക്കമുള്ള ടെർമിനൽ (പൂർത്തിയായ/പരാജയപ്പെട്ട/റദ്ദാക്കിയ/കാലഹരണപ്പെട്ട) Batch API ജോലികളും അവയുടെ ഓരോ വരിയിലുമുള്ള ചെക്ക്പോയിന്റുകളും സ്വയമേവയുള്ള ക്ലീനപ്പ് സ്വീപ്പിലൂടെ ഇല്ലാതാക്കാനും, സ്വന്തം expires_at കഴിഞ്ഞ അപ്ലോഡ് ചെയ്ത ഫയലുകളുടെ BLOB ഉള്ളടക്കം മായ്ക്കാനും അനുവദിക്കുക. ഡിഫോൾട്ടായി ഓഫാണ്: ഒരു ഓപ്പറേറ്റർ ഇത് പ്രവർത്തനക്ഷമമാക്കുന്നതുവരെ നിലവിലുള്ള എല്ലാ ഇൻസ്റ്റാളേഷനുകളും ഈ ഡാറ്റ മുമ്പത്തേതുപോലെ തന്നെ നിലനിർത്തും. ഓപ്പറേറ്റർ ട്രിഗർ ചെയ്യുന്ന DELETE /api/v1/batches/delete-completed റൂട്ടിനെ ഇത് ഒരു തരത്തിലും ബാധിക്കില്ല — അത് വേറിട്ടതും നിബന്ധനകളില്ലാത്തതുമായ ഒരു പൊതു API കരാറാണ്.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "അപ്ഡേറ്റ് ലഭ്യമാണ്: v{current} → v{latest}", "cliproxyapiVersion": "പതിപ്പ്" }, + "modelCatalog": { + "title": "മോഡലുകളും കോംബോകളും", + "subtitle": "എല്ലാ പ്രൊവൈഡറുകളിലുമുള്ള മോഡലുകളും കോംബോ റൂട്ടിംഗ് പൈപ്പ്‌ലൈനുകളും ബ്രൗസ് ചെയ്യുകയും ഹെൽത്ത് ടെസ്റ്റ് നടത്തുകയും ചെയ്യുക.", + "refresh": "പുതുക്കുക", + "modelsTab": "മോഡലുകൾ", + "combosTab": "കോംബോകൾ", + "catalogSections": "കാറ്റലോഗ് വിഭാഗങ്ങൾ", + "loading": "ലോഡുചെയ്യുന്നു...", + "retry": "വീണ്ടും ശ്രമിക്കുക", + "unableToLoad": "മോഡൽ കാറ്റലോഗ് ലോഡ് ചെയ്യാൻ കഴിഞ്ഞില്ല.", + "unableToLoadCombos": "കോംബോകൾ ലോഡ് ചെയ്യാൻ കഴിഞ്ഞില്ല.", + "checkConnection": "കണക്ഷൻ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക.", + "noModelsAvailable": "മോഡലുകളൊന്നും ഇതുവരെ ലഭ്യമല്ല.", + "noModelsMatch": "ഈ ഫിൽട്ടറുകളുമായി പൊരുത്തപ്പെടുന്ന മോഡലുകളൊന്നുമില്ല.", + "noCombosAvailable": "കോംബോകളൊന്നും ഇതുവരെ ലഭ്യമല്ല.", + "noCombosMatch": "ഈ ഫിൽട്ടറുകളുമായി പൊരുത്തപ്പെടുന്ന കോംബോകളൊന്നുമില്ല.", + "clearFilters": "ഫിൽട്ടറുകൾ മായ്‌ക്കുക", + "searchModels": "മോഡലുകൾ തിരയുക", + "searchModelsPlaceholder": "മോഡൽ, പ്രൊവൈഡർ, അല്ലെങ്കിൽ ശേഷി എന്നിവ പ്രകാരം തിരയുക", + "searchCombos": "കോംബോകൾ തിരയുക", + "searchCombosPlaceholder": "കോംബോയുടെ പേര്, മോഡലുകൾ, അല്ലെങ്കിൽ വിവരണം എന്നിവ പ്രകാരം തിരയുക", + "modelCountSingle": "മോഡൽ", + "modelCountPlural": "മോഡലുകൾ", + "comboCountSingle": "കോംബോ", + "comboCountPlural": "കോംബോകൾ", + "provider": "പ്രൊവൈഡർ", + "allProviders": "എല്ലാ പ്രൊവൈഡർമാരും", + "type": "തരം", + "allTypes": "എല്ലാ തരങ്ങളും", + "subtype": "സബ്‌ടൈപ്പ്", + "allSubtypes": "എല്ലാ സബ്‌ടൈപ്പുകളും", + "capability": "ശേഷി", + "allCapabilities": "എല്ലാ ശേഷികളും", + "pricing": "വിലവിവരം", + "allPricing": "എല്ലാ വിലവിവരങ്ങളും", + "freeOnly": "സൗജന്യമായവ മാത്രം", + "nonFree": "സ്റ്റാൻഡേർഡ് / സൗജന്യമല്ലാത്തവ", + "providerHealth": "പ്രൊവൈഡർ ഹെൽത്ത്", + "allHealthStates": "എല്ലാ ഹെൽത്ത് അവസ്ഥകളും", + "healthy": "ഹെൽത്തി", + "degraded": "ഡീഗ്രേഡഡ്", + "down": "പ്രവർത്തനരഹിതം", + "testResult": "ടെസ്റ്റ് ഫലം", + "allResults": "എല്ലാ ഫലങ്ങളും", + "untested": "ടെസ്റ്റ് ചെയ്യാത്തവ", + "statusOk": "ശരി", + "statusSlow": "വേഗത കുറവ്", + "statusError": "പിശക്", + "minContext": "കുറഞ്ഞ കോൺടെക്സ്റ്റ്", + "minContextPlaceholder": "ഉദാ. 32000", + "strategy": "സ്ട്രാറ്റജി", + "allStrategies": "എല്ലാ സ്ട്രാറ്റജികളും", + "status": "സ്റ്റാറ്റസ്", + "allStatuses": "എല്ലാ സ്റ്റാറ്റസുകളും", + "active": "സജീവം", + "paused": "പോസ് ചെയ്തത്", + "minMembers": "കുറഞ്ഞ അംഗങ്ങൾ", + "minMembersPlaceholder": "ഉദാ. 1", + "maxMembers": "പരമാവധി അംഗങ്ങൾ", + "maxMembersPlaceholder": "ഉദാ. 10", + "testSelected": "തിരഞ്ഞെടുത്തവ ടെസ്റ്റ് ചെയ്യുക ({count})", + "testAllFiltered": "ഫിൽട്ടർ ചെയ്ത എല്ലാം ടെസ്റ്റ് ചെയ്യുക ({count})", + "cancel": "റദ്ദാക്കുക", + "clearResults": "ഫലങ്ങൾ മായ്‌ക്കുക", + "testing": "ടെസ്റ്റ് ചെയ്യുന്നു...", + "rateLimited": "റേറ്റ് പരിധി കവിഞ്ഞു", + "quotaExceeded": "ക്വാട്ട കവിഞ്ഞു", + "timeout": "സമയം കഴിഞ്ഞു", + "otherError": "പിശക്", + "justNow": "ഇപ്പോൾ തന്നെ", + "minutesAgo": "{count} മിനിറ്റ് മുൻപ്", + "hoursAgo": "{count} മണിക്കൂർ മുൻപ്", + "tableRegion": "മോഡൽ കാറ്റലോഗ് പട്ടിക", + "combosTableRegion": "കോംബോ കാറ്റലോഗ് പട്ടിക", + "tableCaption": "എല്ലാ പ്രൊവൈഡറുകളിലുമുള്ള മോഡൽ കാറ്റലോഗ്", + "combosTableCaption": "ഹെൽത്ത് ടെസ്റ്റ് ഫലങ്ങളുള്ള കോംബോ കാറ്റലോഗ്", + "selectAllModels": "ഈ പേജിലെ എല്ലാ മോഡലുകളും തിരഞ്ഞെടുക്കുക", + "selectAllCombos": "ഈ പേജിലെ എല്ലാ കോംബോകളും തിരഞ്ഞെടുക്കുക", + "selectModel": "മോഡൽ {name} തിരഞ്ഞെടുക്കുക", + "selectCombo": "കോംബോ {name} തിരഞ്ഞെടുക്കുക", + "model": "മോഡൽ", + "capabilities": "ശേഷികൾ", + "context": "സന്ദർഭം", + "output": "പരമാവധി ഔട്ട്പുട്ട്", + "flags": "ഫ്ലാഗുകൾ", + "healthTest": "ഹെൽത്ത് ടെസ്റ്റ്", + "actions": "പ്രവർത്തനങ്ങൾ", + "test": "ടെസ്റ്റ്", + "custom": "കസ്റ്റം", + "free": "സൗജന്യം", + "noFlags": "വിലയോ സോഴ്സ് ഫ്ലാഗോ റിപ്പോർട്ട് ചെയ്തിട്ടില്ല", + "noCapabilities": "ശേഷി മെറ്റാഡാറ്റയൊന്നും റിപ്പോർട്ട് ചെയ്തിട്ടില്ല", + "showingModels": "{total} മോഡലുകളിൽ {first}–{last} കാണിക്കുന്നു", + "showingCombos": "{total} കോമ്പോകളിൽ {first}–{last} കാണിക്കുന്നു", + "refreshing": "പുതുക്കുന്നു…", + "refreshFailed": "പുതുക്കൽ പരാജയപ്പെട്ടു. അവസാനം ലോഡ് ചെയ്ത കാറ്റലോഗ് കാണിക്കുന്നു.", + "page": "{pageCount}-ൽ പേജ് {page}", + "previous": "മുമ്പത്തേത്", + "next": "അടുത്തത്", + "combo": "കോമ്പോ", + "members": "അംഗങ്ങൾ", + "moreMembers": "+{count} കൂടി" + }, "combos": { "title": "കോംബോകൾ", "description": "വെയ്റ്റഡ് റൂട്ടിംഗും ഫാൾബാക്ക് പിന്തുണയും ഉപയോഗിച്ച് മോഡൽ കോംബോകൾ സൃഷ്ടിക്കുക", diff --git a/src/i18n/messages/mr.json b/src/i18n/messages/mr.json index 98fa7a5ebd75..7e5e88bebbb1 100644 --- a/src/i18n/messages/mr.json +++ b/src/i18n/messages/mr.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदाता डिस्पॅचसाठी प्रति-टेनंट अनुकूली व्हर्च्युअल अॅडमिशन लेन सक्षम करा (#9654): एका टेनंटचा बर्स्ट यापुढे दुसऱ्या टेनंटला 503 देत नाही. OMNIROUTE_CHAT_VIRTUAL_LANES पर्यावरण चल या डॅशबोर्ड सेटिंगपेक्षा वरचढ आहे; बदल सर्व्हर रीस्टार्ट केल्यावर प्रभावी होतात.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "डॅशबोर्डवरील प्रदाता पृष्ठे: प्रदाता मान्य करतो अशाच संकेतांवर मोफत बॅज दाखवा — दस्तऐवजीकृत मोफत स्तर नसलेल्या नोंदणीकृत प्रदात्यांसाठी प्रदर्शन-नाव अनुमान, नॉन-बूलियन मोफत फील्ड आणि :free प्रत्यय वगळले जातात. बंद केल्यास ऐतिहासिक बॅज नियम कायम राहतो.", "featureFlagProxySkipRecentlyFailedDescription": "प्रॉक्सी पूल आणि opencode चे प्रति-खाते रोटेशन नुकताच अयशस्वी झालेला प्रॉक्सी (TCP प्रोब नाकारला गेला किंवा त्याद्वारे 429 प्राप्त झाला) प्रत्येक प्रक्रियेसाठी ठरावीक कालावधीपर्यंत पुन्हा वापरत नाहीत; प्रत्येक पुनरावृत्तीनंतर हा कालावधी दुप्पट होतो, कमाल मर्यादेपर्यंत. प्रॉक्सीची कोणतीही स्थिती लिहिली जात नाही; प्रत्येक उमेदवार बाजूला ठेवल्यास निवड अपरिवर्तित राहते. डीफॉल्टनुसार चालू; `false` साधी निवड पुनर्संचयित करते.", - "featureFlagProxyPoolSharedEgressOrderDescription": "ज्या प्रदात्यांसाठी कोटा egress पत्त्यानुसार विभागला गेला आहे, त्यांच्यासाठी नुकत्याच नाकारलेल्या सदस्याचा नोंदवलेला egress पत्ता शेअर करणाऱ्या पूल सदस्याला निरोगी सदस्यांच्या अगदी खाली क्रमवारी द्या. केवळ क्रमवारी, कधीही वगळले जात नाही. यासाठी PROXY_SKIP_RECENTLY_FAILED आवश्यक आहे, जे ते वाचत असलेला नकार सिग्नल तयार करते. बाय डीफॉल्ट बंद: निवड क्रम अगदी सामान्य रोटेशनप्रमाणे असतो.", "featureFlagProxyPoolEgressObservationDescription": "डॅशबोर्डमध्ये प्रॉक्सी पूलखाली, मागील 24 तासांत त्याच्या सदस्यांना सेवा देणारे किती निरीक्षित इग्रेस IP होते, किती कनेक्शन्सनी त्यांचा वापर केला आणि एका IP मागून सर्वाधिक किती कनेक्शन्स दिसली हे दाखवा. हे केवळ-वाचनीय असून प्रॉक्सी लॉगवरून मोजले जाते आणि रूटिंगसाठी कधीही वापरले जात नाही. डीफॉल्टनुसार बंद: पूल एडिटर अपरिवर्तित राहतो आणि निरीक्षण रूट null असे उत्तर देतो.", "featureFlagProxyHealthBlockedResetsStreakDescription": "प्रॉक्सी आरोग्य तपासणीमध्ये, लक्ष्याने नाकारलेल्या प्रोबला (401/403/429: प्रॉक्सीने पुढे पाठवले, पण गंतव्याने हा इग्रेस IP नाकारला) सेवा दिलेल्या प्रोबप्रमाणे प्रॉक्सीच्या सलग अपयशांची मालिका रीसेट करू द्या. डीफॉल्टनुसार बंद: नकार तटस्थ राहतो आणि मालिका कायम ठेवतो. 5xx दोन्ही बाबतींत अनिर्णीत राहतो आणि नकारामुळे प्रॉक्सी कधीही काढला, अक्षम किंवा पुन्हा सक्रिय केला जात नाही.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वयंचलित क्लीनअप स्वीपला OMNIROUTE_BATCH_RETENTION_DAYS पेक्षा जुनी टर्मिनल (पूर्ण/अयशस्वी/रद्द केलेली/कालबाह्य) Batch API कार्ये, त्यांच्या प्रत्येक ओळीच्या चेकपॉइंटसह हटवू द्या आणि स्वतःची expires_at वेळ उलटून गेलेल्या अपलोड केलेल्या फाइल्समधील BLOB सामग्री साफ करू द्या. डीफॉल्टनुसार बंद: ऑपरेटरने हे सुरू करेपर्यंत प्रत्येक विद्यमान इंस्टॉलेशन हा डेटा पूर्वीप्रमाणेच ठेवते. ऑपरेटरने ट्रिगर केलेला DELETE /api/v1/batches/delete-completed मार्ग कोणत्याही परिस्थितीत अप्रभावित राहतो — तो स्वतंत्र, बिनशर्त सार्वजनिक API करार आहे.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "उपलब्ध अद्यतन: v{current} → v{latest}", "cliproxyapiVersion": "आवृत्ती" }, + "modelCatalog": { + "title": "मॉडेल्स आणि कॉम्बोज", + "subtitle": "प्रत्येक प्रोव्हायडरमधील मॉडेल्स आणि कॉम्बो राउटिंग पाइपलाइन्स ब्राऊझ करा आणि त्यांची हेल्थ तपासा.", + "refresh": "रिफ्रेश करा", + "modelsTab": "मॉडेल्स", + "combosTab": "कॉम्बोज", + "catalogSections": "कॅटलॉग विभाग", + "loading": "लोड होत आहे...", + "retry": "पुन्हा प्रयत्न करा", + "unableToLoad": "मॉडेल कॅटलॉग लोड करण्यात अक्षम.", + "unableToLoadCombos": "कॉम्बोज लोड करण्यात अक्षम.", + "checkConnection": "कनेक्शन तपासा आणि पुन्हा प्रयत्न करा.", + "noModelsAvailable": "अद्याप कोणतीही मॉडेल्स उपलब्ध नाहीत.", + "noModelsMatch": "या फिल्टर्सशी जुळणारे कोणतेही मॉडेल्स नाहीत.", + "noCombosAvailable": "अद्याप कोणतेही कॉम्बोज उपलब्ध नाहीत.", + "noCombosMatch": "या फिल्टर्सशी जुळणारे कोणतेही कॉम्बोज नाहीत.", + "clearFilters": "फिल्टर्स साफ करा", + "searchModels": "मॉडेल्स शोधा", + "searchModelsPlaceholder": "मॉडेल, प्रोव्हायडर किंवा क्षमतेनुसार शोधा", + "searchCombos": "कॉम्बोज शोधा", + "searchCombosPlaceholder": "कॉम्बोचे नाव, मॉडेल्स किंवा वर्णनानुसार शोधा", + "modelCountSingle": "मॉडेल", + "modelCountPlural": "मॉडेल्स", + "comboCountSingle": "कॉम्बो", + "comboCountPlural": "कॉम्बोज", + "provider": "प्रोव्हायडर", + "allProviders": "सर्व प्रोव्हायडर्स", + "type": "प्रकार", + "allTypes": "सर्व प्रकार", + "subtype": "उपप्रकार", + "allSubtypes": "सर्व उपप्रकार", + "capability": "क्षमता", + "allCapabilities": "सर्व क्षमता", + "pricing": "किंमत", + "allPricing": "सर्व किमती", + "freeOnly": "फक्त मोफत", + "nonFree": "स्टँडर्ड / मोफत नसलेले", + "providerHealth": "प्रोव्हायडर हेल्थ", + "allHealthStates": "सर्व हेल्थ स्थिती", + "healthy": "हेल्दी", + "degraded": "डीग्रेडेड", + "down": "डाउन", + "testResult": "चाचणी निकाल", + "allResults": "सर्व निकाल", + "untested": "चाचणी न केलेले", + "statusOk": "ठीक आहे", + "statusSlow": "मंद", + "statusError": "त्रुटी", + "minContext": "किमान संदर्भ", + "minContextPlaceholder": "उदा. 32000", + "strategy": "धोरण", + "allStrategies": "सर्व धोरणे", + "status": "स्थिती", + "allStatuses": "सर्व स्थिती", + "active": "सक्रिय", + "paused": "थांबवले", + "minMembers": "किमान सदस्य", + "minMembersPlaceholder": "उदा. 1", + "maxMembers": "कमाल सदस्य", + "maxMembersPlaceholder": "उदा. 10", + "testSelected": "निवडलेल्यांची चाचणी घ्या ({count})", + "testAllFiltered": "फिल्टर केलेल्या सर्वांची चाचणी घ्या ({count})", + "cancel": "रद्द करा", + "clearResults": "निकाल साफ करा", + "testing": "चाचणी घेत आहे...", + "rateLimited": "रेट मर्यादित", + "quotaExceeded": "कोटा ओलांडला", + "timeout": "वेळ संपली", + "otherError": "त्रुटी", + "justNow": "आत्ताच", + "minutesAgo": "{count} मिनिटांपूर्वी", + "hoursAgo": "{count} तासांपूर्वी", + "tableRegion": "मॉडेल कॅटलॉग सारणी", + "combosTableRegion": "कॉम्बो कॅटलॉग सारणी", + "tableCaption": "सर्व प्रोव्हायडर्समधील मॉडेल कॅटलॉग", + "combosTableCaption": "आरोग्य चाचणी निकालांसह कॉम्बो कॅटलॉग", + "selectAllModels": "या पृष्ठावरील सर्व मॉडेल्स निवडा", + "selectAllCombos": "या पृष्ठावरील सर्व कॉम्बो निवडा", + "selectModel": "मॉडेल {name} निवडा", + "selectCombo": "कॉम्बो {name} निवडा", + "model": "मॉडेल", + "capabilities": "क्षमता", + "context": "संदर्भ", + "output": "कमाल आउटपुट", + "flags": "फ्लॅग्ज", + "healthTest": "आरोग्य चाचणी", + "actions": "कृती", + "test": "चाचणी", + "custom": "सानुकूल", + "free": "मोफत", + "noFlags": "कोणतीही किंमत किंवा स्रोत फ्लॅग नोंदवलेला नाही", + "noCapabilities": "कोणताही क्षमता मेटाडेटा नोंदवलेला नाही", + "showingModels": "{total} पैकी {first}–{last} मॉडेल्स दाखवत आहे", + "showingCombos": "{total} पैकी {first}–{last} कॉम्बो दाखवत आहे", + "refreshing": "रिफ्रेश करत आहे…", + "refreshFailed": "रिफ्रेश अयशस्वी झाले. शेवटचा लोड केलेला कॅटलॉग दाखवत आहे.", + "page": "{pageCount} पैकी पृष्ठ {page}", + "previous": "मागील", + "next": "पुढील", + "combo": "कॉम्बो", + "members": "सदस्य", + "moreMembers": "+{count} आणखी" + }, "combos": { "title": "कॉम्बोज", "description": "भारित रूटिंग आणि फॉलबॅक समर्थनासह मॉडेल कॉम्बोज तयार करा", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index c5c417f12b01..7d687c5be277 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktifkan lorong kemasukan maya adaptif setiap-tenant untuk penghantaran pembekal (#9654): lonjakan satu tenant tidak lagi memberikan 503 kepada tenant lain. Pemboleh ubah persekitaran OMNIROUTE_CHAT_VIRTUAL_LANES mengatasi tetapan papan pemuka ini; perubahan berkuat kuasa apabila pelayan dimulakan semula.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Halaman penyedia papan pemuka: tunjukkan lencana Percuma hanya pada isyarat yang disokong oleh penyedia — menggugurkan heuristik nama paparan, medan percuma bukan boolean dan akhiran :free pada penyedia berdaftar tanpa peringkat percuma yang didokumenkan. Mati mengekalkan peraturan lencana terdahulu.", "featureFlagProxySkipRecentlyFailedDescription": "Kumpulan proksi dan penggiliran opencode bagi setiap akaun akan berhenti menyediakan semula proksi yang baru sahaja gagal (probe TCP ditolak atau 429 diterima melaluinya) untuk tempoh bagi setiap proses yang berganda pada setiap kegagalan berulang, sehingga had maksimum. Tiada status proksi direkodkan; apabila setiap calon diketepikan, pilihan tidak berubah. Dihidupkan secara lalai; `false` memulihkan pemilihan biasa.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Untuk penyedia yang kuotanya dikelompokkan mengikut alamat egress, letakkan kedudukan ahli kolam yang berkongsi alamat egress diperhatikan bagi ahli yang baru ditolak tepat di bawah ahli yang sihat. Tertib sahaja, tidak pernah dikecualikan. Memerlukan PROXY_SKIP_RECENTLY_FAILED, yang menghasilkan isyarat penolakan yang dibacanya. Dimatikan secara lalai: susunan pemilihan adalah tepat mengikut putaran biasa.", "featureFlagProxyPoolEgressObservationDescription": "Tunjukkan, di bawah kumpulan proksi dalam papan pemuka, bilangan IP keluar yang diperhatikan telah digunakan oleh ahlinya sepanjang 24 jam yang lalu, bilangan sambungan yang menggunakannya dan bilangan terbanyak yang dilihat di sebalik satu IP. Baca sahaja, dikira daripada log proksi dan tidak pernah digunakan untuk penghalaan. Dimatikan secara lalai: editor kumpulan tidak berubah dan laluan pemerhatian memberikan null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Dalam imbasan kesihatan proksi, benarkan probe yang ditolak oleh sasaran (401/403/429: proksi telah menyampaikan permintaan, tetapi destinasi menolak IP keluar ini) menetapkan semula rentetan kegagalan berturut-turut proksi, seperti probe yang berjaya dilayan. Dimatikan secara lalai: penolakan kekal neutral dan mengekalkan rentetan tersebut. 5xx kekal tidak muktamad dalam kedua-dua keadaan dan penolakan tidak akan mengalih keluar, menyahdayakan atau mengaktifkan semula proksi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Benarkan proses pembersihan automatik memadam tugas API Batch berstatus terminal (completed/failed/cancelled/expired) yang lebih lama daripada OMNIROUTE_BATCH_RETENTION_DAYS, berserta titik semak setiap barisnya, dan mengosongkan kandungan BLOB bagi fail yang dimuat naik selepas expires_at masing-masing. Dimatikan secara lalai: setiap pemasangan sedia ada mengekalkan data ini tepat seperti sebelumnya sehingga pengendali memilih untuk mengaktifkannya. Laluan DELETE /api/v1/batches/delete-completed yang dicetuskan oleh pengendali tidak terjejas dalam mana-mana keadaan — laluan itu ialah kontrak API awam berasingan yang tidak bersyarat.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Kemas kini tersedia: v{current} → v{latest}", "cliproxyapiVersion": "Versi" }, + "modelCatalog": { + "title": "Model & Kombo", + "subtitle": "Semak imbas dan uji kesihatan model serta saluran paip penghalaan kombo merentasi setiap penyedia.", + "refresh": "Muat Semula", + "modelsTab": "Model", + "combosTab": "Kombo", + "catalogSections": "Bahagian Katalog", + "loading": "Memuatkan...", + "retry": "Cuba Semula", + "unableToLoad": "Tidak dapat memuatkan katalog model.", + "unableToLoadCombos": "Tidak dapat memuatkan kombo.", + "checkConnection": "Periksa sambungan dan cuba lagi.", + "noModelsAvailable": "Tiada model tersedia lagi.", + "noModelsMatch": "Tiada model yang sepadan dengan penapis ini.", + "noCombosAvailable": "Tiada kombo tersedia lagi.", + "noCombosMatch": "Tiada kombo yang sepadan dengan penapis ini.", + "clearFilters": "Kosongkan penapis", + "searchModels": "Cari model", + "searchModelsPlaceholder": "Cari mengikut model, penyedia atau keupayaan", + "searchCombos": "Cari kombo", + "searchCombosPlaceholder": "Cari mengikut nama kombo, model atau penerangan", + "modelCountSingle": "model", + "modelCountPlural": "model", + "comboCountSingle": "kombo", + "comboCountPlural": "kombo", + "provider": "Penyedia", + "allProviders": "Semua penyedia", + "type": "Jenis", + "allTypes": "Semua jenis", + "subtype": "Subjenis", + "allSubtypes": "Semua subjenis", + "capability": "Keupayaan", + "allCapabilities": "Semua keupayaan", + "pricing": "Harga", + "allPricing": "Semua harga", + "freeOnly": "Percuma sahaja", + "nonFree": "Standard / Bukan percuma", + "providerHealth": "Kesihatan penyedia", + "allHealthStates": "Semua status kesihatan", + "healthy": "Sihat", + "degraded": "Merosot", + "down": "Tergendala", + "testResult": "Keputusan ujian", + "allResults": "Semua keputusan", + "untested": "Belum diuji", + "statusOk": "OK", + "statusSlow": "Perlahan", + "statusError": "Ralat", + "minContext": "Konteks minimum", + "minContextPlaceholder": "cth. 32000", + "strategy": "Strategi", + "allStrategies": "Semua strategi", + "status": "Status", + "allStatuses": "Semua status", + "active": "Aktif", + "paused": "Dijeda", + "minMembers": "Ahli minimum", + "minMembersPlaceholder": "cth. 1", + "maxMembers": "Ahli maksimum", + "maxMembersPlaceholder": "cth. 10", + "testSelected": "Uji yang dipilih ({count})", + "testAllFiltered": "Uji semua yang ditapis ({count})", + "cancel": "Batal", + "clearResults": "Kosongkan keputusan", + "testing": "Menguji...", + "rateLimited": "Kadar dihadkan", + "quotaExceeded": "Kuota melebihi had", + "timeout": "Masa tamat", + "otherError": "Ralat", + "justNow": "Baru sahaja", + "minutesAgo": "{count}m lalu", + "hoursAgo": "{count}j lalu", + "tableRegion": "Jadual katalog model", + "combosTableRegion": "Jadual katalog kombo", + "tableCaption": "Katalog model merentas semua penyedia", + "combosTableCaption": "Katalog kombo dengan keputusan ujian kesihatan", + "selectAllModels": "Pilih semua model pada halaman ini", + "selectAllCombos": "Pilih semua kombo pada halaman ini", + "selectModel": "Pilih model {name}", + "selectCombo": "Pilih kombo {name}", + "model": "Model", + "capabilities": "Keupayaan", + "context": "Konteks", + "output": "Output maksimum", + "flags": "Bendera", + "healthTest": "Ujian Kesihatan", + "actions": "Tindakan", + "test": "Uji", + "custom": "Tersuai", + "free": "Percuma", + "noFlags": "Tiada harga atau bendera sumber dilaporkan", + "noCapabilities": "Tiada metadata keupayaan dilaporkan", + "showingModels": "Menunjukkan {first}–{last} daripada {total} model", + "showingCombos": "Menunjukkan {first}–{last} daripada {total} kombo", + "refreshing": "Menyegarkan…", + "refreshFailed": "Penyegaran gagal. Menunjukkan katalog terakhir yang dimuatkan.", + "page": "Halaman {page} daripada {pageCount}", + "previous": "Sebelumnya", + "next": "Seterusnya", + "combo": "Kombo", + "members": "Ahli", + "moreMembers": "+{count} lagi" + }, "combos": { "title": "Kombo", "description": "Cipta gabungan model dengan penghalaan berwajaran dan sokongan sandaran", diff --git a/src/i18n/messages/mt.json b/src/i18n/messages/mt.json index 7dcc98e34212..6181a0a865a6 100644 --- a/src/i18n/messages/mt.json +++ b/src/i18n/messages/mt.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ippermetti korsiji virtwali adattivi tad-dħul għal kull tenant għad-dispaċċ tal-fornituri (#9654): żieda f'daqqa fit-traffiku ta' tenant wieħed ma tibqax tikkawża żball 503 għal ieħor. Il-varjabbli tal-ambjent OMNIROUTE_CHAT_VIRTUAL_LANES tieħu preċedenza fuq din is-sovraskrittura tad-dashboard; il-bidliet jidħlu fis-seħħ meta jerġa' jinbeda s-server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Paġni tal-fornituri fid-dashboard: uri l-badge B’Xejn biss abbażi ta’ indikazzjonijiet li l-fornitur jirrikonoxxi — ineħħi l-ewristika tal-isem muri, il-kampijiet mhux Boolejani dwar l-użu bla ħlas u s-suffissi :free fuq fornituri rreġistrati mingħajr livell bla ħlas dokumentat. Meta jkun Mitfi, tinżamm ir-regola storika tal-badge.", "featureFlagProxySkipRecentlyFailedDescription": "Il-pools tal-proxy u r-rotazzjoni għal kull kont ta’ opencode jieqfu jerġgħu jservu proxy li jkun għadu kemm falla (sonda TCP miċħuda, jew 429 riċevut permezz tiegħu) għal perjodu għal kull proċess li jirdoppja ma’ kull ripetizzjoni, sa limitu massimu. Ma jinkiteb ebda status tal-proxy; meta kull kandidat jitwarrab, l-għażla tibqa’ l-istess. Mixgħul b’mod awtomatiku; `false` jerġa’ jġib l-għażla sempliċi.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Għal fornituri li l-kwota tagħhom hija miġbura skont l-indirizz tal-egress, ikklassifika membru tal-pool li jaqsam l-indirizz tal-egress osservat ta' membru li ġie rrifjutat reċentement eżatt taħt il-membri b'saħħithom. Ordni biss, qatt eskluż. Jeħtieġ PROXY_SKIP_RECENTLY_FAILED, li jipproduċi s-sinjal ta' rifjut li jaqra. Mitfi b'mod awtomatiku: l-ordni tal-għażla hija eżattament ir-rotazzjoni sempliċi.", "featureFlagProxyPoolEgressObservationDescription": "Uri, taħt pool tal-proxy fid-dashboard, kemm-il IP ta’ ħruġ osservat serva lill-membri tiegħu matul l-aħħar 24 siegħa, kemm-il konnessjoni użathom u l-ogħla għadd osservat wara IP wieħed. Għall-qari biss, ikkalkulat mil-log tal-proxy, u qatt ma jintuża għar-routing. Mitfi b’mod awtomatiku: l-editur tal-pool ma jinbidilx u r-rotta tal-osservazzjoni twieġeb null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Fl-iskennjar tas-saħħa tal-proxy, ħalli sonda li l-mira tkun irrifjutat (401/403/429: il-proxy għadda t-talba, iżda d-destinazzjoni rrifjutat dan l-IP ta’ ħruġ) tirrisettja s-sensiela ta’ fallimenti konsekuttivi tal-proxy, bħal sonda moqdija. Mitfi b’mod awtomatiku: rifjut jibqa’ newtrali u jżomm is-sensiela. 5xx jibqa’ inkonklussiv fiż-żewġ każijiet, u rifjut qatt ma jneħħi, jiddiżattiva jew jerġa’ jattiva proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ħalli t-tindif awtomatiku jħassar il-kompiti terminali (ikkompletati/falluti/ikkanċellati/skaduti) tal-Batch API li jkunu eqdem minn OMNIROUTE_BATCH_RETENTION_DAYS, flimkien mal-punti ta’ kontroll tagħhom għal kull linja, u jneħħi l-kontenut BLOB tal-fajls imtellgħin li jkunu qabżu l-expires_at tagħhom. Diżattivat b’mod awtomatiku: kull installazzjoni eżistenti żżomm din id-data eżattament bħal qabel sakemm operatur jagħżel li jattivah. Ir-rotta DELETE /api/v1/batches/delete-completed attivata mill-operatur ma tiġix affettwata fiż-żewġ każijiet — dan huwa kuntratt separat u inkundizzjonat tal-API pubblika.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Aġġornament disponibbli: v{current} → v{latest}", "cliproxyapiVersion": "Verżjoni" }, + "modelCatalog": { + "title": "Mudelli u Combos", + "subtitle": "Esplora u ttestja s-saħħa tal-mudelli u tal-pipelines tar-routing tal-combos fil-fornituri kollha.", + "refresh": "Aġġorna", + "modelsTab": "Mudelli", + "combosTab": "Combos", + "catalogSections": "Taqsimiet tal-Katalgu", + "loading": "Qed jitgħabba...", + "retry": "Erġa' pprova", + "unableToLoad": "Ma setax jitgħabba l-katalgu tal-mudelli.", + "unableToLoadCombos": "Ma setgħux jitgħabbew il-combos.", + "checkConnection": "Iċċekkja l-konnessjoni u erġa' pprova.", + "noModelsAvailable": "Għad m'hemm l-ebda mudell disponibbli.", + "noModelsMatch": "L-ebda mudell ma jaqbel ma' dawn il-filtri.", + "noCombosAvailable": "Għad m'hemm l-ebda combo disponibbli.", + "noCombosMatch": "L-ebda combo ma taqbel ma' dawn il-filtri.", + "clearFilters": "Neħħi l-filtri", + "searchModels": "Fittex mudelli", + "searchModelsPlaceholder": "Fittex skont il-mudell, il-fornitur, jew il-kapaċità", + "searchCombos": "Fittex combos", + "searchCombosPlaceholder": "Fittex skont l-isem tal-combo, il-mudelli, jew id-deskrizzjoni", + "modelCountSingle": "mudell", + "modelCountPlural": "mudelli", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Fornitur", + "allProviders": "Il-fornituri kollha", + "type": "Tip", + "allTypes": "It-tipi kollha", + "subtype": "Sottotip", + "allSubtypes": "Is-sottotipi kollha", + "capability": "Kapaċità", + "allCapabilities": "Il-kapaċitajiet kollha", + "pricing": "Prezzijiet", + "allPricing": "Il-prezzijiet kollha", + "freeOnly": "B'xejn biss", + "nonFree": "Standard / Mhux b'xejn", + "providerHealth": "Saħħa tal-fornitur", + "allHealthStates": "L-istati kollha tas-saħħa", + "healthy": "B'saħħtu", + "degraded": "Degradat", + "down": "Mhux jaħdem", + "testResult": "Riżultat tat-test", + "allResults": "Ir-riżultati kollha", + "untested": "Mhux ittestjat", + "statusOk": "OK", + "statusSlow": "Bil-mod", + "statusError": "Żball", + "minContext": "Kuntest minimu", + "minContextPlaceholder": "eż. 32000", + "strategy": "Strateġija", + "allStrategies": "L-istrateġiji kollha", + "status": "Stat", + "allStatuses": "L-istati kollha", + "active": "Attiv", + "paused": "Pawżat", + "minMembers": "Membri minimi", + "minMembersPlaceholder": "eż. 1", + "maxMembers": "Membri massimi", + "maxMembersPlaceholder": "eż. 10", + "testSelected": "Ittestja dawk magħżula ({count})", + "testAllFiltered": "Ittestja kollha ffiltrati ({count})", + "cancel": "Ikkanċella", + "clearResults": "Ħassar ir-riżultati", + "testing": "Qed jittestja...", + "rateLimited": "Rata limitata", + "quotaExceeded": "Kwota maqbuża", + "timeout": "Skada l-ħin", + "otherError": "Żball", + "justNow": "Issa stess", + "minutesAgo": "{count}m ilu", + "hoursAgo": "{count}h ilu", + "tableRegion": "Tabella tal-katalgu tal-mudelli", + "combosTableRegion": "Tabella tal-katalgu tal-combos", + "tableCaption": "Katalgu tal-mudelli għall-fornituri kollha", + "combosTableCaption": "Katalgu tal-combos bir-riżultati tat-testijiet tas-saħħa", + "selectAllModels": "Agħżel il-mudelli kollha fuq din il-paġna", + "selectAllCombos": "Agħżel il-combos kollha fuq din il-paġna", + "selectModel": "Agħżel il-mudell {name}", + "selectCombo": "Agħżel il-combo {name}", + "model": "Mudell", + "capabilities": "Kapaċitajiet", + "context": "Kuntest", + "output": "Output massimu", + "flags": "Bnadar", + "healthTest": "Test tas-Saħħa", + "actions": "Azzjonijiet", + "test": "Test", + "custom": "Personalizzat", + "free": "B'xejn", + "noFlags": "L-ebda prezz jew bandiera tas-sors ma ġew irrappurtati", + "noCapabilities": "L-ebda metadata tal-kapaċità ma ġiet irrappurtata", + "showingModels": "Qed jintwerew {first}–{last} minn {total} mudelli", + "showingCombos": "Qed jintwerew {first}–{last} minn {total} combos", + "refreshing": "Qed jaġġorna…", + "refreshFailed": "L-aġġornament ma rnexxiex. Qed jintwera l-aħħar katalgu mgħobbi.", + "page": "Paġna {page} minn {pageCount}", + "previous": "Preċedenti", + "next": "Li jmiss", + "combo": "Combo", + "members": "Membri", + "moreMembers": "+{count} oħra" + }, "combos": { "title": "Kombinazzjonijiet", "description": "Oħloq kombinazzjonijiet ta’ mudelli b’instradar ponderat u appoġġ għal alternattivi ta’ riżerva", diff --git a/src/i18n/messages/my.json b/src/i18n/messages/my.json index 0359ac0101a4..ea2e46ea56d9 100644 --- a/src/i18n/messages/my.json +++ b/src/i18n/messages/my.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "provider dispatch (#9654) အတွက် tenant တစ်ခုချင်းစီအလိုက် အလိုက်သင့်ပြောင်းလဲနိုင်သော virtual admission lanes များကို ဖွင့်ပါ။ tenant တစ်ခု၏ ရုတ်တရက်မြင့်တက်လာသော အသုံးပြုမှုကြောင့် အခြား tenant တွင် 503 ဖြစ်ပေါ်တော့မည်မဟုတ်ပါ။ OMNIROUTE_CHAT_VIRTUAL_LANES env var သည် ဤ dashboard override ထက် ဦးစားပေးသက်ရောက်ပြီး ပြောင်းလဲမှုများသည် server ပြန်လည်စတင်ချိန်တွင် အသက်ဝင်မည်ဖြစ်သည်။", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ဒက်ရှ်ဘုတ် ဝန်ဆောင်မှုပေးသူ စာမျက်နှာများတွင် ဝန်ဆောင်မှုပေးသူက အသိအမှတ်ပြုသည့် အချက်ပြမှုများအပေါ် အခြေခံ၍သာ Free တံဆိပ်ကို ပြပါ — မှတ်တမ်းတင်ထားသော အခမဲ့အဆင့် မရှိသည့် မှတ်ပုံတင်ထားသော ဝန်ဆောင်မှုပေးသူများအတွက် ဖော်ပြအမည်အခြေပြု ခန့်မှန်းနည်း၊ boolean မဟုတ်သော free အကွက်များနှင့် :free နောက်ဆက်များကို မသုံးတော့ပါ။ ပိတ်ထားပါက ယခင်တံဆိပ်စည်းမျဉ်းကို ဆက်သုံးပါမည်။", "featureFlagProxySkipRecentlyFailedDescription": "Proxy pool များနှင့် opencode ၏ အကောင့်တစ်ခုချင်းစီအလိုက် အလှည့်ကျရွေးချယ်မှုသည် ပျက်ကွက်ခဲ့သည့် proxy (TCP probe ကို ငြင်းပယ်ခဲ့ခြင်း သို့မဟုတ် ၎င်းမှတစ်ဆင့် 429 တုံ့ပြန်မှုရရှိခြင်း) ကို process တစ်ခုချင်းစီအလိုက် သတ်မှတ်ကာလအတွင်း ပြန်လည်အသုံးမပြုတော့ပါ။ ထပ်မံဖြစ်ပွားတိုင်း ထိုကာလသည် နှစ်ဆတိုးလာပြီး သတ်မှတ်အများဆုံးပမာဏအထိသာ တိုးပါမည်။ Proxy အခြေအနေကို မှတ်တမ်းတင်မည်မဟုတ်ပါ။ Candidate အားလုံးကို ဘေးဖယ်ထားရသည့်အခါ ရွေးချယ်မှုသည် မပြောင်းလဲပါ။ မူလအားဖြင့် ဖွင့်ထားသည်။ `false` သည် ရိုးရိုးရွေးချယ်မှုကို ပြန်လည်ထားရှိပေးသည်။", - "featureFlagProxyPoolSharedEgressOrderDescription": "Egress address ဖြင့် quota သတ်မှတ်ထားသော provider များအတွက် မကြာသေးမီက ငြင်းပယ်ခံခဲ့ရသော member ၏ တွေ့ရှိရသည့် egress address အား မျှဝေသုံးစွဲထားသော pool member ကို ကောင်းမွန်သည့် member များ၏နောက်တွင်သာ အဆင့်သတ်မှတ်ပါ။ အစီအစဉ်အတွက်သာဖြစ်ပြီး လုံးဝဖယ်ထုတ်မည်မဟုတ်ပါ။ ၎င်းဖတ်ရှုသည့် ငြင်းပယ်မှုအချက်ပြမှုကို ထုတ်ပေးသော PROXY_SKIP_RECENTLY_FAILED လိုအပ်ပါသည်။ ပုံသေအားဖြင့် ပိတ်ထားသည်- ရွေးချယ်မှုအစီအစဉ်သည် သာမန်အလှည့်ကျစနစ် အတိအကျအတိုင်း ဖြစ်သည်။", "featureFlagProxyPoolEgressObservationDescription": "Dashboard ရှိ proxy pool တစ်ခု၏အောက်တွင် လွန်ခဲ့သော 24 နာရီအတွင်း ၎င်း၏ member များအတွက် အသုံးပြုခဲ့သည့် စောင့်ကြည့်တွေ့ရှိထားသော egress IP အရေအတွက်၊ ထို IP များကို အသုံးပြုခဲ့သည့် connection အရေအတွက်နှင့် IP တစ်ခုတည်း၏နောက်ကွယ်တွင် အများဆုံးတွေ့ရှိရသည့် အရေအတွက်တို့ကို ပြသပါ။ ၎င်းသည် ဖတ်ရှုရန်သာဖြစ်ပြီး proxy log မှ တွက်ချက်ထားကာ routing အတွက် မည်သည့်အခါမျှ အသုံးမပြုပါ။ မူလအားဖြင့် ပိတ်ထားသည်။ Pool editor သည် မပြောင်းလဲဘဲ observation route က null ကို ပြန်ပေးသည်။", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy health sweep တွင် target က ငြင်းပယ်ခဲ့သော probe (401/403/429—proxy က လက်ဆင့်ကမ်းပေးခဲ့သော်လည်း destination က ဤ egress IP ကို ငြင်းပယ်ခြင်း) ကို အောင်မြင်စွာ ဆောင်ရွက်ခဲ့သည့် probe ကဲ့သို့ proxy ၏ ဆက်တိုက်ပျက်ကွက်မှုအရေအတွက်ကို ပြန်လည်သတ်မှတ်ခွင့်ပြုပါ။ မူလအားဖြင့် ပိတ်ထားသည်။ ငြင်းပယ်မှုသည် သက်ရောက်မှုမရှိဘဲ streak ကို ဆက်လက်ထိန်းထားသည်။ မည်သည့်အခြေအနေတွင်မဆို 5xx သည် အတည်မပြုနိုင်သည့်အခြေအနေအဖြစ် ဆက်ရှိနေပြီး ငြင်းပယ်မှုတစ်ခုကြောင့် proxy ကို ဖယ်ရှားခြင်း၊ ပိတ်ခြင်း သို့မဟုတ် ပြန်လည်အသက်သွင်းခြင်း မည်သည့်အခါမျှ မပြုလုပ်ပါ။", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "အလိုအလျောက် ရှင်းလင်းရေးလုပ်ငန်းစဉ်ကို OMNIROUTE_BATCH_RETENTION_DAYS ထက် ပိုဟောင်းသော အဆုံးသတ်အခြေအနေ (ပြီးဆုံး/မအောင်မြင်/ပယ်ဖျက်/သက်တမ်းကုန်) ရှိသည့် Batch API အလုပ်များနှင့် ၎င်းတို့၏ စာကြောင်းတစ်ကြောင်းချင်းဆိုင်ရာ checkpoint များကို ဖျက်ခွင့်ပြုပြီး၊ ၎င်းတို့၏ ကိုယ်ပိုင် expires_at ကျော်လွန်သွားသော အပ်လုဒ်ဖိုင်များ၏ BLOB အကြောင်းအရာကိုလည်း ရှင်းလင်းပါ။ ပုံသေအားဖြင့် ပိတ်ထားသည်။ အော်ပရေတာက ဖွင့်ရန် ရွေးချယ်သည့်အချိန်အထိ လက်ရှိထည့်သွင်းမှုတိုင်းသည် ဤဒေတာကို ယခင်အတိုင်း အတိအကျ ဆက်လက်ထိန်းသိမ်းထားမည်။ မည်သို့ဖွင့်ပိတ်ထားသည်ဖြစ်စေ အော်ပရေတာက စတင်လုပ်ဆောင်သည့် DELETE /api/v1/batches/delete-completed route အပေါ် သက်ရောက်မှုမရှိပါ — ၎င်းသည် သီးခြားဖြစ်ပြီး ခြွင်းချက်မရှိသော အများသုံး API စာချုပ်ဖြစ်သည်။", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "အပ်ဒိတ်ရရှိနိုင်သည်- v{current} → v{latest}", "cliproxyapiVersion": "ဗားရှင်း" }, + "modelCatalog": { + "title": "မော်ဒယ်များနှင့် Combos", + "subtitle": "ဝန်ဆောင်မှုပေးသူအားလုံးရှိ မော်ဒယ်များနှင့် combo လမ်းကြောင်းသတ်မှတ်မှု ပိုက်လိုင်းများကို ရှာဖွေကြည့်ရှုပြီး အခြေအနေ စစ်ဆေးပါ။", + "refresh": "ပြန်လည်ဆန်းသစ်ပါ", + "modelsTab": "မော်ဒယ်များ", + "combosTab": "Combos", + "catalogSections": "ကတ်တလောက် ကဏ္ဍများ", + "loading": "လုပ်ဆောင်နေသည်...", + "retry": "ထပ်စမ်းကြည့်ပါ", + "unableToLoad": "မော်ဒယ် ကတ်တလောက်ကို ရယူ၍မရပါ။", + "unableToLoadCombos": "Combos များကို ရယူ၍မရပါ။", + "checkConnection": "ချိတ်ဆက်မှုကို စစ်ဆေးပြီး ထပ်စမ်းကြည့်ပါ။", + "noModelsAvailable": "မော်ဒယ်များ မရရှိနိုင်သေးပါ။", + "noModelsMatch": "ဤစစ်ထုတ်မှုများနှင့် ကိုက်ညီသော မော်ဒယ် မရှိပါ။", + "noCombosAvailable": "Combos များ မရရှိနိုင်သေးပါ။", + "noCombosMatch": "ဤစစ်ထုတ်မှုများနှင့် ကိုက်ညီသော combo မရှိပါ။", + "clearFilters": "စစ်ထုတ်မှုများကို ရှင်းလင်းပါ", + "searchModels": "မော်ဒယ်များကို ရှာဖွေပါ", + "searchModelsPlaceholder": "မော်ဒယ်၊ ဝန်ဆောင်မှုပေးသူ သို့မဟုတ် စွမ်းဆောင်ရည်ဖြင့် ရှာဖွေပါ", + "searchCombos": "Combos များကို ရှာဖွေပါ", + "searchCombosPlaceholder": "Combo အမည်၊ မော်ဒယ် သို့မဟုတ် ဖော်ပြချက်ဖြင့် ရှာဖွေပါ", + "modelCountSingle": "မော်ဒယ်", + "modelCountPlural": "မော်ဒယ်များ", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "ဝန်ဆောင်မှုပေးသူ", + "allProviders": "ဝန်ဆောင်မှုပေးသူ အားလုံး", + "type": "အမျိုးအစား", + "allTypes": "အမျိုးအစား အားလုံး", + "subtype": "အမျိုးအစားခွဲ", + "allSubtypes": "အမျိုးအစားခွဲ အားလုံး", + "capability": "စွမ်းဆောင်ရည်", + "allCapabilities": "စွမ်းဆောင်ရည် အားလုံး", + "pricing": "ဈေးနှုန်း", + "allPricing": "ဈေးနှုန်း အားလုံး", + "freeOnly": "အခမဲ့သာ", + "nonFree": "စံနှုန်း / အခပေး", + "providerHealth": "ဝန်ဆောင်မှုပေးသူ အခြေအနေ", + "allHealthStates": "အခြေအနေ အားလုံး", + "healthy": "ကောင်းမွန်သည်", + "degraded": "ကျဆင်းနေသည်", + "down": "ကျနေသည်", + "testResult": "စမ်းသပ်မှု ရလဒ်", + "allResults": "ရလဒ် အားလုံး", + "untested": "မစမ်းသပ်ရသေးပါ", + "statusOk": "အဆင်ပြေသည်", + "statusSlow": "နှေးကွေးသည်", + "statusError": "အမှား", + "minContext": "အနည်းဆုံး context", + "minContextPlaceholder": "ဥပမာ 32000", + "strategy": "မဟာဗျူဟာ", + "allStrategies": "မဟာဗျူဟာ အားလုံး", + "status": "အခြေအနေ", + "allStatuses": "အခြေအနေ အားလုံး", + "active": "အသုံးပြုနေသည်", + "paused": "ခေတ္တရပ်ထားသည်", + "minMembers": "အနည်းဆုံး အဖွဲ့ဝင်", + "minMembersPlaceholder": "ဥပမာ 1", + "maxMembers": "အများဆုံး အဖွဲ့ဝင်", + "maxMembersPlaceholder": "ဥပမာ 10", + "testSelected": "ရွေးထားသည်များကို စမ်းသပ်ရန် ({count})", + "testAllFiltered": "စစ်ထုတ်ထားသည်များ အားလုံးကို စမ်းသပ်ရန် ({count})", + "cancel": "မလုပ်တော့ပါ", + "clearResults": "ရလဒ်များကို ရှင်းလင်းရန်", + "testing": "စမ်းသပ်နေသည်...", + "rateLimited": "နှုန်းထား ကန့်သတ်ခံရသည်", + "quotaExceeded": "ခွင့်ပြုပမာဏ ကျော်လွန်သွားသည်", + "timeout": "အချိန်ကုန်ဆုံးသွားသည်", + "otherError": "အမှား", + "justNow": "ယခုလေးတင်", + "minutesAgo": "လွန်ခဲ့သော {count} မိနစ်က", + "hoursAgo": "လွန်ခဲ့သော {count} နာရီက", + "tableRegion": "မော်ဒယ် ကတ်တလောက် ဇယား", + "combosTableRegion": "Combos ကတ်တလောက် ဇယား", + "tableCaption": "ပံ့ပိုးပေးသူအားလုံးရှိ မော်ဒယ် ကတ်တလောက်", + "combosTableCaption": "ကျန်းမာရေး စစ်ဆေးမှု ရလဒ်များပါဝင်သော Combos ကတ်တလောက်", + "selectAllModels": "ဤစာမျက်နှာရှိ မော်ဒယ်အားလုံးကို ရွေးရန်", + "selectAllCombos": "ဤစာမျက်နှာရှိ Combos အားလုံးကို ရွေးရန်", + "selectModel": "မော်ဒယ် {name} ကို ရွေးရန်", + "selectCombo": "Combo {name} ကို ရွေးရန်", + "model": "မော်ဒယ်", + "capabilities": "စွမ်းဆောင်ရည်များ", + "context": "အကြောင်းအရာ", + "output": "အများဆုံး အထွက်", + "flags": "အမှတ်အသားများ", + "healthTest": "ကျန်းမာရေး စစ်ဆေးမှု", + "actions": "လုပ်ဆောင်ချက်များ", + "test": "စမ်းသပ်ရန်", + "custom": "စိတ်ကြိုက်", + "free": "အခမဲ့", + "noFlags": "ဈေးနှုန်း သို့မဟုတ် ရင်းမြစ် အမှတ်အသား ဖော်ပြထားခြင်း မရှိပါ", + "noCapabilities": "စွမ်းဆောင်ရည် မက်တာဒေတာ ဖော်ပြထားခြင်း မရှိပါ", + "showingModels": "မော်ဒယ် စုစုပေါင်း {total} ခုအနက် {first}–{last} ကို ပြသနေသည်", + "showingCombos": "တွဲစပ်မှု စုစုပေါင်း {total} ခုအနက် {first}–{last} ကို ပြသနေသည်", + "refreshing": "ပြန်လည်ဆန်းသစ်နေသည်…", + "refreshFailed": "ပြန်လည်ဆန်းသစ်မှု မအောင်မြင်ပါ။ နောက်ဆုံး ရယူထားသော ကက်တလောက်ကို ပြသနေပါသည်။", + "page": "စာမျက်နှာ {pageCount} အနက် {page}", + "previous": "ယခင်", + "next": "နောက်တစ်ခု", + "combo": "တွဲစပ်မှု", + "members": "အဖွဲ့ဝင်များ", + "moreMembers": "နောက်ထပ် +{count} ခု" + }, "combos": { "title": "ပေါင်းစပ်မော်ဒယ်များ", "description": "အလေးချိန်အလိုက် လမ်းကြောင်းခွဲခြင်းနှင့် အရန်ပံ့ပိုးမှုပါဝင်သော မော်ဒယ်ပေါင်းစပ်မှုများကို ဖန်တီးပါ", diff --git a/src/i18n/messages/ne.json b/src/i18n/messages/ne.json index b2a4923765c9..bf229253e0d7 100644 --- a/src/i18n/messages/ne.json +++ b/src/i18n/messages/ne.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "प्रदायक डिस्प्याच (#9654) का लागि प्रत्येक टेनेन्टअनुसार अनुकूल हुने भर्चुअल एडमिसन लेनहरू सक्षम गर्नुहोस्: अब एउटा टेनेन्टको अचानक बढेको ट्राफिकले अर्कोलाई 503 गराउँदैन। OMNIROUTE_CHAT_VIRTUAL_LANES env var ले यस ड्यासबोर्ड ओभरराइडभन्दा प्राथमिकता पाउँछ; परिवर्तनहरू सर्भर पुनः सुरु भएपछि लागू हुन्छन्।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ड्यासबोर्डका प्रदायक पृष्ठहरू: प्रदायकले स्वीकार गर्ने सङ्केतहरूमा मात्र निःशुल्क ब्याज देखाउनुहोस् — दस्तावेजीकृत निःशुल्क तह नभएका दर्ता गरिएका प्रदायकहरूका प्रदर्शन-नाममा आधारित अनुमान, गैर-बुलियन निःशुल्क फिल्डहरू र :free प्रत्ययहरू हटाउँछ। बन्द गर्दा ऐतिहासिक ब्याज नियम कायम रहन्छ।", "featureFlagProxySkipRecentlyFailedDescription": "प्रोक्सी पूलहरू र opencode को प्रति-खाता रोटेसनले भर्खरै असफल भएको प्रोक्सी (TCP प्रोब अस्वीकार भएको वा त्यसमार्फत 429 प्राप्त भएको) लाई प्रत्येक पटक दोब्बर हुँदै अधिकतम सीमासम्म पुग्ने प्रति-प्रक्रिया अवधिका लागि पुनः प्रयोग गर्न रोक्छ। कुनै प्रोक्सी स्थिति लेखिँदैन; सबै उम्मेदवार अलग राखिएमा छनोट अपरिवर्तित रहन्छ। पूर्वनिर्धारित रूपमा सक्रिय; `false` ले साधारण छनोट पुनर्स्थापित गर्छ।", - "featureFlagProxyPoolSharedEgressOrderDescription": "egress ठेगाना अनुसार कोटा समूहबद्ध गरिएका प्रदायकहरूका लागि, भर्खरै अस्वीकार गरिएको सदस्यको देखिएको egress ठेगाना साझा गर्ने पूल सदस्यलाई स्वस्थ सदस्यहरूभन्दा ठीक तल क्रमबद्ध गर्नुहोस्। क्रम मात्र, कहिल्यै हटाइँदैन। PROXY_SKIP_RECENTLY_FAILED आवश्यक पर्दछ, जसले यसले पढ्ने अस्वीकृति संकेत उत्पादन गर्छ। पूर्वनिर्धारित रूपमा बन्द: चयन क्रम ठ्याक्कै सामान्य रोटेसन हो।", "featureFlagProxyPoolEgressObservationDescription": "ड्यासबोर्डमा प्रोक्सी पूलअन्तर्गत, पछिल्लो २४ घण्टामा त्यसका सदस्यहरूलाई सेवा दिने कति वटा अवलोकित इग्रेस IP थिए, कति जडानले तिनलाई प्रयोग गरे र एउटै IP पछाडि सबैभन्दा धेरै कति सदस्य देखिए भन्ने देखाउनुहोस्। पढ्नका लागि मात्र, प्रोक्सी लगबाट गणना गरिएको र राउटिङका लागि कहिल्यै प्रयोग नगरिने। पूर्वनिर्धारित रूपमा बन्द: पूल सम्पादक अपरिवर्तित रहन्छ र अवलोकन रुटले null फर्काउँछ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "प्रोक्सी स्वास्थ्य स्वीपमा, लक्ष्यले अस्वीकार गरेको प्रोब (401/403/429: प्रोक्सीले रिले गर्यो, गन्तव्यले यो इग्रेस IP अस्वीकार गर्यो) लाई सेवा दिइएको प्रोबजस्तै प्रोक्सीको लगातार-असफलता क्रम रिसेट गर्न दिनुहोस्। पूर्वनिर्धारित रूपमा बन्द: अस्वीकृति तटस्थ रहन्छ र क्रम कायम राख्छ। दुवै अवस्थामा 5xx अनिर्णायक नै रहन्छ, र अस्वीकृतिले प्रोक्सीलाई कहिल्यै हटाउँदैन, निष्क्रिय पार्दैन वा पुनः सक्रिय गर्दैन।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "स्वचालित सफाइ प्रक्रियालाई OMNIROUTE_BATCH_RETENTION_DAYS भन्दा पुराना अन्तिम अवस्थामा रहेका (पूरा भएका/असफल/रद्द गरिएका/म्याद सकिएका) Batch API कार्यहरू तिनका प्रति-पङ्क्ति चेकपोइन्टसहित मेटाउन र आफ्नै expires_at नाघेका अपलोड गरिएका फाइलहरूको BLOB सामग्री खाली गर्न दिनुहोस्। पूर्वनिर्धारित रूपमा बन्द: अपरेटरले यसलाई सक्रिय नगरेसम्म हरेक विद्यमान इन्स्टलेसनले यो डेटा पहिले जस्तै राख्छ। अपरेटरद्वारा ट्रिगर गरिने DELETE /api/v1/batches/delete-completed रुटमा कुनै पनि अवस्थामा असर पर्दैन — यो छुट्टै, सर्तरहित सार्वजनिक API सम्झौता हो।", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "अपडेट उपलब्ध छ: v{current} → v{latest}", "cliproxyapiVersion": "संस्करण" }, + "modelCatalog": { + "title": "मोडेल र कम्बोहरू", + "subtitle": "सबै प्रदायकहरूमा मोडेलहरू र कम्बो राउटिङ पाइपलाइनहरू ब्राउज गर्नुहोस् र स्वास्थ्य परीक्षण गर्नुहोस्।", + "refresh": "रिफ्रेस गर्नुहोस्", + "modelsTab": "मोडेलहरू", + "combosTab": "कम्बोहरू", + "catalogSections": "क्याटलग खण्डहरू", + "loading": "लोड हुँदैछ...", + "retry": "पुन: प्रयास गर्नुहोस्", + "unableToLoad": "मोडेल क्याटलग लोड गर्न असमर्थ।", + "unableToLoadCombos": "कम्बोहरू लोड गर्न असमर्थ।", + "checkConnection": "कनेक्सन जाँच गर्नुहोस् र पुन: प्रयास गर्नुहोस्।", + "noModelsAvailable": "अहिलेसम्म कुनै मोडेलहरू उपलब्ध छैनन्।", + "noModelsMatch": "यी फिल्टरहरूसँग कुनै पनि मोडेल मेल खाँदैन।", + "noCombosAvailable": "अहिलेसम्म कुनै कम्बोहरू उपलब्ध छैनन्।", + "noCombosMatch": "यी फिल्टरहरूसँग कुनै पनि कम्बो मेल खाँदैन।", + "clearFilters": "फिल्टरहरू हटाउनुहोस्", + "searchModels": "मोडेलहरू खोज्नुहोस्", + "searchModelsPlaceholder": "मोडेल, प्रदायक, वा क्षमता अनुसार खोज्नुहोस्", + "searchCombos": "कम्बोहरू खोज्नुहोस्", + "searchCombosPlaceholder": "कम्बो नाम, मोडेल वा विवरण अनुसार खोज्नुहोस्", + "modelCountSingle": "मोडेल", + "modelCountPlural": "मोडेलहरू", + "comboCountSingle": "कम्बो", + "comboCountPlural": "कम्बोहरू", + "provider": "प्रदायक", + "allProviders": "सबै प्रदायकहरू", + "type": "प्रकार", + "allTypes": "सबै प्रकारहरू", + "subtype": "उपप्रकार", + "allSubtypes": "सबै उपप्रकारहरू", + "capability": "क्षमता", + "allCapabilities": "सबै क्षमताहरू", + "pricing": "मूल्य निर्धारण", + "allPricing": "सबै मूल्य निर्धारण", + "freeOnly": "नि:शुल्क मात्र", + "nonFree": "मानक / सशुल्क", + "providerHealth": "प्रदायक स्वास्थ्य", + "allHealthStates": "सबै स्वास्थ्य स्थितिहरू", + "healthy": "स्वस्थ", + "degraded": "खस्किएको", + "down": "डाउन", + "testResult": "परीक्षण परिणाम", + "allResults": "सबै परिणामहरू", + "untested": "परीक्षण नगरिएको", + "statusOk": "ठीक छ", + "statusSlow": "सुस्त", + "statusError": "त्रुटि", + "minContext": "न्यूनतम सन्दर्भ", + "minContextPlaceholder": "जस्तै: 32000", + "strategy": "रणनीति", + "allStrategies": "सबै रणनीतिहरू", + "status": "स्थिति", + "allStatuses": "सबै स्थितिहरू", + "active": "सक्रिय", + "paused": "रोकिएको", + "minMembers": "न्यूनतम सदस्यहरू", + "minMembersPlaceholder": "जस्तै: 1", + "maxMembers": "अधिकतम सदस्यहरू", + "maxMembersPlaceholder": "जस्तै: 10", + "testSelected": "चयन गरिएका परीक्षण गर्नुहोस् ({count})", + "testAllFiltered": "फिल्टर गरिएका सबै परीक्षण गर्नुहोस् ({count})", + "cancel": "रद्द गर्नुहोस्", + "clearResults": "परिणामहरू खाली गर्नुहोस्", + "testing": "परीक्षण गर्दै...", + "rateLimited": "दर सीमित", + "quotaExceeded": "कोटा समाप्त भयो", + "timeout": "समय समाप्त भयो", + "otherError": "त्रुटि", + "justNow": "भर्खरै", + "minutesAgo": "{count} मिनेट अघि", + "hoursAgo": "{count} घण्टा अघि", + "tableRegion": "मोडेल क्याटलग तालिका", + "combosTableRegion": "कम्बो क्याटलग तालिका", + "tableCaption": "सबै प्रदायकहरूमा मोडेल क्याटलग", + "combosTableCaption": "स्वास्थ्य परीक्षण परिणामसहितको कम्बो क्याटलग", + "selectAllModels": "यस पृष्ठका सबै मोडेलहरू चयन गर्नुहोस्", + "selectAllCombos": "यस पृष्ठका सबै कम्बोहरू चयन गर्नुहोस्", + "selectModel": "मोडेल {name} चयन गर्नुहोस्", + "selectCombo": "कम्बो {name} चयन गर्नुहोस्", + "model": "मोडेल", + "capabilities": "क्षमताहरू", + "context": "सन्दर्भ", + "output": "अधिकतम आउटपुट", + "flags": "फ्ल्यागहरू", + "healthTest": "हेल्थ टेस्ट", + "actions": "कार्यहरू", + "test": "परीक्षण", + "custom": "कस्टम", + "free": "निःशुल्क", + "noFlags": "कुनै मूल्य वा स्रोत फ्ल्याग रिपोर्ट गरिएको छैन", + "noCapabilities": "कुनै क्षमता मेटाडेटा रिपोर्ट गरिएको छैन", + "showingModels": "{total} मोडेलहरू मध्ये {first}–{last} देखाउँदै", + "showingCombos": "{total} कम्बोहरू मध्ये {first}–{last} देखाउँदै", + "refreshing": "रिफ्रेस गर्दै…", + "refreshFailed": "रिफ्रेस असफल भयो। अन्तिम पटक लोड गरिएको क्याटलग देखाउँदै।", + "page": "{pageCount} को पृष्ठ {page}", + "previous": "अघिल्लो", + "next": "अर्को", + "combo": "कम्बो", + "members": "सदस्यहरू", + "moreMembers": "+{count} थप" + }, "combos": { "title": "कम्बोहरू", "description": "भारित राउटिङ र फलब्याक समर्थनसहित मोडेल कम्बोहरू सिर्जना गर्नुहोस्", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index 2535d77e3642..f3f08cc9dd6e 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Schakel adaptieve virtuele toegangsbanen per tenant in voor provider-dispatch (#9654): een piek van de ene tenant geeft de andere niet langer een 503. De omgevingsvariabele OMNIROUTE_CHAT_VIRTUAL_LANES wint het van deze dashboard-instelling; wijzigingen gaan in bij een serverherstart.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Providerpagina's in het dashboard: toon de badge Gratis alleen bij signalen die de provider ondersteunt — de heuristiek voor weergavenamen, niet-booleaanse gratisvelden en :free-achtervoegsels bij geregistreerde providers zonder een gedocumenteerde gratis laag worden niet meer gebruikt. Uit behoudt de historische badgeregel.", "featureFlagProxySkipRecentlyFailedDescription": "Proxypools en de rotatie per account van opencode zorgen ervoor dat een proxy die zojuist is mislukt (geweigerde TCP-probe of een 429 die via de proxy is ontvangen) gedurende een periode per proces niet opnieuw wordt aangeboden. Deze periode verdubbelt bij elke herhaling, tot een maximum. Er wordt geen proxystatus opgeslagen; wanneer elke kandidaat terzijde is geschoven, blijft de keuze ongewijzigd. Standaard ingeschakeld; `false` herstelt de gewone selectie.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Voor providers waarvan het quotum is gegroepeerd per egress-adres: rangschik een pool-lid dat het waargenomen egress-adres deelt met een recent geweigerd lid net onder gezonde leden. Alleen volgorde, nooit uitgesloten. Vereist PROXY_SKIP_RECENTLY_FAILED, wat het weigeringssignaal produceert dat het uitleest. Standaard uitgeschakeld: selectievolgorde is exact de standaardrotatie.", "featureFlagProxyPoolEgressObservationDescription": "Toon onder een proxypool in het dashboard hoeveel waargenomen uitgaande IP-adressen de leden ervan in de afgelopen 24 uur hebben gebruikt, hoeveel verbindingen daarvan gebruikmaakten en hoeveel verbindingen maximaal achter één IP zijn waargenomen. Alleen-lezen, berekend op basis van het proxylogboek en nooit gebruikt voor routering. Standaard uitgeschakeld: de pooleditor blijft ongewijzigd en de observatieroute antwoordt met null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Laat bij de proxygezondheidscontrole een probe die door het doel is geweigerd (401/403/429: de proxy heeft doorgestuurd, maar de bestemming heeft dit uitgaande IP-adres geweigerd) de reeks opeenvolgende fouten van de proxy resetten, net als een geslaagde probe. Standaard uitgeschakeld: een weigering blijft neutraal en behoudt de reeks. Een 5xx blijft in beide gevallen onbeslist, en een weigering verwijdert, deactiveert of heractiveert een proxy nooit.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Laat de automatische opschoonactie definitieve (voltooide/mislukte/geannuleerde/verlopen) Batch API-taken verwijderen die ouder zijn dan OMNIROUTE_BATCH_RETENTION_DAYS, samen met hun controlepunten per regel, en laat de BLOB-inhoud wissen van geüploade bestanden waarvan de eigen expires_at is verstreken. Standaard uitgeschakeld: elke bestaande installatie bewaart deze gegevens precies zoals voorheen, totdat een beheerder dit inschakelt. De door de beheerder geactiveerde route DELETE /api/v1/batches/delete-completed wordt in beide gevallen niet beïnvloed; dit is een afzonderlijk, onvoorwaardelijk openbaar API-contract.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Update beschikbaar: v{current} → v{latest}", "cliproxyapiVersion": "Versie" }, + "modelCatalog": { + "title": "Modellen & combo's", + "subtitle": "Blader door en test de status van modellen en combo-routingpipelines van elke provider.", + "refresh": "Vernieuwen", + "modelsTab": "Modellen", + "combosTab": "Combo's", + "catalogSections": "Catalogussecties", + "loading": "Laden...", + "retry": "Opnieuw proberen", + "unableToLoad": "Kan de modelcatalogus niet laden.", + "unableToLoadCombos": "Kan combo's niet laden.", + "checkConnection": "Controleer de verbinding en probeer het opnieuw.", + "noModelsAvailable": "Er zijn nog geen modellen beschikbaar.", + "noModelsMatch": "Er komen geen modellen overeen met deze filters.", + "noCombosAvailable": "Er zijn nog geen combo's beschikbaar.", + "noCombosMatch": "Er komen geen combo's overeen met deze filters.", + "clearFilters": "Filters wissen", + "searchModels": "Modellen zoeken", + "searchModelsPlaceholder": "Zoeken op model, provider of functionaliteit", + "searchCombos": "Combo's zoeken", + "searchCombosPlaceholder": "Zoeken op combonaam, modellen of beschrijving", + "modelCountSingle": "model", + "modelCountPlural": "modellen", + "comboCountSingle": "combo", + "comboCountPlural": "combo's", + "provider": "Provider", + "allProviders": "Alle providers", + "type": "Type", + "allTypes": "Alle types", + "subtype": "Subtype", + "allSubtypes": "Alle subtypes", + "capability": "Functionaliteit", + "allCapabilities": "Alle functionaliteiten", + "pricing": "Prijzen", + "allPricing": "Alle prijzen", + "freeOnly": "Alleen gratis", + "nonFree": "Standaard / Niet-gratis", + "providerHealth": "Providerstatus", + "allHealthStates": "Alle gezondheidsstatussen", + "healthy": "Gezond", + "degraded": "Gedegradeerd", + "down": "Offline", + "testResult": "Testresultaat", + "allResults": "Alle resultaten", + "untested": "Niet getest", + "statusOk": "OK", + "statusSlow": "Traag", + "statusError": "Fout", + "minContext": "Min. context", + "minContextPlaceholder": "bijv. 32000", + "strategy": "Strategie", + "allStrategies": "Alle strategieën", + "status": "Status", + "allStatuses": "Alle statussen", + "active": "Actief", + "paused": "Gepauzeerd", + "minMembers": "Min. leden", + "minMembersPlaceholder": "bijv. 1", + "maxMembers": "Max. leden", + "maxMembersPlaceholder": "bijv. 10", + "testSelected": "Geselecteerde testen ({count})", + "testAllFiltered": "Alle gefilterde testen ({count})", + "cancel": "Annuleren", + "clearResults": "Resultaten wissen", + "testing": "Testen...", + "rateLimited": "Aanvraaglimiet bereikt", + "quotaExceeded": "Quotum overschreden", + "timeout": "Time-out", + "otherError": "Fout", + "justNow": "Zojuist", + "minutesAgo": "{count}m geleden", + "hoursAgo": "{count}u geleden", + "tableRegion": "Tabel modellencatalogus", + "combosTableRegion": "Tabel combocatalogus", + "tableCaption": "Modellencatalogus van alle providers", + "combosTableCaption": "Combocatalogus met resultaten van statuscontroles", + "selectAllModels": "Selecteer alle modellen op deze pagina", + "selectAllCombos": "Selecteer alle combo's op deze pagina", + "selectModel": "Selecteer model {name}", + "selectCombo": "Selecteer combo {name}", + "model": "Model", + "capabilities": "Mogelijkheden", + "context": "Context", + "output": "Maximale uitvoer", + "flags": "Vlaggen", + "healthTest": "Gezondheidstest", + "actions": "Acties", + "test": "Testen", + "custom": "Aangepast", + "free": "Gratis", + "noFlags": "Geen prijs- of bronvlag gerapporteerd", + "noCapabilities": "Geen metadata over mogelijkheden gerapporteerd", + "showingModels": "Toont {first}–{last} van {total} modellen", + "showingCombos": "Toont {first}–{last} van {total} combo's", + "refreshing": "Vernieuwen…", + "refreshFailed": "Vernieuwen mislukt. Laatst geladen catalogus wordt weergegeven.", + "page": "Pagina {page} van {pageCount}", + "previous": "Vorige", + "next": "Volgende", + "combo": "Combo", + "members": "Leden", + "moreMembers": "+{count} meer" + }, "combos": { "title": "Combo's", "description": "Creëer modelcombinaties met gewogen routing en fallback-ondersteuning", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index 8ddaafcfb757..5424810d16ff 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktiver adaptive virtuelle tilgangsfelt per tenant for leverandørdistribusjon (#9654): et utbrudd fra én tenant gir ikke lenger en annen 503. Miljøvariabelen OMNIROUTE_CHAT_VIRTUAL_LANES overstyrer denne innstillingen i dashbordet; endringer trer i kraft ved omstart av serveren.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leverandørsider i kontrollpanelet: Vis Gratis-merket bare basert på signaler som leverandøren respekterer — bruker ikke lenger heuristikken for visningsnavn, ikke-boolske gratisfelt eller :free-suffikser for registrerte leverandører uten et dokumentert gratisnivå. Når dette er slått av, brukes den tidligere merkeregelen.", "featureFlagProxySkipRecentlyFailedDescription": "Proxygrupper og rotasjonen per konto for opencode slutter midlertidig å bruke en proxy som nettopp sviktet (avvist TCP-sonde eller en 429 mottatt gjennom den), i en prosesspesifikk periode som dobles for hver gjentakelse, opptil en øvre grense. Ingen proxystatus lagres. Hvis alle kandidater settes til side, forblir valget uendret. På som standard; `false` gjenoppretter vanlig valg.", - "featureFlagProxyPoolSharedEgressOrderDescription": "For leverandører der kvoten er inndelt etter egress-adresse, ranger et pool-medlem som deler et nylig avvist medlems observerte egress-adresse like under friske medlemmer. Kun rekkefølge, aldri ekskludert. Krever PROXY_SKIP_RECENTLY_FAILED, som produserer avvisningssignalet den leser. Av som standard: utvalgsrekkefølgen er nøyaktig den vanlige rotasjonen.", "featureFlagProxyPoolEgressObservationDescription": "Vis under en proxygruppe i kontrollpanelet hvor mange observerte utgående IP-adresser som betjente medlemmene i løpet av de siste 24 timene, hvor mange tilkoblinger som brukte dem, og det høyeste antallet som ble observert bak én IP-adresse. Skrivebeskyttet, beregnet fra proxyloggen og aldri brukt til ruting. Av som standard: Redigeringen av proxygruppen er uendret, og observasjonsruten returnerer null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "La en sonde som målet avviste (401/403/429: proxyen videresendte forespørselen, men destinasjonen avviste denne utgående IP-adressen), nullstille proxyens rekke av påfølgende feil under helsesjekken av proxyer, på samme måte som en besvart sonde. Av som standard: En avvisning forblir nøytral og beholder rekken. En 5xx forblir ikke-konkluderende i begge tilfeller, og en avvisning fjerner, deaktiverer eller reaktiverer aldri en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "La den automatiske oppryddingen slette avsluttede (fullførte/mislykkede/avbrutte/utløpte) Batch API-jobber som er eldre enn OMNIROUTE_BATCH_RETENTION_DAYS, sammen med kontrollpunktene deres per linje, og tømme BLOB-innholdet i opplastede filer etter deres respektive expires_at. Av som standard: Alle eksisterende installasjoner beholder disse dataene nøyaktig som før frem til en operatør aktiverer funksjonen. Den operatørutløste ruten DELETE /api/v1/batches/delete-completed påvirkes uansett ikke – den er en separat, ubetinget offentlig API-kontrakt.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Oppdatering tilgjengelig: v{current} → v{latest}", "cliproxyapiVersion": "Versjon" }, + "modelCatalog": { + "title": "Modeller og kombinasjoner", + "subtitle": "Utforsk og helsetest modeller og kombinasjonsruting-pipeliner på tvers av alle leverandører.", + "refresh": "Oppdater", + "modelsTab": "Modeller", + "combosTab": "Kombinasjoner", + "catalogSections": "Katalogseksjoner", + "loading": "Laster inn...", + "retry": "Prøv igjen", + "unableToLoad": "Kunne ikke laste inn modellkatalogen.", + "unableToLoadCombos": "Kunne ikke laste inn kombinasjoner.", + "checkConnection": "Sjekk tilkoblingen og prøv igjen.", + "noModelsAvailable": "Ingen modeller er tilgjengelige ennå.", + "noModelsMatch": "Ingen modeller samsvarer med disse filtrene.", + "noCombosAvailable": "Ingen kombinasjoner er tilgjengelige ennå.", + "noCombosMatch": "Ingen kombinasjoner samsvarer med disse filtrene.", + "clearFilters": "Nullstill filtre", + "searchModels": "Søk etter modeller", + "searchModelsPlaceholder": "Søk etter modell, leverandør eller kapabilitet", + "searchCombos": "Søk etter kombinasjoner", + "searchCombosPlaceholder": "Søk etter kombinasjonsnavn, modeller eller beskrivelse", + "modelCountSingle": "modell", + "modelCountPlural": "modeller", + "comboCountSingle": "kombinasjon", + "comboCountPlural": "kombinasjoner", + "provider": "Leverandør", + "allProviders": "Alle leverandører", + "type": "Type", + "allTypes": "Alle typer", + "subtype": "Undertype", + "allSubtypes": "Alle undertyper", + "capability": "Kapabilitet", + "allCapabilities": "Alle kapabiliteter", + "pricing": "Prising", + "allPricing": "All prising", + "freeOnly": "Kun gratis", + "nonFree": "Standard / ikke-gratis", + "providerHealth": "Leverandørhelse", + "allHealthStates": "Alle helsetilstander", + "healthy": "Frisk", + "degraded": "Redusert", + "down": "Nede", + "testResult": "Testresultat", + "allResults": "Alle resultater", + "untested": "Ikke testet", + "statusOk": "OK", + "statusSlow": "Treg", + "statusError": "Feil", + "minContext": "Min. kontekst", + "minContextPlaceholder": "f.eks. 32000", + "strategy": "Strategi", + "allStrategies": "Alle strategier", + "status": "Status", + "allStatuses": "Alle statuser", + "active": "Aktiv", + "paused": "Pauset", + "minMembers": "Min. medlemmer", + "minMembersPlaceholder": "f.eks. 1", + "maxMembers": "Maks. medlemmer", + "maxMembersPlaceholder": "f.eks. 10", + "testSelected": "Test valgte ({count})", + "testAllFiltered": "Test alle filtrerte ({count})", + "cancel": "Avbryt", + "clearResults": "Tøm resultater", + "testing": "Tester...", + "rateLimited": "Hastighetsbegrenset", + "quotaExceeded": "Kvote overskredet", + "timeout": "Tidsavbrudd", + "otherError": "Feil", + "justNow": "Akkurat nå", + "minutesAgo": "{count}m siden", + "hoursAgo": "{count}t siden", + "tableRegion": "Tabell for modellkatalog", + "combosTableRegion": "Tabell for kombinasjonskatalog", + "tableCaption": "Modellkatalog på tvers av alle leverandører", + "combosTableCaption": "Kombinasjonskatalog med helsetestresultater", + "selectAllModels": "Velg alle modeller på denne siden", + "selectAllCombos": "Velg alle kombinasjoner på denne siden", + "selectModel": "Velg modell {name}", + "selectCombo": "Velg kombinasjon {name}", + "model": "Modell", + "capabilities": "Kapasiteter", + "context": "Kontekst", + "output": "Maks utdata", + "flags": "Flagg", + "healthTest": "Helsetest", + "actions": "Handlinger", + "test": "Test", + "custom": "Egendefinert", + "free": "Gratis", + "noFlags": "Ingen pris- eller kildeflagg rapportert", + "noCapabilities": "Ingen kapasitetsmetadata rapportert", + "showingModels": "Viser {first}–{last} av {total} modeller", + "showingCombos": "Viser {first}–{last} av {total} kombinasjoner", + "refreshing": "Oppdaterer…", + "refreshFailed": "Oppdatering mislyktes. Viser den sist innlastede katalogen.", + "page": "Side {page} av {pageCount}", + "previous": "Forrige", + "next": "Neste", + "combo": "Kombinasjon", + "members": "Medlemmer", + "moreMembers": "+{count} flere" + }, "combos": { "title": "Kombinasjoner", "description": "Lag modellkombinasjoner med vektet ruting og reservestøtte", diff --git a/src/i18n/messages/or.json b/src/i18n/messages/or.json index e9f6e6dc26ef..00cb9111d366 100644 --- a/src/i18n/messages/or.json +++ b/src/i18n/messages/or.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ପ୍ରଦାତା ଡିସ୍ପାଚ୍ (#9654) ପାଇଁ ପ୍ରତି-ଟେନାଣ୍ଟ ଅନୁକୂଳନଶୀଳ ଭର୍ଚୁଆଲ୍ ଆଡମିଶନ୍ ଲେନ୍ଗୁଡ଼ିକ ସକ୍ଷମ କରନ୍ତୁ: ଗୋଟିଏ ଟେନାଣ୍ଟର ହଠାତ୍ ଟ୍ରାଫିକ୍ ବୃଦ୍ଧି ଆଉ ଅନ୍ୟ ଟେନାଣ୍ଟ ପାଇଁ 503 ତ୍ରୁଟି ସୃଷ୍ଟି କରିବ ନାହିଁ। OMNIROUTE_CHAT_VIRTUAL_LANES env var ଏହି ଡ୍ୟାସ୍ବୋର୍ଡ ଓଭର୍ରାଇଡ୍ଠାରୁ ପ୍ରାଥମିକତା ପାଏ; ସର୍ଭର୍ ପୁନଃଚାଳନ ପରେ ପରିବର୍ତ୍ତନଗୁଡ଼ିକ କାର୍ଯ୍ୟକାରୀ ହୁଏ।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ଡ୍ୟାଶବୋର୍ଡ ପ୍ରଦାନକାରୀ ପୃଷ୍ଠାଗୁଡ଼ିକ: କେବଳ ପ୍ରଦାନକାରୀ ସ୍ୱୀକୃତି ଦେଉଥିବା ସଙ୍କେତଗୁଡ଼ିକ ଆଧାରରେ ମାଗଣା ବ୍ୟାଜ୍ ଦେଖାନ୍ତୁ — ଲିପିବଦ୍ଧ ମାଗଣା ସ୍ତର ନଥିବା ପଞ୍ଜୀକୃତ ପ୍ରଦାନକାରୀଙ୍କ ପାଇଁ ପ୍ରଦର୍ଶନ-ନାମ ଅନୁମାନ, ଅଣ-ବୁଲିୟନ୍ ମାଗଣା ଫିଲ୍ଡ ଏବଂ :free ପ୍ରତ୍ୟୟଗୁଡ଼ିକୁ ବାଦ ଦିଏ। ବନ୍ଦ ରଖିଲେ ପୂର୍ବରୁ ପ୍ରଚଳିତ ବ୍ୟାଜ୍ ନିୟମ ବଜାୟ ରହେ।", "featureFlagProxySkipRecentlyFailedDescription": "ପ୍ରକ୍ସି ପୁଲ୍ ଏବଂ opencodeର ପ୍ରତି-ଆକାଉଣ୍ଟ ରୋଟେସନ୍, ସଦ୍ୟ ବିଫଳ ହୋଇଥିବା ପ୍ରକ୍ସିକୁ (ପ୍ରତ୍ୟାଖ୍ୟାନ ହୋଇଥିବା TCP ପ୍ରୋବ୍ କିମ୍ବା ତାହା ମାଧ୍ୟମରେ ପ୍ରାପ୍ତ 429) ପ୍ରତ୍ୟେକ ପୁନରାବୃତ୍ତିରେ ଦ୍ୱିଗୁଣିତ ହେଉଥିବା, ଏକ ସର୍ବାଧିକ ସୀମା ପର୍ଯ୍ୟନ୍ତ ପ୍ରତି-ପ୍ରକ୍ରିୟା ଅବଧି ପାଇଁ ପୁଣି ସେବାରେ ବ୍ୟବହାର କରିବା ବନ୍ଦ କରେ। କୌଣସି ପ୍ରକ୍ସି ସ୍ଥିତି ଲେଖାଯାଏ ନାହିଁ; ପ୍ରତ୍ୟେକ ପ୍ରାର୍ଥୀକୁ ପାଖକୁ ରଖାଗଲେ ଚୟନ ଅପରିବର୍ତ୍ତିତ ରହେ। ଡିଫଲ୍ଟ ଭାବେ ଚାଲୁ; `false` ସାଧାରଣ ଚୟନକୁ ପୁନଃସ୍ଥାପନ କରେ।", - "featureFlagProxyPoolSharedEgressOrderDescription": "ଯେଉଁ ପ୍ରୋଭାଇଡର୍‌ମାନଙ୍କର କୋଟା egress address ଦ୍ୱାରା ବକେଟ୍ ହୋଇଛି, ସେମାନଙ୍କ ପାଇଁ ନିକଟରେ ପ୍ରତ୍ୟାଖ୍ୟାତ ହୋଇଥିବା ସଦସ୍ୟଙ୍କ ନିରୀକ୍ଷିତ egress address ସେୟାର କରୁଥିବା ପୁଲ୍ ସଦସ୍ୟଙ୍କୁ ସୁସ୍ଥ ସଦସ୍ୟମାନଙ୍କ ଠିକ୍ ତଳେ ସ୍ଥାନିତ କରନ୍ତୁ। କେବଳ କ୍ରମ, କେବେ ବି ବାଦ ଦିଆଯାଏ ନାହିଁ। PROXY_SKIP_RECENTLY_FAILED ଆବଶ୍ୟକ, ଯାହା ଏହା ପଢ଼ୁଥିବା ପ୍ରତ୍ୟାଖ୍ୟାନ ସିଗନାଲ୍ ଉତ୍ପନ୍ନ କରେ। ଡିଫଲ୍ଟ ଭାବରେ ବନ୍ଦ: ଚୟନ କ୍ରମ ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ସାଧାରଣ ଘୂର୍ଣ୍ଣନ ଅଟେ।", "featureFlagProxyPoolEgressObservationDescription": "ଡ୍ୟାସବୋର୍ଡରେ ଗୋଟିଏ ପ୍ରକ୍ସି ପୁଲ୍ ଅଧୀନରେ, ଗତ 24 ଘଣ୍ଟାରେ କେତୋଟି ପର୍ଯ୍ୟବେକ୍ଷିତ ଏଗ୍ରେସ୍ IP ଏହାର ସଦସ୍ୟମାନଙ୍କୁ ସେବା ଦେଇଥିଲା, କେତୋଟି ସଂଯୋଗ ସେଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିଥିଲା ଏବଂ ଗୋଟିଏ IP ପଛରେ ସର୍ବାଧିକ କେତୋଟି ଦେଖାଯାଇଥିଲା, ତାହା ଦେଖାନ୍ତୁ। କେବଳ ପଠନୀୟ, ପ୍ରକ୍ସି ଲଗ୍ରୁ ଗଣନା କରାଯାଏ, ରାଉଟିଂ ପାଇଁ କେବେ ବ୍ୟବହୃତ ହୁଏ ନାହିଁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: ପୁଲ୍ ଏଡିଟର୍ ଅପରିବର୍ତ୍ତିତ ରହେ ଏବଂ ପର୍ଯ୍ୟବେକ୍ଷଣ ରୁଟ୍ null ଉତ୍ତର ଦିଏ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "ପ୍ରକ୍ସି ସ୍ୱାସ୍ଥ୍ୟ ଯାଞ୍ଚରେ, ଲକ୍ଷ୍ୟ ଦ୍ୱାରା ପ୍ରତ୍ୟାଖ୍ୟାନ ହୋଇଥିବା ପ୍ରୋବ୍କୁ (401/403/429: ପ୍ରକ୍ସି ରିଲେ କରିଥିଲା, ଗନ୍ତବ୍ୟସ୍ଥଳ ଏହି ଏଗ୍ରେସ୍ IPକୁ ପ୍ରତ୍ୟାଖ୍ୟାନ କରିଥିଲା) ଏକ ସେବା ପ୍ରଦାନ କରାଯାଇଥିବା ପ୍ରୋବ୍ ପରି ପ୍ରକ୍ସିର କ୍ରମାଗତ ବିଫଳତା ଧାରାକୁ ରିସେଟ୍ କରିବାକୁ ଦିଅନ୍ତୁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: ଏକ ପ୍ରତ୍ୟାଖ୍ୟାନ ନିରପେକ୍ଷ ରହେ ଏବଂ ଧାରାକୁ ଅପରିବର୍ତ୍ତିତ ରଖେ। ଉଭୟ କ୍ଷେତ୍ରରେ 5xx ଅନିର୍ଣ୍ଣାୟକ ରହେ, ଏବଂ ଏକ ପ୍ରତ୍ୟାଖ୍ୟାନ କେବେ ମଧ୍ୟ ପ୍ରକ୍ସିକୁ ହଟାଏ, ଅକ୍ଷମ କରେ କିମ୍ବା ପୁନଃସକ୍ରିୟ କରେ ନାହିଁ।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ସ୍ୱୟଂଚାଳିତ କ୍ଲିନଅପ୍ ସ୍ୱିପ୍କୁ OMNIROUTE_BATCH_RETENTION_DAYS ଠାରୁ ପୁରୁଣା ଟର୍ମିନାଲ୍ (ସମ୍ପୂର୍ଣ୍ଣ/ବିଫଳ/ବାତିଲ୍/ମିଆଦ ଶେଷ) Batch API କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ସେମାନଙ୍କର ପ୍ରତି-ଧାଡ଼ି ଚେକ୍ପଏଣ୍ଟ ସହିତ ଡିଲିଟ୍ କରିବାକୁ ଏବଂ ଅପଲୋଡ୍ ହୋଇଥିବା ଫାଇଲ୍ଗୁଡ଼ିକର ନିଜସ୍ୱ expires_at ଅତିକ୍ରମ ହେବା ପରେ ସେମାନଙ୍କ BLOB ବିଷୟବସ୍ତୁ ସଫା କରିବାକୁ ଦିଅନ୍ତୁ। ଡିଫଲ୍ଟ ଭାବେ ବନ୍ଦ: କୌଣସି ଅପରେଟର୍ ଏହାକୁ ସକ୍ରିୟ ନ କରିବା ପର୍ଯ୍ୟନ୍ତ ପ୍ରତ୍ୟେକ ବିଦ୍ୟମାନ ଇନ୍ଷ୍ଟଲେସନ୍ ଏହି ଡାଟାକୁ ପୂର୍ବପରି ଠିକ୍ ସେହିଭଳି ରଖିଥାଏ। ଅପରେଟର୍ ଦ୍ୱାରା ଟ୍ରିଗର୍ ହେଉଥିବା DELETE /api/v1/batches/delete-completed ରୁଟ୍ ଉଭୟ କ୍ଷେତ୍ରରେ ଅପ୍ରଭାବିତ ରହେ — ଏହା ଏକ ପୃଥକ, ସର୍ତ୍ତହୀନ ସାର୍ବଜନୀନ API ଚୁକ୍ତି।", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "ଅପଡେଟ୍ ଉପଲବ୍ଧ: v{current} → v{latest}", "cliproxyapiVersion": "ସଂସ୍କରଣ" }, + "modelCatalog": { + "title": "ମଡେଲ୍ ଏବଂ କମ୍ବୋ", + "subtitle": "ପ୍ରତ୍ୟେକ ପ୍ରଦାନକାରୀଙ୍କ ମଧ୍ୟରେ ମଡେଲ୍ ଏବଂ କମ୍ବୋ ରାଉଟିଂ ପାଇପଲାଇନଗୁଡ଼ିକୁ ବ୍ରାଉଜ୍ କରନ୍ତୁ ଏବଂ ହେଲଥ୍-ପରୀକ୍ଷା କରନ୍ତୁ।", + "refresh": "ରିଫ୍ରେଶ୍ କରନ୍ତୁ", + "modelsTab": "ମଡେଲ୍", + "combosTab": "କମ୍ବୋ", + "catalogSections": "କାଟାଲଗ୍ ବିଭାଗ", + "loading": "ଲୋଡ୍ ହେଉଛି...", + "retry": "ପୁନଃଚେଷ୍ଟା କରନ୍ତୁ", + "unableToLoad": "ମଡେଲ୍ କାଟାଲଗ୍ ଲୋଡ୍ କରିବାରେ ଅସମର୍ଥ।", + "unableToLoadCombos": "କମ୍ବୋ ଲୋଡ୍ କରିବାରେ ଅସମର୍ଥ।", + "checkConnection": "ସଂଯୋଗ ଯାଞ୍ଚ କରନ୍ତୁ ଏବଂ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।", + "noModelsAvailable": "ଏପର୍ଯ୍ୟନ୍ତ କୌଣସି ମଡେଲ୍ ଉପଲବ୍ଧ ନାହିଁ।", + "noModelsMatch": "ଏହି ଫିଲ୍ଟର୍ ସହିତ କୌଣସି ମଡେଲ୍ ମେଳ ଖାଉନାହିଁ।", + "noCombosAvailable": "ଏପର୍ଯ୍ୟନ୍ତ କୌଣସି କମ୍ବୋ ଉପଲବ୍ଧ ନାହିଁ।", + "noCombosMatch": "ଏହି ଫିଲ୍ଟର୍ ସହିତ କୌଣସି କମ୍ବୋ ମେଳ ଖାଉନାହିଁ।", + "clearFilters": "ଫିଲ୍ଟର୍ ହଟାନ୍ତୁ", + "searchModels": "ମଡେଲ୍ ସନ୍ଧାନ କରନ୍ତୁ", + "searchModelsPlaceholder": "ମଡେଲ୍, ପ୍ରଦାନକାରୀ କିମ୍ବା କ୍ଷମତା ଅନୁଯାୟୀ ସନ୍ଧାନ କରନ୍ତୁ", + "searchCombos": "କମ୍ବୋ ସନ୍ଧାନ କରନ୍ତୁ", + "searchCombosPlaceholder": "କମ୍ବୋ ନାମ, ମଡେଲ୍ କିମ୍ବା ବର୍ଣ୍ଣନା ଅନୁଯାୟୀ ସନ୍ଧାନ କରନ୍ତୁ", + "modelCountSingle": "ମଡେଲ୍", + "modelCountPlural": "ମଡେଲଗୁଡ଼ିକ", + "comboCountSingle": "କମ୍ବୋ", + "comboCountPlural": "କମ୍ବୋଗୁଡ଼ିକ", + "provider": "ପ୍ରଦାନକାରୀ", + "allProviders": "ସମସ୍ତ ପ୍ରଦାନକାରୀ", + "type": "ପ୍ରକାର", + "allTypes": "ସମସ୍ତ ପ୍ରକାର", + "subtype": "ଉପ-ପ୍ରକାର", + "allSubtypes": "ସମସ୍ତ ଉପ-ପ୍ରକାର", + "capability": "କ୍ଷମତା", + "allCapabilities": "ସମସ୍ତ କ୍ଷମତା", + "pricing": "ମୂଲ୍ୟ ନିର୍ଦ୍ଧାରଣ", + "allPricing": "ସମସ୍ତ ମୂଲ୍ୟ", + "freeOnly": "କେବଳ ମାଗଣା", + "nonFree": "ଷ୍ଟାଣ୍ଡାର୍ଡ / ଅଣ-ମାଗଣା", + "providerHealth": "ପ୍ରଦାନକାରୀ ସ୍ୱାସ୍ଥ୍ୟ", + "allHealthStates": "ସମସ୍ତ ସ୍ୱାସ୍ଥ୍ୟ ସ୍ଥିତି", + "healthy": "ସୁସ୍ଥ", + "degraded": "ଅବନତିପ୍ରାପ୍ତ", + "down": "ଡାଉନ୍", + "testResult": "ପରୀକ୍ଷା ଫଳାଫଳ", + "allResults": "ସମସ୍ତ ଫଳାଫଳ", + "untested": "ଅପରୀକ୍ଷିତ", + "statusOk": "ଠିକ୍ ଅଛି", + "statusSlow": "ଧୀର", + "statusError": "ତ୍ରୁଟି", + "minContext": "ସର୍ବନିମ୍ନ ପ୍ରସଙ୍ଗ", + "minContextPlaceholder": "ଉଦା. 32000", + "strategy": "ରଣନୀତି", + "allStrategies": "ସମସ୍ତ ରଣନୀତି", + "status": "ସ୍ଥିତି", + "allStatuses": "ସମସ୍ତ ସ୍ଥିତି", + "active": "ସକ୍ରିୟ", + "paused": "ସ୍ଥଗିତ", + "minMembers": "ସର୍ବନିମ୍ନ ସଦସ୍ୟ", + "minMembersPlaceholder": "ଉଦା. 1", + "maxMembers": "ସର୍ବାଧିକ ସଦସ୍ୟ", + "maxMembersPlaceholder": "ଉଦା. 10", + "testSelected": "ମନୋନୀତ ପରୀକ୍ଷା କରନ୍ତୁ ({count})", + "testAllFiltered": "ଫିଲ୍ଟର୍ ହୋଇଥିବା ସମସ୍ତ ପରୀକ୍ଷା କରନ୍ତୁ ({count})", + "cancel": "ବାତିଲ କରନ୍ତୁ", + "clearResults": "ଫଳାଫଳ ଖାଲି କରନ୍ତୁ", + "testing": "ପରୀକ୍ଷା କରାଯାଉଛି...", + "rateLimited": "ରେଟ୍ ସୀମିତ", + "quotaExceeded": "କୋଟା ସମାପ୍ତ", + "timeout": "ସମୟ ସମାପ୍ତ", + "otherError": "ତ୍ରୁଟି", + "justNow": "ଏହିମାତ୍ର", + "minutesAgo": "{count}m ପୂର୍ବରୁ", + "hoursAgo": "{count}h ପୂର୍ବରୁ", + "tableRegion": "ମଡେଲ୍ କାଟାଲଗ୍ ଟେବୁଲ୍", + "combosTableRegion": "କମ୍ବୋ କାଟାଲଗ୍ ଟେବୁଲ୍", + "tableCaption": "ସମସ୍ତ ପ୍ରଦାନକାରୀଙ୍କ ମଧ୍ୟରେ ମଡେଲ୍ କାଟାଲଗ୍", + "combosTableCaption": "ସ୍ୱାସ୍ଥ୍ୟ ପରୀକ୍ଷା ଫଳାଫଳ ସହିତ କମ୍ବୋ କାଟାଲଗ୍", + "selectAllModels": "ଏହି ପୃଷ୍ଠାର ସମସ୍ତ ମଡେଲ୍ ଚୟନ କରନ୍ତୁ", + "selectAllCombos": "ଏହି ପୃଷ୍ଠାର ସମସ୍ତ କମ୍ବୋ ଚୟନ କରନ୍ତୁ", + "selectModel": "ମଡେଲ୍ {name} ଚୟନ କରନ୍ତୁ", + "selectCombo": "କମ୍ବୋ {name} ଚୟନ କରନ୍ତୁ", + "model": "ମଡେଲ୍", + "capabilities": "କ୍ଷମତାଗୁଡ଼ିକ", + "context": "ପ୍ରସଙ୍ଗ", + "output": "ସର୍ବାଧିକ ଆଉଟପୁଟ୍", + "flags": "ଫ୍ଲାଗ୍‌ଗୁଡ଼ିକ", + "healthTest": "ସ୍ୱାସ୍ଥ୍ୟ ପରୀକ୍ଷା", + "actions": "କାର୍ଯ୍ୟଗୁଡ଼ିକ", + "test": "ପରୀକ୍ଷା", + "custom": "କଷ୍ଟମ୍", + "free": "ମାଗଣା", + "noFlags": "କୌଣସି ମୂଲ୍ୟ କିମ୍ବା ଉତ୍ସ ଫ୍ଲାଗ୍ ରିପୋର୍ଟ ହୋଇନାହିଁ", + "noCapabilities": "କୌଣସି କ୍ଷମତା ମେଟାଡାଟା ରିପୋର୍ଟ ହୋଇନାହିଁ", + "showingModels": "{total} ମଡେଲ ମଧ୍ୟରୁ {first}–{last} ଦେଖାଉଛି", + "showingCombos": "{total} କମ୍ବୋ ମଧ୍ୟରୁ {first}–{last} ଦେଖାଉଛି", + "refreshing": "ରିଫ୍ରେଶ୍ ହେଉଛି…", + "refreshFailed": "ରିଫ୍ରେଶ୍ ବିଫଳ ହୋଇଛି। ଶେଷ ଥର ଲୋଡ୍ ହୋଇଥିବା କାଟାଲଗ୍ ଦେଖାଉଛି।", + "page": "{pageCount} ର ପୃଷ୍ଠା {page}", + "previous": "ପୂର୍ବବର୍ତ୍ତୀ", + "next": "ପରବର୍ତ୍ତୀ", + "combo": "କମ୍ବୋ", + "members": "ସଦସ୍ୟ", + "moreMembers": "+{count} ଅଧିକ" + }, "combos": { "title": "କମ୍ବୋଗୁଡ଼ିକ", "description": "ଓଜନ-ଆଧାରିତ ରାଉଟିଂ ଏବଂ ଫଲ୍ବ୍ୟାକ୍ ସମର୍ଥନ ସହିତ ମଡେଲ୍ କମ୍ବୋ ତିଆରି କରନ୍ତୁ", diff --git a/src/i18n/messages/pa.json b/src/i18n/messages/pa.json index b18bf4d06e13..98cdc6a30038 100644 --- a/src/i18n/messages/pa.json +++ b/src/i18n/messages/pa.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ਪ੍ਰਦਾਤਾ ਡਿਸਪੈਚ (#9654) ਲਈ ਪ੍ਰਤੀ-ਟੈਨੈਂਟ ਅਨੁਕੂਲ ਵਰਚੁਅਲ ਐਡਮਿਸ਼ਨ ਲੇਨ ਸਮਰੱਥ ਕਰੋ: ਹੁਣ ਇੱਕ ਟੈਨੈਂਟ ਦਾ ਅਚਾਨਕ ਵਧਿਆ ਲੋਡ ਦੂਜੇ ਲਈ 503 ਪੈਦਾ ਨਹੀਂ ਕਰੇਗਾ। OMNIROUTE_CHAT_VIRTUAL_LANES env var ਨੂੰ ਇਸ ਡੈਸ਼ਬੋਰਡ ਓਵਰਰਾਈਡ ਉੱਤੇ ਤਰਜੀਹ ਮਿਲਦੀ ਹੈ; ਤਬਦੀਲੀਆਂ ਸਰਵਰ ਮੁੜ ਚਾਲੂ ਹੋਣ 'ਤੇ ਲਾਗੂ ਹੁੰਦੀਆਂ ਹਨ।", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ਡੈਸ਼ਬੋਰਡ ਪ੍ਰਦਾਤਾ ਪੰਨੇ: ਮੁਫ਼ਤ ਬੈਜ ਸਿਰਫ਼ ਉਹਨਾਂ ਸੰਕੇਤਾਂ ਉੱਤੇ ਦਿਖਾਓ ਜਿਨ੍ਹਾਂ ਨੂੰ ਪ੍ਰਦਾਤਾ ਮੰਨਦਾ ਹੈ — ਇਹ ਡਿਸਪਲੇ-ਨਾਮ ਅਨੁਮਾਨ, ਗੈਰ-ਬੂਲੀਅਨ free ਫ਼ੀਲਡਾਂ ਅਤੇ ਬਿਨਾਂ ਦਸਤਾਵੇਜ਼ਬੱਧ ਮੁਫ਼ਤ ਟੀਅਰ ਵਾਲੇ ਰਜਿਸਟਰਡ ਪ੍ਰਦਾਤਾਵਾਂ ਉੱਤੇ :free ਪਿਛੇਤਰਾਂ ਨੂੰ ਹਟਾਉਂਦਾ ਹੈ। ਬੰਦ ਹੋਣ ਉੱਤੇ ਪੁਰਾਣਾ ਬੈਜ ਨਿਯਮ ਬਰਕਰਾਰ ਰਹਿੰਦਾ ਹੈ।", "featureFlagProxySkipRecentlyFailedDescription": "Proxy ਪੂਲ ਅਤੇ opencode ਦੀ ਪ੍ਰਤੀ-ਖਾਤਾ ਰੋਟੇਸ਼ਨ ਉਸ Proxy ਨੂੰ ਮੁੜ ਵਰਤਣਾ ਬੰਦ ਕਰ ਦਿੰਦੇ ਹਨ ਜੋ ਹੁਣੇ ਅਸਫਲ ਹੋਇਆ ਹੈ (TCP ਪ੍ਰੋਬ ਅਸਵੀਕਾਰ ਹੋਈ, ਜਾਂ ਇਸ ਰਾਹੀਂ 429 ਮਿਲਿਆ), ਇੱਕ ਪ੍ਰਤੀ-ਪ੍ਰਕਿਰਿਆ ਮਿਆਦ ਲਈ ਜੋ ਹਰ ਦੁਹਰਾਅ ਨਾਲ ਦੁੱਗਣੀ ਹੁੰਦੀ ਹੈ, ਇੱਕ ਅਧਿਕਤਮ ਹੱਦ ਤੱਕ। ਕੋਈ Proxy ਸਥਿਤੀ ਲਿਖੀ ਨਹੀਂ ਜਾਂਦੀ; ਹਰ ਉਮੀਦਵਾਰ ਨੂੰ ਪਾਸੇ ਰੱਖਣ ’ਤੇ ਚੋਣ ਬਦਲਦੀ ਨਹੀਂ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਚਾਲੂ; `false` ਸਧਾਰਨ ਚੋਣ ਨੂੰ ਬਹਾਲ ਕਰਦਾ ਹੈ।", - "featureFlagProxyPoolSharedEgressOrderDescription": "ਉਹਨਾਂ ਪ੍ਰੋਵਾਈਡਰਾਂ ਲਈ ਜਿਨ੍ਹਾਂ ਦਾ ਕੋਟਾ egress ਐਡਰੈੱਸ ਅਨੁਸਾਰ ਬਕੇਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਹਾਲ ਹੀ ਵਿੱਚ ਅਸਵੀਕਾਰ ਕੀਤੇ ਗਏ ਮੈਂਬਰ ਦਾ ਦੇਖਿਆ ਗਿਆ egress ਐਡਰੈੱਸ ਸਾਂਝਾ ਕਰਨ ਵਾਲੇ ਪੂਲ ਮੈਂਬਰ ਨੂੰ ਸਿਹਤਮੰਦ ਮੈਂਬਰਾਂ ਤੋਂ ਠੀਕ ਹੇਠਾਂ ਰੈਂਕ ਕਰੋ। ਸਿਰਫ਼ ਕ੍ਰਮ ਲਈ, ਕਦੇ ਬਾਹਰ ਨਹੀਂ ਕੱਢਿਆ ਜਾਂਦਾ। PROXY_SKIP_RECENTLY_FAILED ਦੀ ਲੋੜ ਹੈ, ਜੋ ਅਸਵੀਕਾਰ ਸਿਗਨਲ ਤਿਆਰ ਕਰਦਾ ਹੈ ਜਿਸਨੂੰ ਇਹ ਪੜ੍ਹਦਾ ਹੈ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਚੋਣ ਕ੍ਰਮ ਬਿਲਕੁਲ ਸਾਧਾਰਨ ਰੋਟੇਸ਼ਨ ਹੈ।", "featureFlagProxyPoolEgressObservationDescription": "ਡੈਸ਼ਬੋਰਡ ਵਿੱਚ ਕਿਸੇ Proxy ਪੂਲ ਹੇਠ ਦਿਖਾਓ ਕਿ ਪਿਛਲੇ 24 ਘੰਟਿਆਂ ਦੌਰਾਨ ਕਿੰਨੇ ਦੇਖੇ ਗਏ egress IPs ਨੇ ਇਸ ਦੇ ਮੈਂਬਰਾਂ ਨੂੰ ਸੇਵਾ ਦਿੱਤੀ, ਕਿੰਨੇ ਕਨੈਕਸ਼ਨਾਂ ਨੇ ਉਨ੍ਹਾਂ ਨੂੰ ਵਰਤਿਆ ਅਤੇ ਇੱਕ IP ਦੇ ਪਿੱਛੇ ਸਭ ਤੋਂ ਵੱਧ ਕਿੰਨੇ ਦੇਖੇ ਗਏ। ਕੇਵਲ ਪੜ੍ਹਨਯੋਗ, Proxy ਲੌਗ ਤੋਂ ਗਣਨਾ ਕੀਤੀ ਗਈ, ਰੂਟਿੰਗ ਲਈ ਕਦੇ ਨਹੀਂ ਵਰਤੀ ਜਾਂਦੀ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਪੂਲ ਸੰਪਾਦਕ ਬਦਲਦਾ ਨਹੀਂ ਹੈ ਅਤੇ ਨਿਰੀਖਣ ਰੂਟ null ਜਵਾਬ ਦਿੰਦਾ ਹੈ।", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ਸਿਹਤ ਜਾਂਚ ਵਿੱਚ, ਟਾਰਗੇਟ ਵੱਲੋਂ ਅਸਵੀਕਾਰ ਕੀਤੀ ਪ੍ਰੋਬ (401/403/429: Proxy ਨੇ ਅੱਗੇ ਭੇਜਿਆ, ਮੰਜ਼ਿਲ ਨੇ ਇਸ egress IP ਨੂੰ ਅਸਵੀਕਾਰ ਕੀਤਾ) ਨੂੰ, ਸਫਲਤਾਪੂਰਵਕ ਸੇਵਾ ਕੀਤੀ ਪ੍ਰੋਬ ਵਾਂਗ, Proxy ਦੀ ਲਗਾਤਾਰ ਅਸਫਲਤਾ ਲੜੀ ਰੀਸੈੱਟ ਕਰਨ ਦਿਓ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਅਸਵੀਕਾਰਤਾ ਨਿਰਪੱਖ ਰਹਿੰਦੀ ਹੈ ਅਤੇ ਲੜੀ ਨੂੰ ਕਾਇਮ ਰੱਖਦੀ ਹੈ। 5xx ਦੋਵਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਅਨਿਰਣਾਇਕ ਰਹਿੰਦਾ ਹੈ, ਅਤੇ ਅਸਵੀਕਾਰਤਾ ਕਦੇ ਵੀ ਕਿਸੇ Proxy ਨੂੰ ਹਟਾਉਂਦੀ, ਅਯੋਗ ਜਾਂ ਮੁੜ ਸਰਗਰਮ ਨਹੀਂ ਕਰਦੀ।", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ਆਟੋਮੈਟਿਕ ਕਲੀਨਅੱਪ ਸਵੀਪ ਨੂੰ OMNIROUTE_BATCH_RETENTION_DAYS ਤੋਂ ਪੁਰਾਣੀਆਂ ਟਰਮੀਨਲ (ਪੂਰੀਆਂ/ਅਸਫਲ/ਰੱਦ/ਮਿਆਦ ਪੁੱਗੀਆਂ) Batch API ਜੌਬਾਂ ਨੂੰ, ਉਨ੍ਹਾਂ ਦੇ ਪ੍ਰਤੀ-ਲਾਈਨ ਚੈਕਪੌਇੰਟਾਂ ਸਮੇਤ, ਮਿਟਾਉਣ ਦਿਓ ਅਤੇ ਆਪਣੀ expires_at ਮਿਆਦ ਲੰਘਾ ਚੁੱਕੀਆਂ ਅੱਪਲੋਡ ਕੀਤੀਆਂ ਫ਼ਾਈਲਾਂ ਦੀ BLOB ਸਮੱਗਰੀ ਸਾਫ਼ ਕਰੋ। ਮੂਲ ਰੂਪ ਵਿੱਚ ਬੰਦ: ਜਦੋਂ ਤੱਕ ਕੋਈ ਓਪਰੇਟਰ ਇਸਨੂੰ ਚਾਲੂ ਕਰਨ ਦੀ ਚੋਣ ਨਹੀਂ ਕਰਦਾ, ਹਰ ਮੌਜੂਦਾ ਇੰਸਟਾਲੇਸ਼ਨ ਇਹ ਡਾਟਾ ਬਿਲਕੁਲ ਪਹਿਲਾਂ ਵਾਂਗ ਹੀ ਰੱਖਦੀ ਹੈ। ਓਪਰੇਟਰ ਵੱਲੋਂ ਸ਼ੁਰੂ ਕੀਤਾ ਗਿਆ DELETE /api/v1/batches/delete-completed ਰੂਟ ਦੋਵਾਂ ਹਾਲਤਾਂ ਵਿੱਚ ਪ੍ਰਭਾਵਿਤ ਨਹੀਂ ਹੁੰਦਾ — ਇਹ ਇੱਕ ਵੱਖਰਾ, ਬਿਨਾਂ ਸ਼ਰਤ ਵਾਲਾ ਜਨਤਕ API ਇਕਰਾਰਨਾਮਾ ਹੈ।", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "ਅੱਪਡੇਟ ਉਪਲਬਧ ਹੈ: v{current} → v{latest}", "cliproxyapiVersion": "ਵਰਜਨ" }, + "modelCatalog": { + "title": "ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼", + "subtitle": "ਹਰੇਕ ਪ੍ਰੋਵਾਈਡਰ ਦੇ ਮਾਡਲਾਂ ਅਤੇ ਕੰਬੋ ਰੂਟਿੰਗ ਪਾਈਪਲਾਈਨਾਂ ਨੂੰ ਬ੍ਰਾਊਜ਼ ਕਰੋ ਅਤੇ ਉਹਨਾਂ ਦਾ ਹੈਲਥ-ਟੈਸਟ ਕਰੋ।", + "refresh": "ਤਾਜ਼ਾ ਕਰੋ", + "modelsTab": "ਮਾਡਲ", + "combosTab": "ਕੰਬੋਜ਼", + "catalogSections": "ਕੈਟਾਲਾਗ ਸੈਕਸ਼ਨ", + "loading": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ...", + "retry": "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ", + "unableToLoad": "ਮਾਡਲ ਕੈਟਾਲਾਗ ਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਮਰੱਥ।", + "unableToLoadCombos": "ਕੰਬੋਜ਼ ਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਮਰੱਥ।", + "checkConnection": "ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", + "noModelsAvailable": "ਅਜੇ ਕੋਈ ਮਾਡਲ ਉਪਲਬਧ ਨਹੀਂ ਹਨ।", + "noModelsMatch": "ਕੋਈ ਵੀ ਮਾਡਲ ਇਹਨਾਂ ਫਿਲਟਰਾਂ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ।", + "noCombosAvailable": "ਅਜੇ ਕੋਈ ਕੰਬੋ ਉਪਲਬਧ ਨਹੀਂ ਹਨ।", + "noCombosMatch": "ਕੋਈ ਵੀ ਕੰਬੋ ਇਹਨਾਂ ਫਿਲਟਰਾਂ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ।", + "clearFilters": "ਫਿਲਟਰ ਸਾਫ਼ ਕਰੋ", + "searchModels": "ਮਾਡਲ ਖੋਜੋ", + "searchModelsPlaceholder": "ਮਾਡਲ, ਪ੍ਰੋਵਾਈਡਰ ਜਾਂ ਸਮਰੱਥਾ ਅਨੁਸਾਰ ਖੋਜੋ", + "searchCombos": "ਕੰਬੋਜ਼ ਖੋਜੋ", + "searchCombosPlaceholder": "ਕੰਬੋ ਦੇ ਨਾਮ, ਮਾਡਲਾਂ ਜਾਂ ਵਰਣਨ ਅਨੁਸਾਰ ਖੋਜੋ", + "modelCountSingle": "ਮਾਡਲ", + "modelCountPlural": "ਮਾਡਲ", + "comboCountSingle": "ਕੰਬੋ", + "comboCountPlural": "ਕੰਬੋਜ਼", + "provider": "ਪ੍ਰੋਵਾਈਡਰ", + "allProviders": "ਸਾਰੇ ਪ੍ਰੋਵਾਈਡਰ", + "type": "ਕਿਸਮ", + "allTypes": "ਸਾਰੀਆਂ ਕਿਸਮਾਂ", + "subtype": "ਉਪ-ਕਿਸਮ", + "allSubtypes": "ਸਾਰੀਆਂ ਉਪ-ਕਿਸਮਾਂ", + "capability": "ਸਮਰੱਥਾ", + "allCapabilities": "ਸਾਰੀਆਂ ਸਮਰੱਥਾਵਾਂ", + "pricing": "ਕੀਮਤ", + "allPricing": "ਸਾਰੀਆਂ ਕੀਮਤਾਂ", + "freeOnly": "ਸਿਰਫ਼ ਮੁਫ਼ਤ", + "nonFree": "ਸਟੈਂਡਰਡ / ਗੈਰ-ਮੁਫ਼ਤ", + "providerHealth": "ਪ੍ਰੋਵਾਈਡਰ ਦੀ ਸਿਹਤ", + "allHealthStates": "ਸਾਰੀਆਂ ਸਿਹਤ ਸਥਿਤੀਆਂ", + "healthy": "ਸਿਹਤਮੰਦ", + "degraded": "ਡੀਗ੍ਰੇਡਿਡ", + "down": "ਡਾਊਨ", + "testResult": "ਟੈਸਟ ਦਾ ਨਤੀਜਾ", + "allResults": "ਸਾਰੇ ਨਤੀਜੇ", + "untested": "ਅਣ-ਟੈਸਟ ਕੀਤਾ", + "statusOk": "ਠੀਕ ਹੈ", + "statusSlow": "ਹੌਲੀ", + "statusError": "ਗਲਤੀ", + "minContext": "ਘੱਟੋ-ਘੱਟ ਸੰਦਰਭ", + "minContextPlaceholder": "ਜਿਵੇਂ ਕਿ 32000", + "strategy": "ਰਣਨੀਤੀ", + "allStrategies": "ਸਾਰੀਆਂ ਰਣਨੀਤੀਆਂ", + "status": "ਸਥਿਤੀ", + "allStatuses": "ਸਾਰੀਆਂ ਸਥਿਤੀਆਂ", + "active": "ਸਰਗਰਮ", + "paused": "ਰੋਕਿਆ ਗਿਆ", + "minMembers": "ਘੱਟੋ-ਘੱਟ ਮੈਂਬਰ", + "minMembersPlaceholder": "ਜਿਵੇਂ ਕਿ 1", + "maxMembers": "ਵੱਧ ਤੋਂ ਵੱਧ ਮੈਂਬਰ", + "maxMembersPlaceholder": "ਜਿਵੇਂ ਕਿ 10", + "testSelected": "ਚੁਣੇ ਹੋਏ ਟੈਸਟ ਕਰੋ ({count})", + "testAllFiltered": "ਸਾਰੇ ਫਿਲਟਰ ਕੀਤੇ ਟੈਸਟ ਕਰੋ ({count})", + "cancel": "ਰੱਦ ਕਰੋ", + "clearResults": "ਨਤੀਜੇ ਸਾਫ਼ ਕਰੋ", + "testing": "ਟੈਸਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "rateLimited": "ਰੇਟ ਸੀਮਿਤ", + "quotaExceeded": "ਕੋਟਾ ਸਮਾਪਤ", + "timeout": "ਸਮਾਂ ਸਮਾਪਤ", + "otherError": "ਗਲਤੀ", + "justNow": "ਹੁਣੇ", + "minutesAgo": "{count}m ਪਹਿਲਾਂ", + "hoursAgo": "{count}h ਪਹਿਲਾਂ", + "tableRegion": "ਮਾਡਲ ਕੈਟਾਲਾਗ ਸਾਰਣੀ", + "combosTableRegion": "ਕੰਬੋਜ਼ ਕੈਟਾਲਾਗ ਸਾਰਣੀ", + "tableCaption": "ਸਾਰੇ ਪ੍ਰਦਾਤਾਵਾਂ ਵਿੱਚ ਮਾਡਲ ਕੈਟਾਲਾਗ", + "combosTableCaption": "ਹੈਲਥ ਟੈਸਟ ਨਤੀਜਿਆਂ ਸਮੇਤ ਕੰਬੋਜ਼ ਕੈਟਾਲਾਗ", + "selectAllModels": "ਇਸ ਪੰਨੇ 'ਤੇ ਸਾਰੇ ਮਾਡਲ ਚੁਣੋ", + "selectAllCombos": "ਇਸ ਪੰਨੇ 'ਤੇ ਸਾਰੇ ਕੰਬੋਜ਼ ਚੁਣੋ", + "selectModel": "ਮਾਡਲ {name} ਚੁਣੋ", + "selectCombo": "ਕੰਬੋ {name} ਚੁਣੋ", + "model": "ਮਾਡਲ", + "capabilities": "ਸਮਰੱਥਾਵਾਂ", + "context": "ਸੰਦਰਭ", + "output": "ਵੱਧ ਤੋਂ ਵੱਧ ਆਉਟਪੁੱਟ", + "flags": "ਫਲੈਗ", + "healthTest": "ਸਿਹਤ ਜਾਂਚ", + "actions": "ਕਾਰਵਾਈਆਂ", + "test": "ਟੈਸਟ", + "custom": "ਕਸਟਮ", + "free": "ਮੁਫ਼ਤ", + "noFlags": "ਕੋਈ ਕੀਮਤ ਜਾਂ ਸਰੋਤ ਫਲੈਗ ਰਿਪੋਰਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ", + "noCapabilities": "ਕੋਈ ਸਮਰੱਥਾ ਮੈਟਾਡੇਟਾ ਰਿਪੋਰਟ ਨਹੀਂ ਕੀਤਾ ਗਿਆ", + "showingModels": "{total} ਵਿੱਚੋਂ {first}–{last} ਮਾਡਲ ਦਿਖਾ ਰਿਹਾ ਹੈ", + "showingCombos": "{total} ਵਿੱਚੋਂ {first}–{last} ਕੰਬੋ ਦਿਖਾ ਰਿਹਾ ਹੈ", + "refreshing": "ਰਿਫ੍ਰੈਸ਼ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…", + "refreshFailed": "ਰਿਫ੍ਰੈਸ਼ ਅਸਫ਼ਲ ਰਿਹਾ। ਆਖਰੀ ਵਾਰ ਲੋਡ ਕੀਤਾ ਕੈਟਾਲਾਗ ਦਿਖਾਇਆ ਜਾ ਰਿਹਾ ਹੈ।", + "page": "{pageCount} ਵਿੱਚੋਂ ਪੰਨਾ {page}", + "previous": "ਪਿਛਲਾ", + "next": "ਅਗਲਾ", + "combo": "ਕੰਬੋ", + "members": "ਮੈਂਬਰ", + "moreMembers": "+{count} ਹੋਰ" + }, "combos": { "title": "ਕੌਂਬੋ", "description": "ਭਾਰਿਤ ਰਾਊਟਿੰਗ ਅਤੇ ਫਾਲਬੈਕ ਸਹਾਇਤਾ ਨਾਲ ਮਾਡਲ ਕੌਂਬੋ ਬਣਾਓ", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index 7f5fc585068f..b165b0d31051 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Paganahin ang adaptive virtual admission lanes para sa bawat tenant sa pagpapadala ng provider (#9654): ang pag-akyat ng trapiko ng isang tenant ay hindi na nagbibigay ng 503 sa iba. Ang environment variable na OMNIROUTE_CHAT_VIRTUAL_LANES ay mas nangingibabaw sa setting na ito sa dashboard; magkakabisa ang mga pagbabago sa pag-restart ng server.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Mga page ng provider sa Dashboard: ipakita lamang ang Libre na badge sa mga signal na kinikilala ng provider — inaalis nito ang heuristic ng display-name, mga non-boolean na free field, at mga :free suffix sa mga nakarehistrong provider na walang dokumentadong libreng tier. Kapag naka-off, pinananatili ang dating panuntunan sa badge.", "featureFlagProxySkipRecentlyFailedDescription": "Pinipigilan ng mga proxy pool at ng pag-ikot ng opencode sa bawat account na muling gumamit ng proxy na kabibigo lang (tinanggihan ang TCP probe, o nakatanggap ng 429 sa pamamagitan nito) sa loob ng isang panahon para sa bawat proseso na dumodoble sa bawat pag-ulit, hanggang sa itinakdang limitasyon. Walang isinusulat na status ng proxy; kapag isinantabi ang lahat ng kandidato, hindi nagbabago ang pagpili. Naka-on bilang default; ibinabalik ng `false` ang karaniwang pagpili.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Para sa mga provider na ang quota ay naka-bucket ayon sa egress address, i-rank ang isang pool member na kapareho ng naobserbahang egress address ng isang kamakailang tinanggihang miyembro sa ilalim lamang ng mga healthy na miyembro. Pagkakasunod-sunod lamang, hindi kailanman ibinubukod. Kinakailangan ang PROXY_SKIP_RECENTLY_FAILED, na bumubuo sa refusal signal na binabasa nito. Naka-off bilang default: ang pagkakasunod-sunod ng pagpili ay eksaktong karaniwang rotation.", "featureFlagProxyPoolEgressObservationDescription": "Ipakita sa ilalim ng isang proxy pool sa dashboard kung ilang naobserbahang egress IP ang ginamit ng mga miyembro nito sa nakalipas na 24 h, kung ilang koneksyon ang gumamit sa mga ito, at ang pinakamataas na bilang na nakita sa likod ng isang IP. Read-only, kinukuwenta mula sa proxy log, at hindi kailanman ginagamit sa pagruruta. Naka-off bilang default: hindi nagbabago ang editor ng pool at null ang isinasagot ng route ng obserbasyon.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Sa pagsusuri sa kalagayan ng proxy, hayaan ang isang probe na tinanggihan ng target (401/403/429: ipinasa ito ng proxy, ngunit tinanggihan ng destinasyon ang egress IP na ito) na i-reset ang sunod-sunod na pagkabigo ng proxy, tulad ng isang naihatid na probe. Naka-off bilang default: nananatiling neutral ang pagtanggi at hindi nito binabago ang sunod-sunod na pagkabigo. Nananatiling walang tiyak na resulta ang isang 5xx sa alinmang paraan, at ang pagtanggi ay hindi kailanman nag-aalis, nagdi-disable, o muling nag-a-activate ng proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Payagan ang awtomatikong cleanup sweep na burahin ang mga terminal (completed/failed/cancelled/expired) na Batch API job na mas luma kaysa OMNIROUTE_BATCH_RETENTION_DAYS, kasama ang kanilang mga checkpoint sa bawat linya, at i-clear ang BLOB content ng mga na-upload na file na lumampas na sa sarili nilang expires_at. Naka-off bilang default: pananatilihin ng bawat kasalukuyang install ang data na ito nang eksaktong gaya ng dati hanggang sa mag-opt in ang isang operator. Hindi maaapektuhan sa alinmang paraan ang route na DELETE /api/v1/batches/delete-completed na pinapagana ng operator -- isa itong hiwalay at walang-kondisyong pampublikong API contract.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Available na Update: v{current} → v{latest}", "cliproxyapiVersion": "Bersyon" }, + "modelCatalog": { + "title": "Mga Modelo at Combo", + "subtitle": "Mag-browse at mag-health-test ng mga modelo at combo routing pipeline sa bawat provider.", + "refresh": "I-refresh", + "modelsTab": "Mga Modelo", + "combosTab": "Mga Combo", + "catalogSections": "Mga Seksyon ng Catalog", + "loading": "Naglo-load...", + "retry": "Subukang muli", + "unableToLoad": "Hindi ma-load ang catalog ng modelo.", + "unableToLoadCombos": "Hindi ma-load ang mga combo.", + "checkConnection": "Suriin ang koneksyon at subukang muli.", + "noModelsAvailable": "Wala pang available na mga modelo.", + "noModelsMatch": "Walang mga modelong tumutugma sa mga filter na ito.", + "noCombosAvailable": "Wala pang available na mga combo.", + "noCombosMatch": "Walang mga combong tumutugma sa mga filter na ito.", + "clearFilters": "I-clear ang mga filter", + "searchModels": "Maghanap ng mga modelo", + "searchModelsPlaceholder": "Maghanap ayon sa modelo, provider, o kakayahan", + "searchCombos": "Maghanap ng mga combo", + "searchCombosPlaceholder": "Maghanap ayon sa pangalan ng combo, mga modelo, o paglalarawan", + "modelCountSingle": "modelo", + "modelCountPlural": "mga modelo", + "comboCountSingle": "combo", + "comboCountPlural": "mga combo", + "provider": "Provider", + "allProviders": "Lahat ng provider", + "type": "Uri", + "allTypes": "Lahat ng uri", + "subtype": "Subtype", + "allSubtypes": "Lahat ng subtype", + "capability": "Kakayahan", + "allCapabilities": "Lahat ng kakayahan", + "pricing": "Pagpepresyo", + "allPricing": "Lahat ng presyo", + "freeOnly": "Libre lamang", + "nonFree": "Standard / May bayad", + "providerHealth": "Kalusugan ng provider", + "allHealthStates": "Lahat ng estado ng kalusugan", + "healthy": "Maayos", + "degraded": "May degradasyon", + "down": "Hindi gumagana", + "testResult": "Resulta ng pagsubok", + "allResults": "Lahat ng resulta", + "untested": "Hindi pa nasusubukan", + "statusOk": "OK", + "statusSlow": "Mabagal", + "statusError": "Error", + "minContext": "Min na konteksto", + "minContextPlaceholder": "hal. 32000", + "strategy": "Estratehiya", + "allStrategies": "Lahat ng estratehiya", + "status": "Katayuan", + "allStatuses": "Lahat ng katayuan", + "active": "Aktibo", + "paused": "Naka-pause", + "minMembers": "Min na miyembro", + "minMembersPlaceholder": "hal. 1", + "maxMembers": "Max na miyembro", + "maxMembersPlaceholder": "hal. 10", + "testSelected": "Subukan ang napili ({count})", + "testAllFiltered": "Subukan ang lahat ng na-filter ({count})", + "cancel": "Kanselahin", + "clearResults": "I-clear ang mga resulta", + "testing": "Sinusubukan...", + "rateLimited": "Nalimitahan ang rate", + "quotaExceeded": "Lumampas sa quota", + "timeout": "Nag-time out", + "otherError": "Error", + "justNow": "Ngayon lang", + "minutesAgo": "{count}m ang nakalipas", + "hoursAgo": "{count}h ang nakalipas", + "tableRegion": "Talahanayan ng katalogo ng modelo", + "combosTableRegion": "Talahanayan ng katalogo ng mga combo", + "tableCaption": "Katalogo ng modelo sa lahat ng provider", + "combosTableCaption": "Katalogo ng mga combo na may mga resulta ng health test", + "selectAllModels": "Piliin ang lahat ng modelo sa pahinang ito", + "selectAllCombos": "Piliin ang lahat ng combo sa pahinang ito", + "selectModel": "Piliin ang modelong {name}", + "selectCombo": "Piliin ang combong {name}", + "model": "Modelo", + "capabilities": "Mga Kakayahan", + "context": "Konteksto", + "output": "Pinakamataas na output", + "flags": "Mga Flag", + "healthTest": "Pagsusuri sa Kalusugan", + "actions": "Mga Aksyon", + "test": "Subukan", + "custom": "Pinasadya", + "free": "Libre", + "noFlags": "Walang naiulat na presyo o source flag", + "noCapabilities": "Walang naiulat na metadata ng kakayahan", + "showingModels": "Ipinapakita ang {first}–{last} ng {total} na modelo", + "showingCombos": "Ipinapakita ang {first}–{last} ng {total} na combo", + "refreshing": "Nire-refresh…", + "refreshFailed": "Nabigo ang pag-refresh. Ipinapakita ang huling na-load na katalogo.", + "page": "Pahina {page} ng {pageCount}", + "previous": "Nakaraan", + "next": "Susunod", + "combo": "Combo", + "members": "Mga Miyembro", + "moreMembers": "+{count} pa" + }, "combos": { "title": "Mga combo", "description": "Gumawa ng mga combo ng modelo na may weighted routing at fallback support", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index 4c5c627eb667..84101ecfbd1e 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Włącz adaptacyjne wirtualne pasma przyjęć dla każdego tenanta przy wysyłce do dostawców (#9654): przeciążenie jednego tenanta nie powoduje już błędu 503 u innego. Zmienna środowiskowa OMNIROUTE_CHAT_VIRTUAL_LANES ma pierwszeństwo przed tym ustawieniem w panelu; zmiany wchodzą w życie po restarcie serwera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Strony dostawców w panelu: wyświetlaj odznakę „Bezpłatne” tylko na podstawie sygnałów uznawanych przez dostawcę — pomija heurystykę nazwy wyświetlanej, niebędące wartościami logicznymi pola dotyczące bezpłatności oraz sufiksy :free u zarejestrowanych dostawców bez udokumentowanej bezpłatnej warstwy. Wyłączenie zachowuje dotychczasową regułę wyświetlania odznaki.", "featureFlagProxySkipRecentlyFailedDescription": "Pule serwerów proxy oraz rotacja opencode dla poszczególnych kont przestają ponownie wybierać serwer proxy, który właśnie zawiódł (odrzucona próba TCP lub otrzymany za jego pośrednictwem kod 429), na okres właściwy dla danego procesu, który podwaja się przy każdym kolejnym takim zdarzeniu, aż do osiągnięcia limitu. Stan serwera proxy nie jest zapisywany; po odłożeniu na bok wszystkich kandydatów wybór pozostaje bez zmian. Domyślnie włączone; `false` przywraca zwykły wybór.", - "featureFlagProxyPoolSharedEgressOrderDescription": "W przypadku dostawców, których limit jest dzielony według adresu wyjściowego, umieszczaj członka puli współdzielącego zaobserwowany adres wyjściowy niedawno odrzuconego członka tuż za zdrowymi członkami. Tylko kolejność, nigdy nie wyklucza. Wymaga PROXY_SKIP_RECENTLY_FAILED, który generuje odczytywany sygnał odmowy. Domyślnie wyłączone: kolejność wyboru odpowiada dokładnie zwykłej rotacji.", "featureFlagProxyPoolEgressObservationDescription": "Wyświetla w panelu, pod pulą serwerów proxy, ile zaobserwowanych wychodzących adresów IP obsługiwało jej elementy w ciągu ostatnich 24 godz., ile połączeń z nich korzystało oraz największą liczbę połączeń za jednym adresem IP. Tylko do odczytu, obliczane na podstawie dziennika serwerów proxy i nigdy niewykorzystywane do routingu. Domyślnie wyłączone: edytor puli pozostaje bez zmian, a trasa obserwacji zwraca null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Podczas kontroli kondycji serwerów proxy pozwala, aby próba odrzucona przez cel (401/403/429: serwer proxy przekazał żądanie, ale miejsce docelowe odrzuciło ten wychodzący adres IP) resetowała serię kolejnych niepowodzeń serwera proxy, tak jak obsłużona próba. Domyślnie wyłączone: odrzucenie pozostaje neutralne i nie przerywa serii. Odpowiedź 5xx pozostaje nierozstrzygająca w obu przypadkach, a odrzucenie nigdy nie usuwa, nie wyłącza ani nie aktywuje ponownie serwera proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Pozwól automatycznemu czyszczeniu usuwać zadania Batch API w stanie końcowym (ukończone/nieudane/anulowane/wygasłe), starsze niż OMNIROUTE_BATCH_RETENTION_DAYS, wraz z ich punktami kontrolnymi dla poszczególnych wierszy oraz czyścić zawartość BLOB przesłanych plików po upływie ich własnego terminu expires_at. Domyślnie wyłączone: każda istniejąca instalacja przechowuje te dane dokładnie tak jak wcześniej, dopóki operator nie włączy tej opcji. Wywoływana przez operatora trasa DELETE /api/v1/batches/delete-completed pozostaje niezależnie od tego bez zmian — jest to osobny, bezwarunkowy kontrakt publicznego API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Dostępna aktualizacja: v{current} → v{latest}", "cliproxyapiVersion": "Wersja" }, + "modelCatalog": { + "title": "Modele i zestawy", + "subtitle": "Przeglądaj i testuj stan modeli oraz potoków routingu zestawów u wszystkich dostawców.", + "refresh": "Odśwież", + "modelsTab": "Modele", + "combosTab": "Zestawy", + "catalogSections": "Sekcje katalogu", + "loading": "Ładowanie...", + "retry": "Ponów próbę", + "unableToLoad": "Nie udało się załadować katalogu modeli.", + "unableToLoadCombos": "Nie udało się załadować zestawów.", + "checkConnection": "Sprawdź połączenie i spróbuj ponownie.", + "noModelsAvailable": "Brak dostępnych modeli.", + "noModelsMatch": "Żadne modele nie pasują do tych filtrów.", + "noCombosAvailable": "Brak dostępnych zestawów.", + "noCombosMatch": "Żadne zestawy nie pasują do tych filtrów.", + "clearFilters": "Wyczyść filtry", + "searchModels": "Szukaj modeli", + "searchModelsPlaceholder": "Szukaj według modelu, dostawcy lub możliwości", + "searchCombos": "Szukaj zestawów", + "searchCombosPlaceholder": "Szukaj według nazwy zestawu, modeli lub opisu", + "modelCountSingle": "model", + "modelCountPlural": "modele", + "comboCountSingle": "zestaw", + "comboCountPlural": "zestawy", + "provider": "Dostawca", + "allProviders": "Wszyscy dostawcy", + "type": "Typ", + "allTypes": "Wszystkie typy", + "subtype": "Podtyp", + "allSubtypes": "Wszystkie podtypy", + "capability": "Możliwości", + "allCapabilities": "Wszystkie możliwości", + "pricing": "Cennik", + "allPricing": "Wszystkie ceny", + "freeOnly": "Tylko bezpłatne", + "nonFree": "Standardowe / Płatne", + "providerHealth": "Stan dostawcy", + "allHealthStates": "Wszystkie stany", + "healthy": "Sprawny", + "degraded": "Zdegradowany", + "down": "Niedostępny", + "testResult": "Wynik testu", + "allResults": "Wszystkie wyniki", + "untested": "Nieprzetestowany", + "statusOk": "OK", + "statusSlow": "Spowolniony", + "statusError": "Błąd", + "minContext": "Minimalny kontekst", + "minContextPlaceholder": "np. 32000", + "strategy": "Strategia", + "allStrategies": "Wszystkie strategie", + "status": "Status", + "allStatuses": "Wszystkie statusy", + "active": "Aktywny", + "paused": "Wstrzymany", + "minMembers": "Minimalna liczba członków", + "minMembersPlaceholder": "np. 1", + "maxMembers": "Maksymalna liczba członków", + "maxMembersPlaceholder": "np. 10", + "testSelected": "Przetestuj zaznaczone ({count})", + "testAllFiltered": "Przetestuj wszystkie odfiltrowane ({count})", + "cancel": "Anuluj", + "clearResults": "Wyczyść wyniki", + "testing": "Testowanie...", + "rateLimited": "Przekroczono limit żądań", + "quotaExceeded": "Przekroczono limit przydziału", + "timeout": "Przekroczono limit czasu", + "otherError": "Błąd", + "justNow": "Przed chwilą", + "minutesAgo": "{count} min temu", + "hoursAgo": "{count} godz. temu", + "tableRegion": "Tabela katalogu modeli", + "combosTableRegion": "Tabela katalogu kombinacji", + "tableCaption": "Katalog modeli u wszystkich dostawców", + "combosTableCaption": "Katalog kombinacji z wynikami testów sprawności", + "selectAllModels": "Zaznacz wszystkie modele na tej stronie", + "selectAllCombos": "Zaznacz wszystkie kombinacje na tej stronie", + "selectModel": "Zaznacz model {name}", + "selectCombo": "Zaznacz kombinację {name}", + "model": "Model", + "capabilities": "Możliwości", + "context": "Kontekst", + "output": "Maks. wyjście", + "flags": "Flagi", + "healthTest": "Test kondycji", + "actions": "Akcje", + "test": "Testuj", + "custom": "Niestandardowy", + "free": "Bezpłatny", + "noFlags": "Nie zgłoszono ceny ani flagi źródła", + "noCapabilities": "Nie zgłoszono metadanych możliwości", + "showingModels": "Wyświetlanie {first}–{last} z {total} modeli", + "showingCombos": "Wyświetlanie {first}–{last} z {total} kombinacji", + "refreshing": "Odświeżanie…", + "refreshFailed": "Odświeżanie nie powiodło się. Wyświetlanie ostatnio załadowanego katalogu.", + "page": "Strona {page} z {pageCount}", + "previous": "Poprzednia", + "next": "Następna", + "combo": "Kombinacja", + "members": "Członkowie", + "moreMembers": "+{count} więcej" + }, "combos": { "title": "Kombinacje", "description": "Tworzenie model combos z routingiem ważonym i obsługą fallback", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index b6e27d0ff566..d7ce54288d8d 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ative faixas de admissão virtuais adaptativas por tenant para o despacho de provedores (#9654): o pico de um tenant não gera mais 503 para outro. A variável de ambiente OMNIROUTE_CHAT_VIRTUAL_LANES tem precedência sobre esta configuração do painel; as alterações entram em vigor ao reiniciar o servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de provedores no painel: exibe o selo Grátis apenas quando houver sinais reconhecidos pelo provedor — descarta a heurística de nome de exibição, campos de gratuidade não booleanos e sufixos :free em provedores registrados sem uma modalidade gratuita documentada. Quando desativado, mantém a regra histórica do selo.", "featureFlagProxySkipRecentlyFailedDescription": "Pools de proxy e a rotação por conta do opencode deixam de reutilizar um proxy que acabou de falhar (sonda TCP recusada, ou um 429 recebido por ele) por um período por processo que dobra a cada repetição, até um limite. Nenhum status de proxy é gravado; com todos os candidatos deixados de lado, a escolha não muda. Ligado por padrão; `false` restaura a seleção simples.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Para provedores cuja cota é agrupada por endereço de saída, classifique um membro do pool que compartilha o endereço de saída observado de um membro recusado recentemente logo abaixo dos membros saudáveis. Apenas ordenação, nunca excluído. Requer PROXY_SKIP_RECENTLY_FAILED, que produz o sinal de recusa que ele lê. Desativado por padrão: a ordem de seleção é exatamente a rotação simples.", "featureFlagProxyPoolEgressObservationDescription": "Mostra, abaixo de um pool de proxy no painel, quantos IPs de saída observados atenderam seus membros nas últimas 24 h, quantas conexões os usaram e o máximo visto atrás de um mesmo IP. Somente leitura, calculado a partir do log de proxy, nunca usado para roteamento. Desligado por padrão: o editor de pool não muda e a rota de observação responde null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Na varredura de saúde de proxy, permite que uma sonda recusada pelo destino (401/403/429: o proxy retransmitiu, o destino recusou este IP de saída) zere a sequência de falhas consecutivas do proxy, como uma sonda atendida. Desligado por padrão: a recusa continua neutra e mantém a sequência. Um 5xx continua inconclusivo em qualquer caso, e uma recusa nunca remove, desativa ou reativa um proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permite que a varredura automática de limpeza exclua jobs terminais (completed/failed/cancelled/expired) da Batch API mais antigos que OMNIROUTE_BATCH_RETENTION_DAYS, junto com seus checkpoints por linha, e limpe o conteúdo BLOB de arquivos enviados que já passaram do próprio expires_at. Desligado por padrão: toda instalação existente mantém esses dados exatamente como estão até um operador ativar. A rota DELETE /api/v1/batches/delete-completed, acionada pelo operador, não é afetada de nenhuma forma -- é um contrato de API pública separado e incondicional.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Atualização disponível: v{current} → v{latest}", "cliproxyapiVersion": "Versão" }, + "modelCatalog": { + "title": "Modelos e Combos", + "subtitle": "Navegue e teste a integridade de modelos e pipelines de roteamento de combos em todos os provedores.", + "refresh": "Atualizar", + "modelsTab": "Modelos", + "combosTab": "Combos", + "catalogSections": "Seções do Catálogo", + "loading": "Carregando...", + "retry": "Tentar novamente", + "unableToLoad": "Não foi possível carregar o catálogo de modelos.", + "unableToLoadCombos": "Não foi possível carregar os combos.", + "checkConnection": "Verifique a conexão e tente novamente.", + "noModelsAvailable": "Nenhum modelo disponível ainda.", + "noModelsMatch": "Nenhum modelo corresponde a estes filtros.", + "noCombosAvailable": "Nenhum combo disponível ainda.", + "noCombosMatch": "Nenhum combo corresponde a estes filtros.", + "clearFilters": "Limpar filtros", + "searchModels": "Buscar modelos", + "searchModelsPlaceholder": "Buscar por modelo, provedor ou capacidade", + "searchCombos": "Buscar combos", + "searchCombosPlaceholder": "Buscar por nome do combo, modelos ou descrição", + "modelCountSingle": "modelo", + "modelCountPlural": "modelos", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Provedor", + "allProviders": "Todos os provedores", + "type": "Tipo", + "allTypes": "Todos os tipos", + "subtype": "Subtipo", + "allSubtypes": "Todos os subtipos", + "capability": "Capacidade", + "allCapabilities": "Todas as capacidades", + "pricing": "Preços", + "allPricing": "Todos os preços", + "freeOnly": "Apenas gratuitos", + "nonFree": "Padrão / Não gratuito", + "providerHealth": "Integridade do provedor", + "allHealthStates": "Todos os estados de integridade", + "healthy": "Saudável", + "degraded": "Degradado", + "down": "Fora do ar", + "testResult": "Resultado do teste", + "allResults": "Todos os resultados", + "untested": "Não testado", + "statusOk": "OK", + "statusSlow": "Lento", + "statusError": "Erro", + "minContext": "Contexto mínimo", + "minContextPlaceholder": "ex.: 32000", + "strategy": "Estratégia", + "allStrategies": "Todas as estratégias", + "status": "Status", + "allStatuses": "Todos os status", + "active": "Ativo", + "paused": "Pausado", + "minMembers": "Mínimo de membros", + "minMembersPlaceholder": "ex.: 1", + "maxMembers": "Máximo de membros", + "maxMembersPlaceholder": "ex.: 10", + "testSelected": "Testar selecionados ({count})", + "testAllFiltered": "Testar todos os filtrados ({count})", + "cancel": "Cancelar", + "clearResults": "Limpar resultados", + "testing": "Testando...", + "rateLimited": "Limite de taxa atingido", + "quotaExceeded": "Cota excedida", + "timeout": "Tempo limite esgotado", + "otherError": "Erro", + "justNow": "Agora mesmo", + "minutesAgo": "há {count}m", + "hoursAgo": "há {count}h", + "tableRegion": "Tabela de catálogo de modelos", + "combosTableRegion": "Tabela de catálogo de combos", + "tableCaption": "Catálogo de modelos em todos os provedores", + "combosTableCaption": "Catálogo de combos com resultados de testes de integridade", + "selectAllModels": "Selecionar todos os modelos nesta página", + "selectAllCombos": "Selecionar todos os combos nesta página", + "selectModel": "Selecionar modelo {name}", + "selectCombo": "Selecionar combo {name}", + "model": "Modelo", + "capabilities": "Capacidades", + "context": "Contexto", + "output": "Saída máxima", + "flags": "Sinalizadores", + "healthTest": "Teste de integridade", + "actions": "Ações", + "test": "Testar", + "custom": "Personalizado", + "free": "Gratuito", + "noFlags": "Nenhum sinalizador de preço ou origem informado", + "noCapabilities": "Nenhum metadado de capacidade informado", + "showingModels": "Exibindo {first}–{last} de {total} modelos", + "showingCombos": "Exibindo {first}–{last} de {total} combos", + "refreshing": "Atualizando…", + "refreshFailed": "Falha ao atualizar. Exibindo o último catálogo carregado.", + "page": "Página {page} de {pageCount}", + "previous": "Anterior", + "next": "Próximo", + "combo": "Combo", + "members": "Membros", + "moreMembers": "+{count} mais" + }, "combos": { "title": "Combinações", "description": "Crie combos de modelos com roteamento ponderado e suporte a fallback", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index e515dd38ea4e..b63808884430 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Ative filas de admissão virtuais adaptativas por tenant para o encaminhamento de fornecedores (#9654): um pico de tráfego de um tenant já não gera 503 noutro. A variável de ambiente OMNIROUTE_CHAT_VIRTUAL_LANES sobrepõe-se a esta definição do painel; as alterações entram em vigor ao reiniciar o servidor.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Páginas de fornecedores no dashboard: mostrar o distintivo Gratuito apenas com base nos sinais que o fornecedor reconhece — ignora a heurística do nome de apresentação, os campos free não booleanos e os sufixos :free em fornecedores registados sem um nível gratuito documentado. Desativado mantém a regra histórica do distintivo.", "featureFlagProxySkipRecentlyFailedDescription": "Os conjuntos de proxies e a rotação por conta do opencode deixam de voltar a disponibilizar um proxy que acabou de falhar (sondagem TCP recusada ou resposta 429 recebida através do mesmo) durante um período por processo que duplica a cada repetição, até um limite máximo. Não é registado qualquer estado do proxy; se todos os candidatos forem postos de parte, a escolha permanece inalterada. Ativado por predefinição; `false` repõe a seleção simples.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Para fornecedores cuja quota é agrupada por endereço de saída, classificar um membro do pool que partilha o endereço de saída observado de um membro recentemente recusado imediatamente abaixo dos membros saudáveis. Apenas ordenação, nunca excluído. Requer PROXY_SKIP_RECENTLY_FAILED, que produz o sinal de recusa que este lê. Desativado por predefinição: a ordem de seleção é exatamente a rotação simples.", "featureFlagProxyPoolEgressObservationDescription": "Mostrar, sob um conjunto de proxies no dashboard, quantos IPs de saída observados serviram os respetivos membros nas últimas 24 h, quantas ligações os utilizaram e o número máximo de membros observados por trás de um único IP. Apenas de leitura, calculado a partir do registo do proxy e nunca utilizado para encaminhamento. Desativado por predefinição: o editor do conjunto permanece inalterado e a rota de observação devolve null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Na verificação de integridade dos proxies, permitir que uma sondagem recusada pelo destino (401/403/429: o proxy reencaminhou o pedido, mas o destino recusou este IP de saída) reinicie a sequência de falhas consecutivas do proxy, tal como uma sondagem bem-sucedida. Desativado por predefinição: uma recusa permanece neutra e mantém a sequência. Uma resposta 5xx permanece inconclusiva em qualquer dos casos, e uma recusa nunca remove, desativa nem reativa um proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permitir que a limpeza automática elimine tarefas da Batch API em estado terminal (concluídas/com falha/canceladas/expiradas) com mais de OMNIROUTE_BATCH_RETENTION_DAYS, juntamente com os respetivos pontos de controlo por linha, e limpe o conteúdo BLOB dos ficheiros carregados cuja própria data expires_at já tenha passado. Desativado por predefinição: todas as instalações existentes mantêm estes dados exatamente como antes até que um operador ative esta opção. A rota DELETE /api/v1/batches/delete-completed acionada pelo operador não é afetada em nenhum dos casos — trata-se de um contrato de API pública separado e incondicional.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Atualização disponível: v{current} → v{latest}", "cliproxyapiVersion": "Versão" }, + "modelCatalog": { + "title": "Modelos e Combos", + "subtitle": "Navegue e teste o estado de modelos e pipelines de encaminhamento de combos em todos os fornecedores.", + "refresh": "Atualizar", + "modelsTab": "Modelos", + "combosTab": "Combos", + "catalogSections": "Secções do catálogo", + "loading": "A carregar...", + "retry": "Tentar novamente", + "unableToLoad": "Não foi possível carregar o catálogo de modelos.", + "unableToLoadCombos": "Não foi possível carregar os combos.", + "checkConnection": "Verifique a ligação e tente novamente.", + "noModelsAvailable": "Ainda não existem modelos disponíveis.", + "noModelsMatch": "Nenhum modelo corresponde a estes filtros.", + "noCombosAvailable": "Ainda não existem combos disponíveis.", + "noCombosMatch": "Nenhum combo corresponde a estes filtros.", + "clearFilters": "Limpar filtros", + "searchModels": "Pesquisar modelos", + "searchModelsPlaceholder": "Pesquisar por modelo, fornecedor ou capacidade", + "searchCombos": "Pesquisar combos", + "searchCombosPlaceholder": "Pesquisar por nome do combo, modelos ou descrição", + "modelCountSingle": "modelo", + "modelCountPlural": "modelos", + "comboCountSingle": "combo", + "comboCountPlural": "combos", + "provider": "Fornecedor", + "allProviders": "Todos os fornecedores", + "type": "Tipo", + "allTypes": "Todos os tipos", + "subtype": "Subtipo", + "allSubtypes": "Todos os subtipos", + "capability": "Capacidade", + "allCapabilities": "Todas as capacidades", + "pricing": "Preços", + "allPricing": "Todos os preços", + "freeOnly": "Apenas gratuitos", + "nonFree": "Padrão / Não gratuito", + "providerHealth": "Estado do fornecedor", + "allHealthStates": "Todos os estados", + "healthy": "Operacional", + "degraded": "Degradado", + "down": "Em baixo", + "testResult": "Resultado do teste", + "allResults": "Todos os resultados", + "untested": "Não testado", + "statusOk": "OK", + "statusSlow": "Lento", + "statusError": "Erro", + "minContext": "Contexto mínimo", + "minContextPlaceholder": "ex.: 32000", + "strategy": "Estratégia", + "allStrategies": "Todas as estratégias", + "status": "Estado", + "allStatuses": "Todos os estados", + "active": "Ativo", + "paused": "Em pausa", + "minMembers": "Membros mínimos", + "minMembersPlaceholder": "ex.: 1", + "maxMembers": "Membros máximos", + "maxMembersPlaceholder": "ex.: 10", + "testSelected": "Testar selecionados ({count})", + "testAllFiltered": "Testar todos os filtrados ({count})", + "cancel": "Cancelar", + "clearResults": "Limpar resultados", + "testing": "A testar...", + "rateLimited": "Limite de taxa atingido", + "quotaExceeded": "Quota excedida", + "timeout": "Tempo limite excedido", + "otherError": "Erro", + "justNow": "Agora mesmo", + "minutesAgo": "há {count}m", + "hoursAgo": "há {count}h", + "tableRegion": "Tabela do catálogo de modelos", + "combosTableRegion": "Tabela do catálogo de combos", + "tableCaption": "Catálogo de modelos em todos os fornecedores", + "combosTableCaption": "Catálogo de combos com resultados de testes de integridade", + "selectAllModels": "Selecionar todos os modelos nesta página", + "selectAllCombos": "Selecionar todos os combos nesta página", + "selectModel": "Selecionar modelo {name}", + "selectCombo": "Selecionar combo {name}", + "model": "Modelo", + "capabilities": "Capacidades", + "context": "Contexto", + "output": "Saída máxima", + "flags": "Sinalizadores", + "healthTest": "Teste de estado", + "actions": "Ações", + "test": "Testar", + "custom": "Personalizado", + "free": "Gratuito", + "noFlags": "Nenhum sinalizador de preço ou origem reportado", + "noCapabilities": "Nenhum metadado de capacidade reportado", + "showingModels": "A mostrar {first}–{last} de {total} modelos", + "showingCombos": "A mostrar {first}–{last} de {total} combos", + "refreshing": "A atualizar…", + "refreshFailed": "Falha ao atualizar. A mostrar o último catálogo carregado.", + "page": "Página {page} de {pageCount}", + "previous": "Anterior", + "next": "Seguinte", + "combo": "Combo", + "members": "Membros", + "moreMembers": "+{count} mais" + }, "combos": { "title": "Combinações", "description": "Crie combinações de modelos com roteamento ponderado e suporte substituto", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index 531c54d463cc..aebeb3bf8a5c 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Activați benzile de admitere virtuale adaptive per-tenant pentru expedierea către furnizori (#9654): un vârf de trafic al unui tenant nu mai returnează 503 altui tenant. Variabila de mediu OMNIROUTE_CHAT_VIRTUAL_LANES are prioritate față de această setare din panou; modificările intră în vigoare la repornirea serverului.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Paginile furnizorilor din tabloul de bord: afișează insigna Gratuit numai pe baza indiciilor confirmate de furnizor — elimină euristica bazată pe numele afișat, câmpurile pentru gratuitate care nu au valori booleene și sufixele :free în cazul furnizorilor înregistrați care nu au un nivel gratuit documentat. Opțiunea Dezactivat păstrează regula istorică privind insigna.", "featureFlagProxySkipRecentlyFailedDescription": "Pool-urile de proxy-uri și rotația per cont din opencode nu mai reutilizează un proxy care tocmai a eșuat (sondă TCP refuzată sau un răspuns 429 primit prin acesta) pentru o perioadă per proces care se dublează la fiecare repetare, până la o limită maximă. Nu este înregistrată nicio stare a proxy-ului; dacă toți candidații sunt puși deoparte, alegerea rămâne neschimbată. Activat în mod implicit; `false` restabilește selecția simplă.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Pentru furnizorii a căror cotă este grupată după adresa de egress, poziționează un membru din pool care partajează adresa de egress observată a unui membru refuzat recent imediat sub membrii sănătoși. Doar ordonare, niciodată exclus. Necesită PROXY_SKIP_RECENTLY_FAILED, care produce semnalul de refuz pe care îl citește. Dezactivat în mod implicit: ordinea de selecție este exact rotația simplă.", "featureFlagProxyPoolEgressObservationDescription": "Afișează, sub un pool de proxy-uri din panoul de control, câte IP-uri de ieșire observate au deservit membrii acestuia în ultimele 24 h, câte conexiuni le-au folosit și numărul maxim de conexiuni observate în spatele unui singur IP. Doar pentru citire, calculat din jurnalul proxy-ului și niciodată utilizat pentru rutare. Dezactivat în mod implicit: editorul pool-ului rămâne neschimbat, iar ruta de observare returnează null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "În verificarea periodică a stării proxy-urilor, permite unei sonde refuzate de destinație (401/403/429: proxy-ul a retransmis, iar destinația a refuzat acest IP de ieșire) să reseteze seria de eșecuri consecutive a proxy-ului, la fel ca o sondă procesată cu succes. Dezactivat în mod implicit: un refuz rămâne neutru și păstrează seria. Un răspuns 5xx rămâne neconcludent în ambele cazuri, iar un refuz nu elimină, nu dezactivează și nu reactivează niciodată un proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Permite procesului automat de curățare să șteargă sarcinile Batch API în stare terminală (finalizate/eșuate/anulate/expirate) mai vechi decât OMNIROUTE_BATCH_RETENTION_DAYS, împreună cu punctele de control pentru fiecare linie, și să golească conținutul BLOB al fișierelor încărcate care și-au depășit propria valoare expires_at. Dezactivată implicit: fiecare instalare existentă păstrează aceste date exact ca înainte, până când un operator activează opțiunea. Ruta DELETE /api/v1/batches/delete-completed declanșată de operator nu este afectată în niciun caz — aceasta este un contract API public separat și necondiționat.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Actualizare disponibilă: v{current} → v{latest}", "cliproxyapiVersion": "Versiune" }, + "modelCatalog": { + "title": "Modele și combo-uri", + "subtitle": "Explorează și testează starea modelelor și a conductelor de rutare combo pentru toți furnizorii.", + "refresh": "Reîmprospătează", + "modelsTab": "Modele", + "combosTab": "Combo-uri", + "catalogSections": "Secțiuni catalog", + "loading": "Se încarcă...", + "retry": "Reîncearcă", + "unableToLoad": "Catalogul de modele nu a putut fi încărcat.", + "unableToLoadCombos": "Combo-urile nu au putut fi încărcate.", + "checkConnection": "Verifică conexiunea și încearcă din nou.", + "noModelsAvailable": "Nu există încă modele disponibile.", + "noModelsMatch": "Niciun model nu corespunde acestor filtre.", + "noCombosAvailable": "Nu există încă combo-uri disponibile.", + "noCombosMatch": "Niciun combo nu corespunde acestor filtre.", + "clearFilters": "Resetează filtrele", + "searchModels": "Caută modele", + "searchModelsPlaceholder": "Caută după model, furnizor sau capabilitate", + "searchCombos": "Caută combo-uri", + "searchCombosPlaceholder": "Caută după numele combo-ului, modele sau descriere", + "modelCountSingle": "model", + "modelCountPlural": "modele", + "comboCountSingle": "combo", + "comboCountPlural": "combo-uri", + "provider": "Furnizor", + "allProviders": "Toți furnizorii", + "type": "Tip", + "allTypes": "Toate tipurile", + "subtype": "Subtip", + "allSubtypes": "Toate subtipurile", + "capability": "Capabilitate", + "allCapabilities": "Toate capabilitățile", + "pricing": "Prețuri", + "allPricing": "Toate prețurile", + "freeOnly": "Doar gratuite", + "nonFree": "Standard / Cu plată", + "providerHealth": "Stare furnizor", + "allHealthStates": "Toate stările", + "healthy": "Funcțional", + "degraded": "Degradat", + "down": "Indisponibil", + "testResult": "Rezultat test", + "allResults": "Toate rezultatele", + "untested": "Netestat", + "statusOk": "OK", + "statusSlow": "Lent", + "statusError": "Eroare", + "minContext": "Context minim", + "minContextPlaceholder": "de ex. 32000", + "strategy": "Strategie", + "allStrategies": "Toate strategiile", + "status": "Stare", + "allStatuses": "Toate stările", + "active": "Activ", + "paused": "În pauză", + "minMembers": "Membri minimi", + "minMembersPlaceholder": "de ex. 1", + "maxMembers": "Membri maximi", + "maxMembersPlaceholder": "de ex. 10", + "testSelected": "Testează cele selectate ({count})", + "testAllFiltered": "Testează toate cele filtrate ({count})", + "cancel": "Anulează", + "clearResults": "Șterge rezultatele", + "testing": "Se testează...", + "rateLimited": "Rată limitată", + "quotaExceeded": "Cotă depășită", + "timeout": "Timp expirat", + "otherError": "Eroare", + "justNow": "Chiar acum", + "minutesAgo": "acum {count}m", + "hoursAgo": "acum {count}h", + "tableRegion": "Tabel catalog modele", + "combosTableRegion": "Tabel catalog combinații", + "tableCaption": "Catalog de modele de la toți furnizorii", + "combosTableCaption": "Catalog de combinații cu rezultatele testelor de funcționare", + "selectAllModels": "Selectează toate modelele de pe această pagină", + "selectAllCombos": "Selectează toate combinațiile de pe această pagină", + "selectModel": "Selectează modelul {name}", + "selectCombo": "Selectează combinația {name}", + "model": "Model", + "capabilities": "Capabilități", + "context": "Context", + "output": "Output maxim", + "flags": "Indicatori", + "healthTest": "Test de funcționare", + "actions": "Acțiuni", + "test": "Test", + "custom": "Personalizat", + "free": "Gratuit", + "noFlags": "Niciun indicator de preț sau sursă raportat", + "noCapabilities": "Nu au fost raportate metadate despre capabilități", + "showingModels": "Se afișează {first}–{last} din {total} modele", + "showingCombos": "Se afișează {first}–{last} din {total} combinații", + "refreshing": "Se reîmprospătează…", + "refreshFailed": "Reîmprospătarea a eșuat. Se afișează ultimul catalog încărcat.", + "page": "Pagina {page} din {pageCount}", + "previous": "Anterior", + "next": "Următor", + "combo": "Combinație", + "members": "Membri", + "moreMembers": "+{count} în plus" + }, "combos": { "title": "Combo-uri", "description": "Creați combinații de modele cu rutare ponderată și suport alternativ", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index 874faffadb38..b4abbefc0039 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Включите адаптивные виртуальные полосы допуска для каждого тенанта при маршрутизации к провайдерам (#9654): всплеск нагрузки одного тенанта больше не вызывает 503 у другого. Переменная окружения OMNIROUTE_CHAT_VIRTUAL_LANES имеет приоритет над этой настройкой в панели; изменения вступают в силу после перезапуска сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Страницы провайдеров на панели управления: показывать значок «Бесплатно» только для признаков, которые учитывает провайдер. Эвристика на основе отображаемого имени, небулевы поля free и суффиксы :free для зарегистрированных провайдеров без документально подтверждённого бесплатного тарифа больше не используются. При отключении сохраняется прежнее правило отображения значка.", "featureFlagProxySkipRecentlyFailedDescription": "Пулы прокси и ротация opencode для каждой учётной записи временно перестают повторно выбирать прокси сразу после сбоя (отказ при проверке TCP или ответ 429, полученный через него) на срок, действующий в рамках процесса и удваивающийся при каждом повторном сбое вплоть до установленного предела. Статус прокси не записывается; если отложены все кандидаты, выбор остаётся прежним. По умолчанию включено; `false` возвращает обычный выбор.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Для провайдеров, квота которых распределяется по egress-адресу: размещать участника пула, имеющего общий зафиксированный egress-адрес с недавно отклоненным участником, сразу после работоспособных участников. Влияет только на порядок, исключение не производится. Требуется PROXY_SKIP_RECENTLY_FAILED, формирующий считываемый сигнал отказа. По умолчанию отключено: порядок выбора строго соответствует обычной ротации.", "featureFlagProxyPoolEgressObservationDescription": "Показывать под пулом прокси на панели управления, сколько наблюдаемых исходящих IP-адресов использовалось его участниками за последние 24 ч, сколько подключений использовало эти адреса и какое наибольшее число подключений приходилось на один IP-адрес. Данные доступны только для чтения, вычисляются по журналу прокси и никогда не используются для маршрутизации. По умолчанию отключено: редактор пула остаётся без изменений, а маршрут наблюдений возвращает null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "При проверке работоспособности прокси позволить проверке, отклонённой целевым сервером (401/403/429: прокси передал запрос, но целевой сервер отклонил этот исходящий IP-адрес), сбрасывать счётчик последовательных сбоев прокси, как при успешно обслуженной проверке. По умолчанию отключено: отказ остаётся нейтральным и не сбрасывает счётчик. Ответ 5xx в любом случае остаётся неопределённым, а отказ никогда не удаляет, не отключает и не активирует прокси повторно.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Разрешить автоматической очистке удалять задания Batch API в конечном состоянии (завершённые/завершившиеся ошибкой/отменённые/с истёкшим сроком действия) старше OMNIROUTE_BATCH_RETENTION_DAYS вместе с их построчными контрольными точками, а также очищать содержимое BLOB загруженных файлов после наступления указанного для них expires_at. По умолчанию отключено: во всех существующих установках эти данные сохраняются без изменений, пока оператор не включит эту функцию. Маршрут DELETE /api/v1/batches/delete-completed, запускаемый оператором, не затрагивается независимо от этой настройки — это отдельный безусловный контракт публичного API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Доступно обновление: v{current} → v{latest}", "cliproxyapiVersion": "Версия" }, + "modelCatalog": { + "title": "Модели и комбо", + "subtitle": "Просматривайте и тестируйте работоспособность моделей и пайплайнов маршрутизации комбо по всем провайдерам.", + "refresh": "Обновить", + "modelsTab": "Модели", + "combosTab": "Комбо", + "catalogSections": "Разделы каталога", + "loading": "Загрузка...", + "retry": "Повторить попытку", + "unableToLoad": "Не удалось загрузить каталог моделей.", + "unableToLoadCombos": "Не удалось загрузить комбо.", + "checkConnection": "Проверьте соединение и повторите попытку.", + "noModelsAvailable": "Пока нет доступных моделей.", + "noModelsMatch": "Нет моделей, соответствующих этим фильтрам.", + "noCombosAvailable": "Пока нет доступных комбо.", + "noCombosMatch": "Нет комбо, соответствующих этим фильтрам.", + "clearFilters": "Сбросить фильтры", + "searchModels": "Поиск моделей", + "searchModelsPlaceholder": "Поиск по модели, провайдеру или возможности", + "searchCombos": "Поиск комбо", + "searchCombosPlaceholder": "Поиск по названию комбо, моделям или описанию", + "modelCountSingle": "модель", + "modelCountPlural": "модели", + "comboCountSingle": "комбо", + "comboCountPlural": "комбо", + "provider": "Провайдер", + "allProviders": "Все провайдеры", + "type": "Тип", + "allTypes": "Все типы", + "subtype": "Подтип", + "allSubtypes": "Все подтипы", + "capability": "Возможность", + "allCapabilities": "Все возможности", + "pricing": "Тарификация", + "allPricing": "Любая тарификация", + "freeOnly": "Только бесплатные", + "nonFree": "Стандартные / Платные", + "providerHealth": "Состояние провайдера", + "allHealthStates": "Все состояния", + "healthy": "В норме", + "degraded": "Работает со сбоями", + "down": "Не работает", + "testResult": "Результат теста", + "allResults": "Все результаты", + "untested": "Не тестировалось", + "statusOk": "ОК", + "statusSlow": "Медленно", + "statusError": "Ошибка", + "minContext": "Мин. контекст", + "minContextPlaceholder": "напр., 32000", + "strategy": "Стратегия", + "allStrategies": "Все стратегии", + "status": "Статус", + "allStatuses": "Все статусы", + "active": "Активно", + "paused": "Приостановлено", + "minMembers": "Мин. участников", + "minMembersPlaceholder": "напр., 1", + "maxMembers": "Макс. участников", + "maxMembersPlaceholder": "напр., 10", + "testSelected": "Тестировать выбранные ({count})", + "testAllFiltered": "Тестировать все отфильтрованные ({count})", + "cancel": "Отмена", + "clearResults": "Очистить результаты", + "testing": "Тестирование...", + "rateLimited": "Превышен лимит запросов", + "quotaExceeded": "Квота исчерпана", + "timeout": "Время ожидания истекло", + "otherError": "Ошибка", + "justNow": "Только что", + "minutesAgo": "{count} мин назад", + "hoursAgo": "{count} ч назад", + "tableRegion": "Таблица каталога моделей", + "combosTableRegion": "Таблица каталога комбо", + "tableCaption": "Каталог моделей по всем провайдерам", + "combosTableCaption": "Каталог комбо с результатами проверки работоспособности", + "selectAllModels": "Выбрать все модели на этой странице", + "selectAllCombos": "Выбрать все комбо на этой странице", + "selectModel": "Выбрать модель {name}", + "selectCombo": "Выбрать комбо {name}", + "model": "Модель", + "capabilities": "Возможности", + "context": "Контекст", + "output": "Макс. вывод", + "flags": "Флаги", + "healthTest": "Проверка работоспособности", + "actions": "Действия", + "test": "Проверить", + "custom": "Пользовательский", + "free": "Бесплатно", + "noFlags": "Нет данных о цене или источнике", + "noCapabilities": "Нет метаданных о возможностях", + "showingModels": "Показано {first}–{last} из {total} моделей", + "showingCombos": "Показано {first}–{last} из {total} комбинаций", + "refreshing": "Обновление…", + "refreshFailed": "Ошибка обновления. Отображается последний загруженный каталог.", + "page": "Страница {page} из {pageCount}", + "previous": "Предыдущая", + "next": "Следующая", + "combo": "Комбо", + "members": "Участники", + "moreMembers": "+{count} еще" + }, "combos": { "title": "Комбо", "description": "Создавайте комбинации моделей с взвешенной маршрутизацией и поддержкой резервного варианта.", diff --git a/src/i18n/messages/si.json b/src/i18n/messages/si.json index 5207a998e218..bfa87f451203 100644 --- a/src/i18n/messages/si.json +++ b/src/i18n/messages/si.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "සපයන්නා වෙත යැවීම සඳහා එක් එක් ටෙනන්ට්ට අනුව අනුවර්තනය වන අතථ්ය ප්රවේශ මංතීරු සබල කරන්න (#9654): එක් ටෙනන්ට් කෙනෙකුගේ හදිසි ඉල්ලීම් වැඩිවීමක් තවදුරටත් වෙනත් අයෙකුට 503 දෝෂයක් ඇති නොකරයි. OMNIROUTE_CHAT_VIRTUAL_LANES පරිසර විචල්යය මෙම උපකරණ පුවරු අතික්රමණයට වඩා ප්රමුඛ වේ; වෙනස්කම් සේවාදායකය නැවත ආරම්භ කළ විට ක්රියාත්මක වේ.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "උපකරණ පුවරුවේ සැපයුම්කරු පිටු: සැපයුම්කරු පිළිගන්නා සංඥා මත පමණක් නොමිලේ ලාංඡනය පෙන්වන්න — ලේඛනගත නොමිලේ මට්ටමක් නොමැති ලියාපදිංචි සැපයුම්කරුවන් සඳහා සංදර්ශක නාම අනුමානය, බූලීය නොවන නොමිලේ ක්ෂේත්ර සහ :free ප්රත්ය අත්හරියි. අක්රිය කළ විට ඓතිහාසික ලාංඡන රීතිය භාවිත කරයි.", "featureFlagProxySkipRecentlyFailedDescription": "ප්රොක්සි සංචිත සහ opencode හි ගිණුමකට වෙන් වූ මාරු කිරීම, අසාර්ථක වූ ප්රොක්සියක් (ප්රතික්ෂේප වූ TCP පරීක්ෂාවක් හෝ එය හරහා ලැබුණු 429 ප්රතිචාරයක්) එක් එක් නැවත සිදුවීමේදී දෙගුණ වන, උපරිම සීමාවකට යටත් ක්රියාවලි-විශේෂිත කාලයක් සඳහා නැවත භාවිත කිරීම නවත්වයි. කිසිදු ප්රොක්සි තත්ත්වයක් ලියනු නොලැබේ; සෑම අපේක්ෂකයෙකුම පසෙකට කළ විට තේරීම වෙනස් නොවේ. පෙරනිමියෙන් සක්‍රියයි; `false` සරල තේරීම ප්‍රතිසාධනය කරයි.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Egress ලිපිනය අනුව කෝටාව කාණ්ඩ කර ඇති සපයන්නන් සඳහා, මෑතකදී ප්‍රතික්ෂේප වූ සාමාජිකයෙකුගේ නිරීක්ෂිත egress ලිපිනය බෙදාගන්නා pool සාමාජිකයෙකු නිරෝගී සාමාජිකයින්ට මදක් පහළින් ශ්‍රේණිගත කරන්න. අනුපිළිවෙල පමණි, කිසිවිටෙකත් බැහැර නොකෙරේ. මෙය කියවන ප්‍රතික්ෂේප කිරීමේ සංඥාව ලබා දෙන PROXY_SKIP_RECENTLY_FAILED අවශ්‍ය වේ. පෙරනිමියෙන් අක්‍රියයි: තේරීම් අනුපිළිවෙල සාමාන්‍ය භ්‍රමණයම වේ.", "featureFlagProxyPoolEgressObservationDescription": "උපකරණ පුවරුවේ ප්රොක්සි සංචිතයක් යටතේ, පසුගිය පැය 24 තුළ එහි සාමාජිකයන්ට සේවය සැපයූ නිරීක්ෂිත පිටතට යන IP ලිපින ගණන, ඒවා භාවිත කළ සම්බන්ධතා ගණන සහ එක් IP ලිපිනයක් පිටුපසින් නිරීක්ෂණය වූ උපරිම ගණන පෙන්වන්න. මෙය කියවීමට පමණක් වන අතර ප්රොක්සි ලොගයෙන් ගණනය කෙරෙන අතර මාර්ගගත කිරීම සඳහා කිසි විටෙක භාවිත නොකෙරේ. පෙරනිමියෙන් අක්රියයි: සංචිත සංස්කාරකය වෙනස් නොවන අතර නිරීක්ෂණ මාර්ගය null ලෙස පිළිතුරු දෙයි.", "featureFlagProxyHealthBlockedResetsStreakDescription": "ප්රොක්සි සෞඛ්ය පරීක්ෂණ වටයේදී, ඉලක්කය ප්රතික්ෂේප කළ පරීක්ෂාවකට (401/403/429: ප්රොක්සිය ඉල්ලීම යොමු කළ නමුත් ගමනාන්තය මෙම පිටතට යන IP ලිපිනය ප්රතික්ෂේප කළේය) සාර්ථකව සේවය කළ පරීක්ෂාවක් මෙන් ප්රොක්සියේ අඛණ්ඩ අසාර්ථකවීම් පෙළ යළි සැකසීමට ඉඩ දෙන්න. පෙරනිමියෙන් අක්රියයි: ප්රතික්ෂේප කිරීමක් මධ්යස්ථව පවතින අතර අඛණ්ඩ අසාර්ථකවීම් පෙළ එලෙසම තබයි. 5xx ප්රතිචාරයක් අවස්ථා දෙකේදීම අවිනිශ්චිතව පවතින අතර, ප්රතික්ෂේප කිරීමක් කිසි විටෙක ප්රොක්සියක් ඉවත් කිරීම, අක්රිය කිරීම හෝ නැවත සක්රිය කිරීම සිදු නොකරයි.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "ස්වයංක්රීය පිරිසිදු කිරීමේ ක්රියාවලියට OMNIROUTE_BATCH_RETENTION_DAYS ට වඩා පැරණි අවසන් තත්ත්වයේ (සම්පූර්ණ කළ/අසාර්ථක වූ/අවලංගු කළ/කල් ඉකුත් වූ) Batch API කාර්ය, ඒවායේ එක් එක් පේළියේ checkpoints සමඟ මකා දැමීමටත්, තමන්ගේ expires_at පසු කළ උඩුගත කළ ගොනුවල BLOB අන්තර්ගතය හිස් කිරීමටත් ඉඩ දෙන්න. පෙරනිමියෙන් අක්රියයි: ක්රියාකරු තේරීමෙන් සක්රිය කරන තෙක් පවතින සෑම ස්ථාපනයක්ම මෙම දත්ත පෙර පරිදිම තබා ගනී. ක්රියාකරු විසින් ක්රියාත්මක කරන DELETE /api/v1/batches/delete-completed මාර්ගයට මෙය කෙසේ සැකසුවත් බලපෑමක් නැත — එය වෙනම, කොන්දේසි රහිත පොදු API ගිවිසුමකි.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "යාවත්කාලීනයක් ඇත: v{current} → v{latest}", "cliproxyapiVersion": "අනුවාදය" }, + "modelCatalog": { + "title": "මාදිලි සහ සංයෝජන", + "subtitle": "සෑම සපයන්නෙකු හරහාම මාදිලි සහ සංයෝජන රවුටින් නල මාර්ග පිරික්සන්න සහ සෞඛ්‍ය තත්ත්වය පරීක්ෂා කරන්න.", + "refresh": "නැවුම් කරන්න", + "modelsTab": "මාදිලි", + "combosTab": "සංයෝජන", + "catalogSections": "නාමාවලි කොටස්", + "loading": "පූරණය වෙමින් පවතී...", + "retry": "නැවත උත්සාහ කරන්න", + "unableToLoad": "මාදිලි නාමාවලිය පූරණය කිරීමට නොහැකි විය.", + "unableToLoadCombos": "සංයෝජන පූරණය කිරීමට නොහැකි විය.", + "checkConnection": "සබඳතාව පරීක්ෂා කර නැවත උත්සාහ කරන්න.", + "noModelsAvailable": "තවමත් මාදිලි කිසිවක් ලබා ගත නොහැක.", + "noModelsMatch": "මෙම පෙරහන්වලට ගැළපෙන මාදිලි කිසිවක් නැත.", + "noCombosAvailable": "තවමත් සංයෝජන කිසිවක් ලබා ගත නොහැක.", + "noCombosMatch": "මෙම පෙරහන්වලට ගැළපෙන සංයෝජන කිසිවක් නැත.", + "clearFilters": "පෙරහන් ඉවත් කරන්න", + "searchModels": "මාදිලි සොයන්න", + "searchModelsPlaceholder": "මාදිලිය, සපයන්නා, හෝ හැකියාව අනුව සොයන්න", + "searchCombos": "සංයෝජන සොයන්න", + "searchCombosPlaceholder": "සංයෝජන නම, මාදිලි, හෝ විස්තරය අනුව සොයන්න", + "modelCountSingle": "මාදිලිය", + "modelCountPlural": "මාදිලි", + "comboCountSingle": "සංයෝජනය", + "comboCountPlural": "සංයෝජන", + "provider": "සපයන්නා", + "allProviders": "සියලුම සපයන්නන්", + "type": "වර්ගය", + "allTypes": "සියලුම වර්ග", + "subtype": "උප වර්ගය", + "allSubtypes": "සියලුම උප වර්ග", + "capability": "හැකියාව", + "allCapabilities": "සියලුම හැකියාවන්", + "pricing": "මිල ගණන්", + "allPricing": "සියලුම මිල ගණන්", + "freeOnly": "නොමිලේ පමණි", + "nonFree": "සම්මත / නොමිලේ නොවන", + "providerHealth": "සපයන්නාගේ සෞඛ්‍ය තත්ත්වය", + "allHealthStates": "සියලුම සෞඛ්‍ය තත්ත්වයන්", + "healthy": "යහපත්", + "degraded": "පිරිහුණු", + "down": "අක්‍රියයි", + "testResult": "පරීක්ෂණ ප්‍රතිඵලය", + "allResults": "සියලු ප්‍රතිඵල", + "untested": "පරීක්ෂා කර නැත", + "statusOk": "හරි", + "statusSlow": "මන්දගාමී", + "statusError": "දෝෂයකි", + "minContext": "අවම සන්දර්භය", + "minContextPlaceholder": "උදා. 32000", + "strategy": "උපායමාර්ගය", + "allStrategies": "සියලු උපායමාර්ග", + "status": "තත්ත්වය", + "allStatuses": "සියලු තත්ත්වයන්", + "active": "සක්‍රියයි", + "paused": "විරාම කර ඇත", + "minMembers": "අවම සාමාජිකයින්", + "minMembersPlaceholder": "උදා. 1", + "maxMembers": "උපරිම සාමාජිකයින්", + "maxMembersPlaceholder": "උදා. 10", + "testSelected": "තෝරාගත් ({count}) පරීක්ෂා කරන්න", + "testAllFiltered": "පෙරූ සියල්ල ({count}) පරීක්ෂා කරන්න", + "cancel": "අවලංගු කරන්න", + "clearResults": "ප්‍රතිඵල ඉවත් කරන්න", + "testing": "පරීක්ෂා කරමින්...", + "rateLimited": "අනුපාතය සීමා කර ඇත", + "quotaExceeded": "කෝටාව ඉක්මවා ඇත", + "timeout": "කාලය ඉකුත් විය", + "otherError": "දෝෂයකි", + "justNow": "සුළු මොහොතකට පෙර", + "minutesAgo": "මිනිත්තු {count}කට පෙර", + "hoursAgo": "පැය {count}කට පෙර", + "tableRegion": "මාදිලි නාමාවලි වගුව", + "combosTableRegion": "සංයෝජන නාමාවලි වගුව", + "tableCaption": "සියලු සපයන්නන් හරහා මාදිලි නාමාවලිය", + "combosTableCaption": "සෞඛ්‍ය පරීක්ෂණ ප්‍රතිඵල සහිත සංයෝජන නාමාවලිය", + "selectAllModels": "මෙම පිටුවේ ඇති සියලුම මාදිලි තෝරන්න", + "selectAllCombos": "මෙම පිටුවේ ඇති සියලුම සංයෝජන තෝරන්න", + "selectModel": "{name} මාදිලිය තෝරන්න", + "selectCombo": "{name} සංයෝජනය තෝරන්න", + "model": "මාදිලිය", + "capabilities": "හැකියාවන්", + "context": "සන්දර්භය", + "output": "උපරිම ප්‍රතිදානය", + "flags": "ධජ", + "healthTest": "සෞඛ්‍ය පරීක්ෂාව", + "actions": "ක්‍රියා", + "test": "පරීක්ෂා කරන්න", + "custom": "අභිරුචි", + "free": "නොමිලේ", + "noFlags": "කිසිදු මිලක් හෝ මූලාශ්‍ර ධජයක් වාර්තා වී නොමැත", + "noCapabilities": "කිසිදු හැකියාවක පාරදත්ත වාර්තා වී නොමැත", + "showingModels": "ආකෘති {total} න් {first}–{last} දක්වා පෙන්වයි", + "showingCombos": "සංයෝජන {total} න් {first}–{last} දක්වා පෙන්වයි", + "refreshing": "නැවුම් කරමින්…", + "refreshFailed": "නැවුම් කිරීම අසාර්ථක විය. අවසන් වරට පූරණය කළ නාමාවලිය පෙන්වයි.", + "page": "පිටු {pageCount} න් {page} පිටුව", + "previous": "පෙර", + "next": "ඊළඟ", + "combo": "සංයෝජනය", + "members": "සාමාජිකයින්", + "moreMembers": "තවත් +{count} ක්" + }, "combos": { "title": "සංයෝජන", "description": "බරිත මාර්ගගත කිරීම සහ විකල්ප සහාය සහිත ආකෘති සංයෝජන සාදන්න", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index a79085fe4936..a0dc242ff27a 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Povoľte adaptívne virtuálne vstupné pruhy pre každého nájomcu (tenant) pri odosielaní poskytovateľom (#9654): špička jedného nájomcu už nespôsobí 503 u iného. Premenná prostredia OMNIROUTE_CHAT_VIRTUAL_LANES má prednosť pred týmto nastavením v riadiacom paneli; zmeny sa prejavia po reštarte servera.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Stránky poskytovateľov na ovládacom paneli: zobrazovať odznak Bezplatné iba na základe signálov, ktoré poskytovateľ uznáva — nepoužíva sa heuristika zobrazovaného názvu, polia bez booleovskej hodnoty označujúce bezplatnosť ani prípony :free pri registrovaných poskytovateľoch bez zdokumentovanej bezplatnej úrovne. Vypnutie zachová pôvodné pravidlo zobrazovania odznaku.", "featureFlagProxySkipRecentlyFailedDescription": "Fondy proxy serverov a rotácia opencode pre jednotlivé účty prestanú počas obdobia platného pre daný proces opätovne používať proxy server, ktorý práve zlyhal (odmietnutá sonda TCP alebo odpoveď 429 prijatá cez tento proxy server). Toto obdobie sa pri každom opakovaní zdvojnásobí až po stanovený limit. Stav proxy servera sa nezapisuje; ak sú všetci kandidáti odložení bokom, výber zostáva nezmenený. Predvolene zapnuté; `false` obnoví bežný výber.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Pre poskytovateľov, ktorých kvóta je rozdelená podľa egress adresy, zaraďte člena fondu zdieľajúceho zaznamenanú egress adresu nedávno odmietnutého člena tesne za zdravých členov. Iba zmena poradia, nikdy nie vylúčenie. Vyžaduje PROXY_SKIP_RECENTLY_FAILED, ktoré generuje signál odmietnutia, z ktorého číta. Predvolene vypnuté: poradie výberu presne zodpovedá bežnej rotácii.", "featureFlagProxyPoolEgressObservationDescription": "V ovládacom paneli zobraziť pod fondom proxy serverov, cez koľko pozorovaných výstupných IP adries komunikovali jeho členovia za posledných 24 h, koľko pripojení ich použilo a aký najvyšší počet pripojení bol zaznamenaný za jednou IP adresou. Iba na čítanie, vypočítané z denníka proxy servera a nikdy nepoužívané na smerovanie. Predvolene vypnuté: editor fondu zostáva nezmenený a trasa pozorovania vracia null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Pri kontrole stavu proxy serverov umožniť, aby sonda odmietnutá cieľom (401/403/429: proxy server ju preniesol, ale cieľ odmietol túto výstupnú IP adresu) vynulovala sériu po sebe nasledujúcich zlyhaní proxy servera rovnako ako obslúžená sonda. Predvolene vypnuté: odmietnutie zostáva neutrálne a zachováva sériu. Odpoveď 5xx zostáva v oboch prípadoch nejednoznačná a odmietnutie nikdy neodstráni, nezakáže ani znovu neaktivuje proxy server.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Povoliť automatickému čisteniu odstraňovať ukončené (dokončené/neúspešné/zrušené/expirované) úlohy Batch API staršie než OMNIROUTE_BATCH_RETENTION_DAYS spolu s ich kontrolnými bodmi pre jednotlivé riadky a vymazať obsah BLOB nahraných súborov po uplynutí ich vlastného expires_at. Predvolene vypnuté: každá existujúca inštalácia uchováva tieto údaje presne ako doteraz, kým operátor túto funkciu nezapne. Trasa DELETE /api/v1/batches/delete-completed spúšťaná operátorom zostáva v oboch prípadoch nedotknutá – ide o samostatný, bezpodmienečný verejný kontrakt API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Aktualizácia je k dispozícii: v{current} → v{latest}", "cliproxyapiVersion": "Verzia" }, + "modelCatalog": { + "title": "Modely a kombá", + "subtitle": "Prehliadajte a testujte stav modelov a smerovacích pipelines komb naprieč všetkými poskytovateľmi.", + "refresh": "Obnoviť", + "modelsTab": "Modely", + "combosTab": "Kombá", + "catalogSections": "Sekcie katalógu", + "loading": "Načítava sa...", + "retry": "Skúsiť znova", + "unableToLoad": "Nepodarilo sa načítať katalóg modelov.", + "unableToLoadCombos": "Nepodarilo sa načítať kombá.", + "checkConnection": "Skontrolujte pripojenie a skúste to znova.", + "noModelsAvailable": "Zatiaľ nie sú k dispozícii žiadne modely.", + "noModelsMatch": "Týmto filtrom nezodpovedajú žiadne modely.", + "noCombosAvailable": "Zatiaľ nie sú k dispozícii žiadne kombá.", + "noCombosMatch": "Týmto filtrom nezodpovedajú žiadne kombá.", + "clearFilters": "Vymazať filtre", + "searchModels": "Hľadať modely", + "searchModelsPlaceholder": "Hľadať podľa modelu, poskytovateľa alebo schopnosti", + "searchCombos": "Hľadať kombá", + "searchCombosPlaceholder": "Hľadať podľa názvu komba, modelov alebo popisu", + "modelCountSingle": "model", + "modelCountPlural": "modely", + "comboCountSingle": "kombo", + "comboCountPlural": "kombá", + "provider": "Poskytovateľ", + "allProviders": "Všetci poskytovatelia", + "type": "Typ", + "allTypes": "Všetky typy", + "subtype": "Podtyp", + "allSubtypes": "Všetky podtypy", + "capability": "Schopnosť", + "allCapabilities": "Všetky schopnosti", + "pricing": "Ceny", + "allPricing": "Všetky ceny", + "freeOnly": "Iba bezplatné", + "nonFree": "Štandardné / platené", + "providerHealth": "Stav poskytovateľa", + "allHealthStates": "Všetky stavy", + "healthy": "V poriadku", + "degraded": "Zhoršený stav", + "down": "Nedostupné", + "testResult": "Výsledok testu", + "allResults": "Všetky výsledky", + "untested": "Netestované", + "statusOk": "OK", + "statusSlow": "Pomalé", + "statusError": "Chyba", + "minContext": "Minimálny kontext", + "minContextPlaceholder": "napr. 32000", + "strategy": "Stratégia", + "allStrategies": "Všetky stratégie", + "status": "Stav", + "allStatuses": "Všetky stavy", + "active": "Aktívne", + "paused": "Pozastavené", + "minMembers": "Min. počet členov", + "minMembersPlaceholder": "napr. 1", + "maxMembers": "Max. počet členov", + "maxMembersPlaceholder": "napr. 10", + "testSelected": "Otestovať vybrané ({count})", + "testAllFiltered": "Otestovať všetky filtrované ({count})", + "cancel": "Zrušiť", + "clearResults": "Vymazať výsledky", + "testing": "Testuje sa...", + "rateLimited": "Prekročený limit požiadaviek", + "quotaExceeded": "Prekročená kvóta", + "timeout": "Časový limit vypršal", + "otherError": "Chyba", + "justNow": "Práve teraz", + "minutesAgo": "pred {count} min", + "hoursAgo": "pred {count} h", + "tableRegion": "Tabuľka katalógu modelov", + "combosTableRegion": "Tabuľka katalógu kombinácií", + "tableCaption": "Katalóg modelov naprieč všetkými poskytovateľmi", + "combosTableCaption": "Katalóg kombinácií s výsledkami testov stavu", + "selectAllModels": "Vybrať všetky modely na tejto stránke", + "selectAllCombos": "Vybrať všetky kombinácie na tejto stránke", + "selectModel": "Vybrať model {name}", + "selectCombo": "Vybrať kombináciu {name}", + "model": "Model", + "capabilities": "Schopnosti", + "context": "Kontext", + "output": "Maximálny výstup", + "flags": "Príznaky", + "healthTest": "Test stavu", + "actions": "Akcie", + "test": "Otestovať", + "custom": "Vlastné", + "free": "Bezplatné", + "noFlags": "Nebola nahlásená žiadna cena ani príznak zdroja", + "noCapabilities": "Neboli nahlásené žiadne metadáta o schopnostiach", + "showingModels": "Zobrazuje sa {first} – {last} z {total} modelov", + "showingCombos": "Zobrazuje sa {first} – {last} z {total} kombinácií", + "refreshing": "Obnovuje sa…", + "refreshFailed": "Obnovenie zlyhalo. Zobrazuje sa naposledy načítaný katalóg.", + "page": "Stránka {page} z {pageCount}", + "previous": "Predchádzajúca", + "next": "Nasledujúca", + "combo": "Kombinácia", + "members": "Členovia", + "moreMembers": "+{count} ďalších" + }, "combos": { "title": "kombá", "description": "Vytvárajte kombinácie modelov s váženým smerovaním a záložnou podporou", diff --git a/src/i18n/messages/sl.json b/src/i18n/messages/sl.json index eea19776fb35..3551b80c52b4 100644 --- a/src/i18n/messages/sl.json +++ b/src/i18n/messages/sl.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Omogoči prilagodljive navidezne sprejemne pasove za posameznega najemnika pri posredovanju ponudniku (#9654): nenaden porast zahtev enega najemnika ne povzroča več napak 503 pri drugem. Spremenljivka okolja OMNIROUTE_CHAT_VIRTUAL_LANES ima prednost pred to nastavitvijo nadzorne plošče; spremembe začnejo veljati po ponovnem zagonu strežnika.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Strani ponudnikov na nadzorni plošči: značko Brezplačno prikaži samo pri signalih, ki jih ponudnik upošteva — brez hevristike prikaznega imena, neboolovskih polj free in pripon :free pri registriranih ponudnikih brez dokumentirane brezplačne ravni. Izklopljeno ohrani preteklo pravilo za značke.", "featureFlagProxySkipRecentlyFailedDescription": "Skupine posredniških strežnikov in vrtenje opencode za posamezen račun za določeno obdobje znotraj procesa prenehajo znova uporabljati posredniški strežnik, ki je pravkar odpovedal (zavrnjeno preverjanje TCP ali prek njega prejeta napaka 429). To obdobje se ob vsaki ponovitvi podvoji do določene zgornje meje. Stanje posredniškega strežnika se ne zapiše; če so vsi kandidati izločeni, izbira ostane nespremenjena. Privzeto vklopljeno; `false` obnovi običajno izbiro.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Za ponudnike, katerih kvota je razdeljena po izhodnem naslovu, uvrsti člana bazena, ki si deli zabeleženi izhodni naslov nedavno zavrnjenega člana, tik pod zdrave člane. Vpliva samo na vrstni red, nikoli ni izključen. Zahteva PROXY_SKIP_RECENTLY_FAILED, ki ustvari signal zavrnitve, ki ga ta možnost bere. Privzeto izklopljeno: vrstni red izbire je natanko običajna rotacija.", "featureFlagProxyPoolEgressObservationDescription": "Na nadzorni plošči pod skupino posredniških strežnikov prikaži, koliko opaženih izhodnih naslovov IP so v zadnjih 24 h uporabljali njeni člani, koliko povezav jih je uporabilo in največje število povezav prek enega naslova IP. Podatki so samo za branje, izračunani iz dnevnika posredniškega strežnika in se nikoli ne uporabljajo za usmerjanje. Privzeto izklopljeno: urejevalnik skupine ostane nespremenjen, opazovalna pot pa vrne null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Pri preverjanju zdravja posredniških strežnikov naj sonda, ki jo je cilj zavrnil (401/403/429: posredniški strežnik jo je posredoval, cilj pa je zavrnil ta izhodni naslov IP), ponastavi niz zaporednih neuspehov posredniškega strežnika, tako kot uspešno izvedena sonda. Privzeto izklopljeno: zavrnitev ostane nevtralna in ohrani niz. Odziv 5xx v obeh primerih ostane nedoločen, zavrnitev pa posredniškega strežnika nikoli ne odstrani, onemogoči ali znova aktivira.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Dovolite, da samodejno čiščenje izbriše končana (uspešno zaključena/neuspešna/preklicana/potekla) opravila Batch API, starejša od OMNIROUTE_BATCH_RETENTION_DAYS, skupaj z njihovimi kontrolnimi točkami za posamezne vrstice, ter počisti vsebino BLOB naloženih datotek, ki jim je potekel njihov expires_at. Privzeto je izklopljeno: vsaka obstoječa namestitev te podatke ohrani popolnoma enako kot prej, dokler skrbnik funkcije ne omogoči. To v nobenem primeru ne vpliva na pot DELETE /api/v1/batches/delete-completed, ki jo sproži skrbnik – gre za ločeno, brezpogojno javno pogodbo API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Na voljo je posodobitev: v{current} → v{latest}", "cliproxyapiVersion": "Različica" }, + "modelCatalog": { + "title": "Modeli in kombinacije", + "subtitle": "Brskajte in preverjajte delovanje modelov ter usmerjevalnih cevovodov kombinacij pri vseh ponudnikih.", + "refresh": "Osveži", + "modelsTab": "Modeli", + "combosTab": "Kombinacije", + "catalogSections": "Razdelki kataloga", + "loading": "Nalaganje...", + "retry": "Poskusi znova", + "unableToLoad": "Kataloga modelov ni mogoče naložiti.", + "unableToLoadCombos": "Kombinacij ni mogoče naložiti.", + "checkConnection": "Preverite povezavo in poskusite znova.", + "noModelsAvailable": "Noben model še ni na voljo.", + "noModelsMatch": "Noben model ne ustreza tem filtrom.", + "noCombosAvailable": "Nobena kombinacija še ni na voljo.", + "noCombosMatch": "Nobena kombinacija ne ustreza tem filtrom.", + "clearFilters": "Počisti filtre", + "searchModels": "Išči modele", + "searchModelsPlaceholder": "Iskanje po modelu, ponudniku ali zmožnosti", + "searchCombos": "Išči kombinacije", + "searchCombosPlaceholder": "Iskanje po imenu kombinacije, modelih ali opisu", + "modelCountSingle": "model", + "modelCountPlural": "modeli", + "comboCountSingle": "kombinacija", + "comboCountPlural": "kombinacije", + "provider": "Ponudnik", + "allProviders": "Vsi ponudniki", + "type": "Vrsta", + "allTypes": "Vse vrste", + "subtype": "Podvrsta", + "allSubtypes": "Vse podvrste", + "capability": "Zmožnost", + "allCapabilities": "Vse zmožnosti", + "pricing": "Cene", + "allPricing": "Vse cene", + "freeOnly": "Samo brezplačno", + "nonFree": "Standardno / Plačljivo", + "providerHealth": "Stanje ponudnika", + "allHealthStates": "Vsa stanja", + "healthy": "Brezhibno", + "degraded": "Poslabšano", + "down": "Ne deluje", + "testResult": "Rezultat preizkusa", + "allResults": "Vsi rezultati", + "untested": "Nepreizkušeno", + "statusOk": "V redu", + "statusSlow": "Počasno", + "statusError": "Napaka", + "minContext": "Minimalni kontekst", + "minContextPlaceholder": "npr. 32000", + "strategy": "Strategija", + "allStrategies": "Vse strategije", + "status": "Stanje", + "allStatuses": "Vsa stanja", + "active": "Aktivno", + "paused": "V premoru", + "minMembers": "Minimalno članov", + "minMembersPlaceholder": "npr. 1", + "maxMembers": "Maksimalno članov", + "maxMembersPlaceholder": "npr. 10", + "testSelected": "Preizkusi izbrane ({count})", + "testAllFiltered": "Preizkusi vse filtrirane ({count})", + "cancel": "Prekliči", + "clearResults": "Počisti rezultate", + "testing": "Preizkušanje...", + "rateLimited": "Presežena omejitev zahtev", + "quotaExceeded": "Presežena kvota", + "timeout": "Časovna omejitev potekla", + "otherError": "Napaka", + "justNow": "Pravkar", + "minutesAgo": "pred {count} m", + "hoursAgo": "pred {count} h", + "tableRegion": "Tabela kataloga modelov", + "combosTableRegion": "Tabela kataloga kombinacij", + "tableCaption": "Katalog modelov pri vseh ponudnikih", + "combosTableCaption": "Katalog kombinacij z rezultati preizkusov delovanja", + "selectAllModels": "Izberi vse modele na tej strani", + "selectAllCombos": "Izberi vse kombinacije na tej strani", + "selectModel": "Izberi model {name}", + "selectCombo": "Izberi kombinacijo {name}", + "model": "Model", + "capabilities": "Zmogljivosti", + "context": "Kontekst", + "output": "Največji izhod", + "flags": "Zastavice", + "healthTest": "Preizkus stanja", + "actions": "Dejanja", + "test": "Preizkus", + "custom": "Po meri", + "free": "Brezplačno", + "noFlags": "Ni sporočene cene ali izvorne zastavice", + "noCapabilities": "Ni sporočenih metapodatkov o zmogljivostih", + "showingModels": "Prikazovanje {first}–{last} od {total} modelov", + "showingCombos": "Prikazovanje {first}–{last} od {total} kombinacij", + "refreshing": "Osveževanje…", + "refreshFailed": "Osvežitev ni uspela. Prikazan je zadnji naloženi katalog.", + "page": "Stran {page} od {pageCount}", + "previous": "Prejšnja", + "next": "Naslednja", + "combo": "Kombinacija", + "members": "Člani", + "moreMembers": "+{count} več" + }, "combos": { "title": "Kombinacije", "description": "Ustvarite kombinacije modelov z uteženim usmerjanjem in podporo za nadomestne možnosti", diff --git a/src/i18n/messages/sr.json b/src/i18n/messages/sr.json index bf1f1e01bea7..f3e59a889891 100644 --- a/src/i18n/messages/sr.json +++ b/src/i18n/messages/sr.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Омогући адаптивне виртуелне линије пријема по закупцу за слање захтева провајдерима (#9654): нагли скок захтева једног закупца више не изазива 503 грешку код другог. Env варијабла OMNIROUTE_CHAT_VIRTUAL_LANES има приоритет над овим прекидачем у контролној табли; промене се примењују при поновном покретању сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Странице добављача на контролној табли: приказују ознаку „Бесплатно“ само за сигнале које добављач уважава — без претпоставки на основу приказаног назива, небуловских поља за бесплатан приступ и суфикса :free код регистрованих добављача без документованог бесплатног пакета. Када је искључено, задржава се претходно правило за приказ ознаке.", "featureFlagProxySkipRecentlyFailedDescription": "Прокси скупови и ротација по налогу у opencode престају да поново користе прокси који је управо отказао (одбијена TCP провера или одговор 429 примљен преко њега) током периода на нивоу процеса који се удвостручује при сваком понављању, до задате горње границе. Статус проксија се не уписује; када су сви кандидати издвојени, избор остаје непромењен. Подразумевано је укључено; `false` враћа обичан избор.", - "featureFlagProxyPoolSharedEgressOrderDescription": "За пружаоце услуга чија је квота груписана према излазној адреси, рангирај члана пула који дели уочену излазну адресу недавно одбијеног члана одмах испод здравих чланова. Само редослед, никада се не искључује. Захтева PROXY_SKIP_RECENTLY_FAILED, који производи сигнал одбијања који се овде чита. Подразумевано искључено: редослед избора је управо обична ротација.", "featureFlagProxyPoolEgressObservationDescription": "У контролној табли, испод прокси скупа, прикажите колико је уочених излазних IP адреса опслуживало његове чланове током последња 24 ч, колико веза их је користило и највећи број веза забележен иза једне IP адресе. Само за читање, израчунава се из евиденције проксија и никада се не користи за усмеравање. Подразумевано је искључено: уређивач скупа остаје непромењен, а рута за посматрање враћа null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "У провери исправности проксија омогућите да провера коју је циљ одбио (401/403/429: прокси је проследио захтев, а одредиште је одбило ову излазну IP адресу) ресетује низ узастопних неуспеха проксија, као и успешно опслужена провера. Подразумевано је искључено: одбијање остаје неутрално и задржава низ. Одговор 5xx у оба случаја остаје неодређен, а одбијање никада не уклања, не онемогућава нити поново активира прокси.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Дозволи аутоматском чишћењу да избрише завршене (успешне/неуспешне/отказане/истекле) Batch API послове старије од вредности OMNIROUTE_BATCH_RETENTION_DAYS, заједно са њиховим контролним тачкама по редовима, и да обрише BLOB садржај отпремљених датотека након њиховог сопственог expires_at. Подразумевано је искључено: свака постојећа инсталација наставља да чува ове податке потпуно исто као раније док оператер не омогући ову опцију. Рута DELETE /api/v1/batches/delete-completed коју покреће оператер ни у једном случају није погођена — она представља засебан, безуслован уговор јавног API-ја.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Доступно ажурирање: v{current} → v{latest}", "cliproxyapiVersion": "Верзија" }, + "modelCatalog": { + "title": "Модели и комбинације", + "subtitle": "Прегледајте и тестирајте исправност модела и токова рутирања комбинација код свих добављача.", + "refresh": "Освежи", + "modelsTab": "Модели", + "combosTab": "Комбинације", + "catalogSections": "Одељци каталога", + "loading": "Учитавање...", + "retry": "Покушај поново", + "unableToLoad": "Учитавање каталога модела није успело.", + "unableToLoadCombos": "Учитавање комбинација није успело.", + "checkConnection": "Проверите везу и покушајте поново.", + "noModelsAvailable": "Још увек нема доступних модела.", + "noModelsMatch": "Ниједан модел не одговара овим филтерима.", + "noCombosAvailable": "Још увек нема доступних комбинација.", + "noCombosMatch": "Ниједна комбинација не одговара овим филтерима.", + "clearFilters": "Обриши филтере", + "searchModels": "Претражи моделе", + "searchModelsPlaceholder": "Претражи по моделу, добављачу или могућности", + "searchCombos": "Претражи комбинације", + "searchCombosPlaceholder": "Претражи по називу комбинације, моделима или опису", + "modelCountSingle": "модел", + "modelCountPlural": "модели", + "comboCountSingle": "комбинација", + "comboCountPlural": "комбинације", + "provider": "Добављач", + "allProviders": "Сви добављачи", + "type": "Тип", + "allTypes": "Сви типови", + "subtype": "Подтип", + "allSubtypes": "Сви подтипови", + "capability": "Могућност", + "allCapabilities": "Све могућности", + "pricing": "Цене", + "allPricing": "Све цене", + "freeOnly": "Само бесплатно", + "nonFree": "Стандардно / Плаћено", + "providerHealth": "Исправност добављача", + "allHealthStates": "Сва стања исправности", + "healthy": "Исправно", + "degraded": "Деградирано", + "down": "Недоступан", + "testResult": "Резултат теста", + "allResults": "Сви резултати", + "untested": "Није тестирано", + "statusOk": "У реду", + "statusSlow": "Споро", + "statusError": "Грешка", + "minContext": "Мин. контекст", + "minContextPlaceholder": "нпр. 32000", + "strategy": "Стратегија", + "allStrategies": "Све стратегије", + "status": "Статус", + "allStatuses": "Сви статуси", + "active": "Активан", + "paused": "Паузиран", + "minMembers": "Мин. чланова", + "minMembersPlaceholder": "нпр. 1", + "maxMembers": "Макс. чланова", + "maxMembersPlaceholder": "нпр. 10", + "testSelected": "Тестирај изабране ({count})", + "testAllFiltered": "Тестирај све филтриране ({count})", + "cancel": "Откажи", + "clearResults": "Обриши резултате", + "testing": "Тестирање...", + "rateLimited": "Ограничен број захтева", + "quotaExceeded": "Прекорачена квота", + "timeout": "Време је истекло", + "otherError": "Грешка", + "justNow": "Управо сада", + "minutesAgo": "пре {count} мин", + "hoursAgo": "пре {count} ч", + "tableRegion": "Табела каталога модела", + "combosTableRegion": "Табела каталога комбинација", + "tableCaption": "Каталог модела свих добављача", + "combosTableCaption": "Каталог комбинација са резултатима провере исправности", + "selectAllModels": "Изабери све моделе на овој страници", + "selectAllCombos": "Изабери све комбинације на овој страници", + "selectModel": "Изабери модел {name}", + "selectCombo": "Изабери комбинацију {name}", + "model": "Модел", + "capabilities": "Могућности", + "context": "Контекст", + "output": "Максимални излаз", + "flags": "Ознаке", + "healthTest": "Тест исправности", + "actions": "Радње", + "test": "Тест", + "custom": "Прилагођено", + "free": "Бесплатно", + "noFlags": "Није пријављена цена нити ознака извора", + "noCapabilities": "Нису пријављени метаподаци о могућностима", + "showingModels": "Приказује се {first}–{last} од {total} модела", + "showingCombos": "Приказује се {first}–{last} од {total} комбинација", + "refreshing": "Освежавање…", + "refreshFailed": "Освежавање није успело. Приказује се последњи учитани каталог.", + "page": "Страница {page} од {pageCount}", + "previous": "Претходна", + "next": "Следећа", + "combo": "Комбинација", + "members": "Чланови", + "moreMembers": "+{count} још" + }, "combos": { "title": "Комбинације", "description": "Креирајте комбинације модела са пондерисаним рутирањем и подршком за резервне опције", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 57ac46c8ef2b..7ef7ed317f62 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Aktivera adaptiva virtuella åtkomstfiler per tenant för providerutskick (#9654): en tenants burst ger inte längre en annan 503. Miljövariabeln OMNIROUTE_CHAT_VIRTUAL_LANES har företräde framför den här inställningen i instrumentpanelen; ändringarna träder i kraft vid omstart av servern.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Leverantörssidor på kontrollpanelen: visa märket Gratis endast utifrån uppgifter som leverantören bekräftar – bortse från heuristiken för visningsnamn, icke-booleska gratisfält och suffixet :free för registrerade leverantörer utan en dokumenterad kostnadsfri nivå. Av behåller den tidigare märkesregeln.", "featureFlagProxySkipRecentlyFailedDescription": "Proxypooler och rotationen per konto för opencode slutar att återanvända en proxy som nyss misslyckades (nekad TCP-kontroll eller ett 429-svar som togs emot via den) under en processpecifik period som fördubblas vid varje upprepat fel, upp till en maxgräns. Ingen proxystatus skrivs; om alla kandidater läggs åt sidan förblir valet oförändrat. Påslaget som standard; `false` återställer det vanliga urvalet.", - "featureFlagProxyPoolSharedEgressOrderDescription": "För leverantörer vars kvot är uppdelad per utgående adress, rangordna en poolmedlem som delar en nyligen nekad medlems observerade utgående adress strax under felfria medlemmar. Endast ordning, exkluderas aldrig. Kräver PROXY_SKIP_RECENTLY_FAILED, som genererar avvisningssignalen den läser. Inaktiverad som standard: urvalsordningen är exakt den vanliga rotationen.", "featureFlagProxyPoolEgressObservationDescription": "Visa under en proxypool på instrumentpanelen hur många observerade utgående IP-adresser som betjänade dess medlemmar under de senaste 24 timmarna, hur många anslutningar som använde dem och det högsta antalet som observerades bakom en och samma IP-adress. Skrivskyddat, beräknat från proxyloggen och används aldrig för dirigering. Avstängt som standard: poolredigeraren är oförändrad och observationsrutten returnerar null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Låt en kontroll som avvisades av målet (401/403/429: proxyn vidarebefordrade begäran men destinationen avvisade den utgående IP-adressen) nollställa proxyns serie av på varandra följande fel i proxyhälsokontrollen, precis som en besvarad kontroll. Avstängt som standard: ett avvisande förblir neutralt och bibehåller serien. Ett 5xx-svar förblir icke avgörande i båda fallen, och ett avvisande tar aldrig bort, inaktiverar eller återaktiverar en proxy.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Låt den automatiska rensningen ta bort avslutade (slutförda/misslyckade/avbrutna/utgångna) Batch API-jobb som är äldre än OMNIROUTE_BATCH_RETENTION_DAYS, tillsammans med deras kontrollpunkter per rad, och rensa BLOB-innehållet i uppladdade filer efter deras egna expires_at. Av som standard: varje befintlig installation behåller dessa data precis som tidigare tills en operatör väljer att aktivera funktionen. Den operatörsutlösta rutten DELETE /api/v1/batches/delete-completed påverkas inte oavsett inställning – det är ett separat, ovillkorligt offentligt API-kontrakt.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Uppdatering tillgänglig: v{current} → v{latest}", "cliproxyapiVersion": "Version" }, + "modelCatalog": { + "title": "Modeller & kombinationer", + "subtitle": "Bläddra bland och hälsotesta modeller och pipelines för kombinationsroutning hos alla leverantörer.", + "refresh": "Uppdatera", + "modelsTab": "Modeller", + "combosTab": "Kombinationer", + "catalogSections": "Katalogsektioner", + "loading": "Läser in...", + "retry": "Försök igen", + "unableToLoad": "Det gick inte att läsa in modellkatalogen.", + "unableToLoadCombos": "Det gick inte att läsa in kombinationer.", + "checkConnection": "Kontrollera anslutningen och försök igen.", + "noModelsAvailable": "Inga modeller är tillgängliga ännu.", + "noModelsMatch": "Inga modeller matchar dessa filter.", + "noCombosAvailable": "Inga kombinationer är tillgängliga ännu.", + "noCombosMatch": "Inga kombinationer matchar dessa filter.", + "clearFilters": "Rensa filter", + "searchModels": "Sök modeller", + "searchModelsPlaceholder": "Sök efter modell, leverantör eller förmåga", + "searchCombos": "Sök kombinationer", + "searchCombosPlaceholder": "Sök efter kombinationsnamn, modeller eller beskrivning", + "modelCountSingle": "modell", + "modelCountPlural": "modeller", + "comboCountSingle": "kombination", + "comboCountPlural": "kombinationer", + "provider": "Leverantör", + "allProviders": "Alla leverantörer", + "type": "Typ", + "allTypes": "Alla typer", + "subtype": "Undertyp", + "allSubtypes": "Alla undertyper", + "capability": "Förmåga", + "allCapabilities": "Alla förmågor", + "pricing": "Prissättning", + "allPricing": "All prissättning", + "freeOnly": "Endast gratis", + "nonFree": "Standard / Ej gratis", + "providerHealth": "Leverantörshälsa", + "allHealthStates": "Alla hälsotillstånd", + "healthy": "Frisk", + "degraded": "Försämrad", + "down": "Nere", + "testResult": "Testresultat", + "allResults": "Alla resultat", + "untested": "Ej testad", + "statusOk": "OK", + "statusSlow": "Långsam", + "statusError": "Fel", + "minContext": "Minsta kontext", + "minContextPlaceholder": "t.ex. 32000", + "strategy": "Strategi", + "allStrategies": "Alla strategier", + "status": "Status", + "allStatuses": "Alla statusar", + "active": "Aktiv", + "paused": "Pausad", + "minMembers": "Minsta antal medlemmar", + "minMembersPlaceholder": "t.ex. 1", + "maxMembers": "Högsta antal medlemmar", + "maxMembersPlaceholder": "t.ex. 10", + "testSelected": "Testa markerade ({count})", + "testAllFiltered": "Testa alla filtrerade ({count})", + "cancel": "Avbryt", + "clearResults": "Rensa resultat", + "testing": "Testar...", + "rateLimited": "Hastighetsbegränsad", + "quotaExceeded": "Kvot överskriden", + "timeout": "Tidsgräns överskriden", + "otherError": "Fel", + "justNow": "Alldeles nyss", + "minutesAgo": "{count}m sedan", + "hoursAgo": "{count}h sedan", + "tableRegion": "Tabell för modellkatalog", + "combosTableRegion": "Tabell för kombinationskatalog", + "tableCaption": "Modellkatalog över alla leverantörer", + "combosTableCaption": "Kombinationskatalog med hälsotestresultat", + "selectAllModels": "Markera alla modeller på denna sida", + "selectAllCombos": "Markera alla kombinationer på denna sida", + "selectModel": "Markera modell {name}", + "selectCombo": "Markera kombination {name}", + "model": "Modell", + "capabilities": "Förmågor", + "context": "Kontext", + "output": "Max utdata", + "flags": "Flaggor", + "healthTest": "Hälsotest", + "actions": "Åtgärder", + "test": "Testa", + "custom": "Anpassad", + "free": "Gratis", + "noFlags": "Inget pris eller källflagga rapporterad", + "noCapabilities": "Ingen metadata om förmågor rapporterad", + "showingModels": "Visar {first}–{last} av {total} modeller", + "showingCombos": "Visar {first}–{last} av {total} kombinationer", + "refreshing": "Uppdaterar…", + "refreshFailed": "Uppdateringen misslyckades. Visar den senast inlästa katalogen.", + "page": "Sida {page} av {pageCount}", + "previous": "Föregående", + "next": "Nästa", + "combo": "Kombination", + "members": "Medlemmar", + "moreMembers": "+{count} fler" + }, "combos": { "title": "Kombinationer", "description": "Skapa modellkombinationer med viktad routing och reservstöd", diff --git a/src/i18n/messages/sw.json b/src/i18n/messages/sw.json index 7ad2c0e01a6b..774b43eddea4 100644 --- a/src/i18n/messages/sw.json +++ b/src/i18n/messages/sw.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Washa njia za uandikishaji pepe zinazobadilika kwa kila mpangaji (tenant) kwa utumaji wa watoa huduma (#9654): mlipuko wa mpangaji mmoja hautoi tena 503 kwa mwingine. Kigezo cha mazingira cha OMNIROUTE_CHAT_VIRTUAL_LANES kinashinda mpangilio huu wa dashibodi; mabadiliko yanatumika wakati seva inapoanzishwa upya.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Kurasa za watoa huduma kwenye dashibodi: onyesha beji ya Bila Malipo kwenye viashiria ambavyo mtoa huduma anavitambua pekee — huondoa utambuzi wa kukisia kwa kutumia jina la kuonyesha, sehemu zisizo za Boolean zinazoashiria huduma ya bila malipo, na viambishi :free kwa watoa huduma waliosajiliwa ambao hawana kiwango cha huduma ya bila malipo kilichoandikwa. Kuzima huhifadhi kanuni ya awali ya beji.", "featureFlagProxySkipRecentlyFailedDescription": "Makundi ya proksi na uzungushaji wa kila akaunti wa opencode huacha kutumia tena proksi iliyoshindwa hivi punde (jaribio la TCP lilikataliwa, au 429 ilipokelewa kupitia proksi hiyo) kwa kipindi maalumu kwa kila mchakato, ambacho huongezeka maradufu kila kushindwa kunaporudiwa, hadi kikomo fulani. Hakuna hali ya proksi inayoandikwa; kila chaguo linalowezekana likiwekwa kando, uteuzi hubaki bila kubadilika. Imewashwa kwa chaguo-msingi; `false` hurejesha uteuzi wa kawaida.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Kwa watoa huduma ambao kiwango chao kimegawanywa kulingana na anwani ya egress, panga mwanachama wa pool anayeshiriki anwani ya egress iliyoonekana ya mwanachama aliyekataliwa hivi karibuni chini kidogo ya wanachama wenye afya. Ni upangaji tu, haondolewi kamwe. Inahitaji PROXY_SKIP_RECENTLY_FAILED, ambayo hutoa ishara ya kukataliwa inayoisoma. Imezimwa kwa chaguo-msingi: mpangilio wa uteuzi ni mzunguko wa kawaida kabisa.", "featureFlagProxyPoolEgressObservationDescription": "Onyesha, chini ya kundi la proksi kwenye dashibodi, idadi ya anwani za IP za kutoka zilizozingatiwa ambazo zilitumiwa na wanachama wake katika saa 24 zilizopita, idadi ya miunganisho iliyozitumia, na idadi kubwa zaidi iliyoonekana nyuma ya anwani moja ya IP. Ni ya kusoma pekee, huhesabiwa kutoka kwenye kumbukumbu ya proksi, na haitumiki kamwe kuelekeza trafiki. Imezimwa kwa chaguo-msingi: kihariri cha kundi hakibadiliki na njia ya uchunguzi hujibu null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Katika ukaguzi wa afya ya proksi, ruhusu jaribio lililokataliwa na lengwa (401/403/429: proksi ilisambaza ombi, lakini lengwa lilikataa anwani hii ya IP ya kutoka) liweke upya mfululizo wa kushindwa kwa proksi, kama jaribio lililohudumiwa. Imezimwa kwa chaguo-msingi: kukataliwa hubaki bila upande na hudumisha mfululizo huo. 5xx hubaki bila hitimisho kwa vyovyote vile, na kukataliwa kamwe hakuondoi, hakuzima wala kuwezesha tena proksi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Ruhusu usafishaji wa kiotomatiki ufute kazi za Batch API zilizo katika hali ya mwisho (zilizokamilika/zilizoshindwa/zilizoghairiwa/zilizopitwa na muda) ambazo ni za zamani kuliko OMNIROUTE_BATCH_RETENTION_DAYS, pamoja na vituo vyake vya ukaguzi vya kila mstari, na ufute maudhui ya BLOB ya faili zilizopakiwa ambazo muda wake wa expires_at umepita. Huzimwa kwa chaguo-msingi: kila usakinishaji uliopo utaendelea kuhifadhi data hii kama hapo awali hadi mwendeshaji atakapochagua kuwasha kipengele hiki. Njia ya DELETE /api/v1/batches/delete-completed inayoanzishwa na mwendeshaji haiathiriwi kwa vyovyote vile — ni mkataba tofauti wa API ya umma usio na masharti.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Sasisho linapatikana: v{current} → v{latest}", "cliproxyapiVersion": "Toleo" }, + "modelCatalog": { + "title": "Miundo na Michanganyiko", + "subtitle": "Vinjari na ujaribu hali ya miundo na mifereji ya kuelekeza ya michanganyiko kwa kila mtoa huduma.", + "refresh": "Onyesha upya", + "modelsTab": "Miundo", + "combosTab": "Michanganyiko", + "catalogSections": "Sehemu za Katalogi", + "loading": "Inapakia...", + "retry": "Jaribu tena", + "unableToLoad": "Imeshindwa kupakia katalogi ya miundo.", + "unableToLoadCombos": "Imeshindwa kupakia michanganyiko.", + "checkConnection": "Angalia muunganisho na ujaribu tena.", + "noModelsAvailable": "Hakuna miundo inayopatikana bado.", + "noModelsMatch": "Hakuna miundo inayolingana na vichujio hivi.", + "noCombosAvailable": "Hakuna michanganyiko inayopatikana bado.", + "noCombosMatch": "Hakuna michanganyiko inayolingana na vichujio hivi.", + "clearFilters": "Futa vichujio", + "searchModels": "Tafuta miundo", + "searchModelsPlaceholder": "Tafuta kwa muundo, mtoa huduma, au uwezo", + "searchCombos": "Tafuta michanganyiko", + "searchCombosPlaceholder": "Tafuta kwa jina la mchanganyiko, miundo, au maelezo", + "modelCountSingle": "muundo", + "modelCountPlural": "miundo", + "comboCountSingle": "mchanganyiko", + "comboCountPlural": "michanganyiko", + "provider": "Mtoa huduma", + "allProviders": "Watoa huduma wote", + "type": "Aina", + "allTypes": "Aina zote", + "subtype": "Aina ndogo", + "allSubtypes": "Aina ndogo zote", + "capability": "Uwezo", + "allCapabilities": "Uwezo wote", + "pricing": "Bei", + "allPricing": "Bei zote", + "freeOnly": "Bila malipo tu", + "nonFree": "Kawaida / Yenye malipo", + "providerHealth": "Hali ya mtoa huduma", + "allHealthStates": "Hali zote za utendaji", + "healthy": "Nzuri", + "degraded": "Iliyodorora", + "down": "Haifanyi kazi", + "testResult": "Matokeo ya jaribio", + "allResults": "Matokeo yote", + "untested": "Haijajaribiwa", + "statusOk": "Sawa", + "statusSlow": "Polepole", + "statusError": "Hitilafu", + "minContext": "Muktadha wa chini", + "minContextPlaceholder": "k.m. 32000", + "strategy": "Mkakati", + "allStrategies": "Mikakati yote", + "status": "Hali", + "allStatuses": "Hali zote", + "active": "Amilifu", + "paused": "Imesitishwa", + "minMembers": "Wanachama wa chini", + "minMembersPlaceholder": "k.m. 1", + "maxMembers": "Wanachama wa juu", + "maxMembersPlaceholder": "k.m. 10", + "testSelected": "Jaribu zilizochaguliwa ({count})", + "testAllFiltered": "Jaribu zote zilizochujwa ({count})", + "cancel": "Ghairi", + "clearResults": "Futa matokeo", + "testing": "Inajaribu...", + "rateLimited": "Kikomo cha kiwango kimefikiwa", + "quotaExceeded": "Kiwango kimezidi", + "timeout": "Muda umekwisha", + "otherError": "Hitilafu", + "justNow": "Sasa hivi", + "minutesAgo": "{count}m zilizopita", + "hoursAgo": "{count}h zilizopita", + "tableRegion": "Jedwali la katalogi ya miundo", + "combosTableRegion": "Jedwali la katalogi ya michanganyiko", + "tableCaption": "Katalogi ya miundo kwa watoa huduma wote", + "combosTableCaption": "Katalogi ya michanganyiko yenye matokeo ya majaribio ya afya", + "selectAllModels": "Chagua miundo yote kwenye ukurasa huu", + "selectAllCombos": "Chagua michanganyiko yote kwenye ukurasa huu", + "selectModel": "Chagua muundo {name}", + "selectCombo": "Chagua mchanganyiko {name}", + "model": "Muundo", + "capabilities": "Uwezo", + "context": "Muktadha", + "output": "Kiwango cha juu cha matokeo", + "flags": "Bendera", + "healthTest": "Jaribio la Afya", + "actions": "Vitendo", + "test": "Jaribu", + "custom": "Maalum", + "free": "Bure", + "noFlags": "Hakuna bei au bendera ya chanzo iliyoripotiwa", + "noCapabilities": "Hakuna metadata ya uwezo iliyoripotiwa", + "showingModels": "Inaonyesha {first}–{last} kati ya miundo {total}", + "showingCombos": "Inaonyesha {first}–{last} kati ya michanganyiko {total}", + "refreshing": "Inapakia upya…", + "refreshFailed": "Kupakia upya kumeshindikana. Inaonyesha orodha ya mwisho iliyopakiwa.", + "page": "Ukurasa wa {page} kati ya {pageCount}", + "previous": "Iliyotangulia", + "next": "Inayofuata", + "combo": "Mchanganyiko", + "members": "Wanachama", + "moreMembers": "+{count} zaidi" + }, "combos": { "title": "Mikusanyiko", "description": "Unda mikusanyiko ya modeli yenye uelekezaji wenye uzani na usaidizi wa kutumia mbadala", diff --git a/src/i18n/messages/ta.json b/src/i18n/messages/ta.json index d2924fb61e5d..e98e0db33eb0 100644 --- a/src/i18n/messages/ta.json +++ b/src/i18n/messages/ta.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "வழங்குநர் அனுப்பீட்டிற்கு ஒவ்வொரு குத்தகைதாரருக்கும் (tenant) தகவமைப்பு மெய்நிகர் சேர்க்கைப் பாதைகளை இயக்கு (#9654): ஒரு குத்தகைதாரரின் அதிகரிப்பு இனி மற்றொருவருக்கு 503 ஐ அளிக்காது. OMNIROUTE_CHAT_VIRTUAL_LANES சூழல் மாறி இந்த டாஷ்போர்டு அமைப்பை விட முன்னுரிமை பெறுகிறது; மாற்றங்கள் சேவையகம் மறுதொடக்கத்தில் நடைமுறைக்கு வரும்.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "டாஷ்போர்டு வழங்குநர் பக்கங்கள்: வழங்குநர் ஏற்கும் குறியீடுகளில் மட்டும் இலவசம் என்ற அடையாளத்தைக் காட்டும் — ஆவணப்படுத்தப்பட்ட இலவச அடுக்கு இல்லாத பதிவுசெய்யப்பட்ட வழங்குநர்களுக்கான காட்சிப் பெயர் ஊகம், பூலியன் அல்லாத இலவசப் புலங்கள் மற்றும் :free பின்னொட்டுகளைப் புறக்கணிக்கும். இதை முடக்கினால், முந்தைய அடையாள விதி பயன்படுத்தப்படும்.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy குளங்களும் opencode-இன் ஒவ்வொரு கணக்கிற்குமான சுழற்சியும், இப்போது தோல்வியடைந்த ஒரு proxy-ஐ (மறுக்கப்பட்ட TCP ஆய்வு அல்லது அதன் வழியாகப் பெறப்பட்ட 429) ஒவ்வொரு செயல்முறைக்கும் உரிய ஒரு காலகட்டத்திற்கு மீண்டும் வழங்குவதை நிறுத்தும்; ஒவ்வொரு தொடர் தோல்வியின்போதும் அந்தக் காலகட்டம் இரட்டிப்பாகி, அதிகபட்ச வரம்பு வரை செல்லும். எந்த proxy நிலையும் எழுதப்படாது; ஒவ்வொரு தேர்வுக்குரியதும் ஒதுக்கி வைக்கப்பட்டால், தேர்வு மாறாமல் இருக்கும். இயல்பாக இயக்கப்பட்டிருக்கும்; `false` சாதாரண தேர்வை மீட்டமைக்கும்.", - "featureFlagProxyPoolSharedEgressOrderDescription": "வெளியேறும் முகவரியின்படி (egress address) ஒதுக்கீடு நிர்வகிக்கப்படும் வழங்குநர்களுக்கு, சமீபத்தில் நிராகரிக்கப்பட்ட உறுப்பினரின் கண்டறியப்பட்ட வெளியேறும் முகவரியைப் பகிரும் பூல் உறுப்பினரை, ஆரோக்கியமான உறுப்பினர்களுக்கு சற்று கீழே தரவரிசைப்படுத்துங்கள். வரிசை மட்டுமே மாற்றப்படும், ஒருபோதும் விலக்கப்படாது. இது படிக்கும் நிராகரிப்பு சிக்னலை உருவாக்கும் PROXY_SKIP_RECENTLY_FAILED இதற்குத் தேவை. இயல்பாக முடக்கப்பட்டுள்ளது: தேர்வு வரிசை என்பது துல்லியமாக வழக்கமான சுழற்சி முறையாகும்.", "featureFlagProxyPoolEgressObservationDescription": "டாஷ்போர்டில் ஒரு proxy குளத்தின் கீழ், கடந்த 24 மணிநேரத்தில் அதன் உறுப்பினர்களுக்குச் சேவையளித்த கண்டறியப்பட்ட வெளியேற்ற IP-களின் எண்ணிக்கை, அவற்றைப் பயன்படுத்திய இணைப்புகளின் எண்ணிக்கை மற்றும் ஓர் IP-க்குப் பின்னால் காணப்பட்ட அதிகபட்ச இணைப்புகளின் எண்ணிக்கை ஆகியவற்றைக் காட்டும். படிக்க மட்டும்; proxy பதிவிலிருந்து கணக்கிடப்படும்; வழித்தடத் தேர்வுக்கு ஒருபோதும் பயன்படுத்தப்படாது. இயல்பாக முடக்கப்பட்டிருக்கும்: குளத் திருத்தி மாறாமல் இருக்கும், மேலும் கண்காணிப்பு வழித்தடம் null எனப் பதிலளிக்கும்.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ஆரோக்கியச் சோதனையில், இலக்கு மறுத்த ஓர் ஆய்வு (401/403/429: proxy அதை அனுப்பியது, ஆனால் இலக்கு இந்த வெளியேற்ற IP-ஐ மறுத்தது), சேவையளிக்கப்பட்ட ஆய்வைப் போலவே proxy-இன் தொடர்ச்சியான தோல்வி வரிசையை மீட்டமைக்க அனுமதிக்கும். இயல்பாக முடக்கப்பட்டிருக்கும்: ஒரு மறுப்பு நடுநிலையாகவே இருந்து, தோல்வி வரிசையைத் தொடர வைத்திருக்கும். எந்த நிலையிலும் 5xx தீர்மானிக்க முடியாததாகவே இருக்கும்; மேலும் ஒரு மறுப்பு ஒருபோதும் proxy-ஐ அகற்றவோ, முடக்கவோ அல்லது மீண்டும் செயல்படுத்தவோ செய்யாது.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS-ஐ விடப் பழைய, இறுதி நிலையை அடைந்த (completed/failed/cancelled/expired) Batch API பணிகளையும், அவற்றின் ஒவ்வொரு வரிக்குமான checkpoints-ஐயும் தானியங்குச் சுத்தப்படுத்தல் நீக்க அனுமதிக்கவும்; மேலும், தங்களின் expires_at-ஐக் கடந்த பதிவேற்றப்பட்ட கோப்புகளின் BLOB உள்ளடக்கத்தை அழிக்கவும். இயல்பாக முடக்கப்பட்டுள்ளது: ஒரு நிர்வாகி இதைத் தேர்வுசெய்து இயக்கும் வரை, ஏற்கனவே உள்ள ஒவ்வொரு நிறுவலும் இந்தத் தரவை முன்பு போலவே வைத்திருக்கும். நிர்வாகியால் தூண்டப்படும் DELETE /api/v1/batches/delete-completed வழித்தடம் எந்த நிலையிலும் பாதிக்கப்படாது — அது ஒரு தனியான, நிபந்தனையற்ற பொது API ஒப்பந்தமாகும்.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "புதுப்பிப்பு கிடைக்கிறது: v{current} → v{latest}", "cliproxyapiVersion": "பதிப்பு" }, + "modelCatalog": { + "title": "மாடல்கள் & காம்போக்கள்", + "subtitle": "அனைத்து வழங்குநர்களிலும் உள்ள மாடல்கள் மற்றும் காம்போ ரூட்டிங் பைப்லைன்களை உலாவவும், அவற்றின் இயக்க நிலையைச் சோதிக்கவும்.", + "refresh": "புதுப்பி", + "modelsTab": "மாடல்கள்", + "combosTab": "காம்போக்கள்", + "catalogSections": "கேட்லாக் பிரிவுகள்", + "loading": "ஏற்றுகிறது...", + "retry": "மீண்டும் முயற்சி செய்", + "unableToLoad": "மாடல் கேட்லாக்கை ஏற்ற முடியவில்லை.", + "unableToLoadCombos": "காம்போக்களை ஏற்ற முடியவில்லை.", + "checkConnection": "இணைப்பைச் சரிபார்த்து மீண்டும் முயற்சிக்கவும்.", + "noModelsAvailable": "இன்னும் மாடல்கள் எதுவும் கிடைக்கவில்லை.", + "noModelsMatch": "இந்த வடிப்பான்களுக்குப் பொருந்தும் மாடல்கள் எதுவும் இல்லை.", + "noCombosAvailable": "இன்னும் காம்போக்கள் எதுவும் கிடைக்கவில்லை.", + "noCombosMatch": "இந்த வடிப்பான்களுக்குப் பொருந்தும் காம்போக்கள் எதுவும் இல்லை.", + "clearFilters": "வடிப்பான்களை அழி", + "searchModels": "மாடல்களைத் தேடு", + "searchModelsPlaceholder": "மாடல், வழங்குநர் அல்லது திறன் மூலம் தேடுங்கள்", + "searchCombos": "காம்போக்களைத் தேடு", + "searchCombosPlaceholder": "காம்போ பெயர், மாடல்கள் அல்லது விளக்கம் மூலம் தேடுங்கள்", + "modelCountSingle": "மாடல்", + "modelCountPlural": "மாடல்கள்", + "comboCountSingle": "காம்போ", + "comboCountPlural": "காம்போக்கள்", + "provider": "வழங்குநர்", + "allProviders": "அனைத்து வழங்குநர்கள்", + "type": "வகை", + "allTypes": "அனைத்து வகைகள்", + "subtype": "துணை வகை", + "allSubtypes": "அனைத்து துணை வகைகள்", + "capability": "திறன்", + "allCapabilities": "அனைத்து திறன்கள்", + "pricing": "விலை நிர்ணயம்", + "allPricing": "அனைத்து விலை நிர்ணயங்களும்", + "freeOnly": "இலவசம் மட்டும்", + "nonFree": "நிலையானது / கட்டணமுடையது", + "providerHealth": "வழங்குநரின் இயக்க நிலை", + "allHealthStates": "அனைத்து இயக்க நிலைகளும்", + "healthy": "சீரானது", + "degraded": "பாதிக்கப்பட்டது", + "down": "செயலிழந்துள்ளது", + "testResult": "சோதனை முடிவு", + "allResults": "அனைத்து முடிவுகள்", + "untested": "சோதிக்கப்படாதவை", + "statusOk": "சரி", + "statusSlow": "மெதுவானது", + "statusError": "பிழை", + "minContext": "குறைந்தபட்ச சூழல்", + "minContextPlaceholder": "எ.கா. 32000", + "strategy": "உத்தி", + "allStrategies": "அனைத்து உத்திகள்", + "status": "நிலை", + "allStatuses": "அனைத்து நிலைகள்", + "active": "செயலில் உள்ளது", + "paused": "இடைநிறுத்தப்பட்டது", + "minMembers": "குறைந்தபட்ச உறுப்பினர்கள்", + "minMembersPlaceholder": "எ.கா. 1", + "maxMembers": "அதிகபட்ச உறுப்பினர்கள்", + "maxMembersPlaceholder": "எ.கா. 10", + "testSelected": "தேர்ந்தெடுக்கப்பட்டதைச் சோதிக்கவும் ({count})", + "testAllFiltered": "வடிகட்டப்பட்ட அனைத்தையும் சோதிக்கவும் ({count})", + "cancel": "ரத்துசெய்", + "clearResults": "முடிவுகளை அழிக்கவும்", + "testing": "சோதிக்கப்படுகிறது...", + "rateLimited": "விகித வரம்பு விதிக்கப்பட்டது", + "quotaExceeded": "அளவு வரம்பு மீறப்பட்டது", + "timeout": "நேரம் முடிந்தது", + "otherError": "பிழை", + "justNow": "சற்றுமுன்", + "minutesAgo": "{count} நிமிடங்களுக்கு முன்", + "hoursAgo": "{count} மணிநேரத்திற்கு முன்", + "tableRegion": "மாடல் அட்டவணை பட்டியல்", + "combosTableRegion": "காம்போ அட்டவணை பட்டியல்", + "tableCaption": "அனைத்து வழங்குநர்களிலும் உள்ள மாடல் பட்டியல்", + "combosTableCaption": "நலப் பரிசோதனை முடிவுகளுடன் கூடிய காம்போ பட்டியல்", + "selectAllModels": "இப்பக்கத்திலுள்ள அனைத்து மாடல்களையும் தேர்ந்தெடுக்கவும்", + "selectAllCombos": "இப்பக்கத்திலுள்ள அனைத்து காம்போக்களையும் தேர்ந்தெடுக்கவும்", + "selectModel": "{name} மாடலைத் தேர்ந்தெடுக்கவும்", + "selectCombo": "{name} காம்போவைத் தேர்ந்தெடுக்கவும்", + "model": "மாடல்", + "capabilities": "திறன்கள்", + "context": "சூழல்", + "output": "அதிகபட்ச வெளியீடு", + "flags": "கொடிகள்", + "healthTest": "ஆரோக்கிய சோதனை", + "actions": "செயல்கள்", + "test": "சோதனை", + "custom": "தனிப்பயன்", + "free": "இலவசம்", + "noFlags": "விலை அல்லது மூலக் கொடி எதுவும் தெரிவிக்கப்படவில்லை", + "noCapabilities": "திறன் மேல்தரவு எதுவும் தெரிவிக்கப்படவில்லை", + "showingModels": "{total} மாடல்களில் {first}–{last} காட்டப்படுகிறது", + "showingCombos": "{total} சேர்க்கைகளில் {first}–{last} காட்டப்படுகிறது", + "refreshing": "புதுப்பிக்கிறது…", + "refreshFailed": "புதுப்பித்தல் தோல்வியடைந்தது. கடைசியாக ஏற்றப்பட்ட பட்டியல் காட்டப்படுகிறது.", + "page": "{pageCount}-இல் பக்கம் {page}", + "previous": "முந்தையது", + "next": "அடுத்தது", + "combo": "சேர்க்கை", + "members": "உறுப்பினர்கள்", + "moreMembers": "+{count} மேலும்" + }, "combos": { "title": "காம்போக்கள்", "description": "எடையிட்ட வழிப்படுத்தல் மற்றும் மாற்று ஆதரவுடன் மாதிரி காம்போக்களை உருவாக்கவும்", diff --git a/src/i18n/messages/te.json b/src/i18n/messages/te.json index ce94760b8688..dd35786ec800 100644 --- a/src/i18n/messages/te.json +++ b/src/i18n/messages/te.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "ప్రొవైడర్ డిస్పాచ్ కోసం ప్రతి-టెనెంట్ అడాప్టివ్ వర్చువల్ అడ్మిషన్ లేన్లను ప్రారంభించండి (#9654): ఒక టెనెంట్ బర్స్ట్ ఇకపై మరొక టెనెంట్కు 503 ఇవ్వదు. OMNIROUTE_CHAT_VIRTUAL_LANES ఎన్విరాన్మెంట్ వేరియబుల్ ఈ డాష్బోర్డ్ సెట్టింగ్ కంటే ప్రాధాన్యత పొందుతుంది; మార్పులు సర్వర్ పునఃప్రారంభంలో ప్రభావం చూపుతాయి.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "డ్యాష్బోర్డ్ ప్రొవైడర్ పేజీలు: ప్రొవైడర్ గుర్తించే సంకేతాలపైనే ఉచిత బ్యాడ్జ్ను చూపించండి — డాక్యుమెంట్ చేయబడిన ఉచిత టైర్ లేని నమోదిత ప్రొవైడర్లలో డిస్ప్లే-పేరు హ్యూరిస్టిక్, బూలియన్ కాని ఉచిత ఫీల్డ్లు మరియు :free ప్రత్యయాలను విస్మరిస్తుంది. ఆఫ్ చేస్తే మునుపటి బ్యాడ్జ్ నియమాన్ని కొనసాగిస్తుంది.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy పూల్లు మరియు opencode యొక్క ఒక్కో ఖాతా రొటేషన్లో, అప్పుడే విఫలమైన Proxyని (TCP ప్రోబ్ తిరస్కరించబడటం లేదా దాని ద్వారా 429 అందుకోవడం) ప్రతి పునరావృతంతో రెట్టింపయ్యే, గరిష్ఠ పరిమితి వరకు ఉండే ఒక్కో ప్రాసెస్ వ్యవధిలో మళ్లీ అందించకుండా ఆపుతుంది. Proxy స్థితి ఏదీ వ్రాయబడదు; ప్రతి అభ్యర్థినీ పక్కన పెడితే ఎంపికలో మార్పు ఉండదు. డిఫాల్ట్‌గా ఆన్‌లో ఉంటుంది; `false` సాధారణ ఎంపికను పునరుద్ధరిస్తుంది.", - "featureFlagProxyPoolSharedEgressOrderDescription": "ఎగ్రెస్ అడ్రస్ ఆధారంగా కోటా కేటాయించబడే ప్రొవైడర్ల కోసం, ఇటీవల తిరస్కరించబడిన మెంబర్ యొక్క గుర్తించిన ఎగ్రెస్ అడ్రస్‌ను షేర్ చేసుకునే పూల్ మెంబర్‌ను హెల్తీ మెంబర్ల కంటే సరిగ్గా దిగువన ర్యాంక్ చేయండి. ఆర్డర్ మాత్రమే, ఎప్పటికీ మినహాయించబడదు. దీనికి PROXY_SKIP_RECENTLY_FAILED అవసరం, ఇది చదివే తిరస్కరణ సిగ్నల్‌ను ఉత్పత్తి చేస్తుంది. డిఫాల్ట్‌గా ఆఫ్ చేయబడి ఉంటుంది: ఎంపిక క్రమం ఖచ్చితంగా సాధారణ రొటేషన్ లాగే ఉంటుంది.", "featureFlagProxyPoolEgressObservationDescription": "డ్యాష్బోర్డ్లోని Proxy పూల్ కింద, గత 24 గంటల్లో దాని సభ్యులకు సేవలందించిన గమనించిన ఎగ్రెస్ IPల సంఖ్య, వాటిని ఉపయోగించిన కనెక్షన్ల సంఖ్య మరియు ఒకే IP వెనుక అత్యధికంగా కనిపించిన సంఖ్యను చూపండి. ఇది చదవడానికి మాత్రమే, Proxy లాగ్ నుండి గణించబడుతుంది, రూటింగ్ కోసం ఎప్పుడూ ఉపయోగించబడదు. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: పూల్ ఎడిటర్ మారదు మరియు పరిశీలన రూట్ null అని సమాధానమిస్తుంది.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy ఆరోగ్య స్వీప్లో, లక్ష్యం తిరస్కరించిన ప్రోబ్ (401/403/429: Proxy ప్రసారం చేసింది, గమ్యస్థానం ఈ ఎగ్రెస్ IPని తిరస్కరించింది) విజయవంతంగా సేవలందించిన ప్రోబ్లాగే Proxy యొక్క వరుస వైఫల్యాల పరంపరను రీసెట్ చేయనివ్వండి. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: తిరస్కరణ తటస్థంగానే ఉండి పరంపరను అలాగే ఉంచుతుంది. ఏ విధంగానైనా 5xx అనిశ్చితంగానే ఉంటుంది, అలాగే తిరస్కరణ ఎప్పుడూ Proxyని తొలగించదు, నిలిపివేయదు లేదా మళ్లీ సక్రియం చేయదు.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "OMNIROUTE_BATCH_RETENTION_DAYS కంటే పాతవైన టెర్మినల్ (పూర్తయిన/విఫలమైన/రద్దయిన/గడువు ముగిసిన) Batch API జాబ్లను, వాటి ప్రతి-లైన్ చెక్పాయింట్లతో సహా ఆటోమేటిక్ క్లీనప్ స్వీప్ తొలగించేలా చేయండి; అలాగే వాటి స్వంత expires_at దాటిన అప్లోడ్ చేసిన ఫైల్ల BLOB కంటెంట్ను క్లియర్ చేయండి. డిఫాల్ట్గా ఆఫ్లో ఉంటుంది: ఆపరేటర్ దీన్ని ఎంచుకునే వరకు ప్రతి ప్రస్తుత ఇన్స్టాలేషన్ ఈ డేటాను మునుపటిలాగే ఉంచుతుంది. ఆపరేటర్ ప్రారంభించే DELETE /api/v1/batches/delete-completed రూట్పై ఏ విధంగానూ ప్రభావం ఉండదు — అది ప్రత్యేకమైన, షరతులు లేని పబ్లిక్ API ఒప్పందం.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "అప్‌డేట్ అందుబాటులో ఉంది: v{current} → v{latest}", "cliproxyapiVersion": "సంవత్సరం" }, + "modelCatalog": { + "title": "మోడల్స్ & కాంబోలు", + "subtitle": "ప్రతి ప్రొవైడర్‌లోని మోడల్స్ మరియు కాంబో రూటింగ్ పైప్‌లైన్‌లను బ్రౌజ్ చేయండి మరియు వాటి హెల్త్-టెస్ట్ చేయండి.", + "refresh": "రిఫ్రెష్ చేయండి", + "modelsTab": "మోడల్స్", + "combosTab": "కాంబోలు", + "catalogSections": "కేటలాగ్ విభాగాలు", + "loading": "లోడ్ అవుతోంది...", + "retry": "మళ్లీ ప్రయత్నించండి", + "unableToLoad": "మోడల్ కేటలాగ్‌ను లోడ్ చేయడం సాధ్యపడలేదు.", + "unableToLoadCombos": "కాంబోలను లోడ్ చేయడం సాధ్యపడలేదు.", + "checkConnection": "కనెక్షన్‌ని తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి.", + "noModelsAvailable": "ఇంకా మోడల్‌లు ఏవీ అందుబాటులో లేవు.", + "noModelsMatch": "ఈ ఫిల్టర్‌లకు ఏ మోడల్‌లు సరిపోలడం లేదు.", + "noCombosAvailable": "ఇంకా కాంబోలు ఏవీ అందుబాటులో లేవు.", + "noCombosMatch": "ఈ ఫిల్టర్‌లకు ఏ కాంబోలు సరిపోలడం లేదు.", + "clearFilters": "ఫిల్టర్‌లను క్లియర్ చేయండి", + "searchModels": "మోడల్స్‌ను శోధించండి", + "searchModelsPlaceholder": "మోడల్, ప్రొవైడర్ లేదా సామర్థ్యం ద్వారా శోధించండి", + "searchCombos": "కాంబోలను శోధించండి", + "searchCombosPlaceholder": "కాంబో పేరు, మోడల్స్ లేదా వివరణ ద్వారా శోధించండి", + "modelCountSingle": "మోడల్", + "modelCountPlural": "మోడల్స్", + "comboCountSingle": "కాంబో", + "comboCountPlural": "కాంబోలు", + "provider": "ప్రొవైడర్", + "allProviders": "అన్ని ప్రొవైడర్‌లు", + "type": "రకం", + "allTypes": "అన్ని రకాలు", + "subtype": "ఉప రకం", + "allSubtypes": "అన్ని ఉప రకాలు", + "capability": "సామర్థ్యం", + "allCapabilities": "అన్ని సామర్థ్యాలు", + "pricing": "ధర", + "allPricing": "అన్ని ధరలు", + "freeOnly": "ఉచితమైనవి మాత్రమే", + "nonFree": "స్టాండర్డ్ / నాన్-ఫ్రీ", + "providerHealth": "ప్రొవైడర్ హెల్త్", + "allHealthStates": "అన్ని హెల్త్ స్థితులు", + "healthy": "హెల్తీ", + "degraded": "క్షీణించింది", + "down": "డౌన్", + "testResult": "పరీక్ష ఫలితం", + "allResults": "అన్ని ఫలితాలు", + "untested": "పరీక్షించబడలేదు", + "statusOk": "సరే", + "statusSlow": "నెమ్మదిగా ఉంది", + "statusError": "లోపం", + "minContext": "కనిష్ట కాంటెక్స్ట్", + "minContextPlaceholder": "ఉదా. 32000", + "strategy": "వ్యూహం", + "allStrategies": "అన్ని వ్యూహాలు", + "status": "స్థితి", + "allStatuses": "అన్ని స్థితులు", + "active": "క్రియాశీలం", + "paused": "పాజ్ చేయబడింది", + "minMembers": "కనిష్ట సభ్యులు", + "minMembersPlaceholder": "ఉదా. 1", + "maxMembers": "గరిష్ట సభ్యులు", + "maxMembersPlaceholder": "ఉదా. 10", + "testSelected": "ఎంచుకున్న వాటిని పరీక్షించండి ({count})", + "testAllFiltered": "ఫిల్టర్ చేసిన అన్నింటినీ పరీక్షించండి ({count})", + "cancel": "రద్దు చేయి", + "clearResults": "ఫలితాలను క్లియర్ చేయి", + "testing": "పరీక్షిస్తోంది...", + "rateLimited": "రేట్ పరిమితి దాటింది", + "quotaExceeded": "కోటా మించిపోయింది", + "timeout": "సమయం ముగిసింది", + "otherError": "లోపం", + "justNow": "ఇప్పుడే", + "minutesAgo": "{count}ని. క్రితం", + "hoursAgo": "{count}గం. క్రితం", + "tableRegion": "మోడల్ కేటలాగ్ పట్టిక", + "combosTableRegion": "కాంబోల కేటలాగ్ పట్టిక", + "tableCaption": "అన్ని ప్రొవైడర్లలోని మోడల్ కేటలాగ్", + "combosTableCaption": "హెల్త్ టెస్ట్ ఫలితాలతో కూడిన కాంబోల కేటలాగ్", + "selectAllModels": "ఈ పేజీలోని అన్ని మోడళ్లను ఎంచుకోండి", + "selectAllCombos": "ఈ పేజీలోని అన్ని కాంబోలను ఎంచుకోండి", + "selectModel": "మోడల్ {name}ని ఎంచుకోండి", + "selectCombo": "కాంబో {name}ని ఎంచుకోండి", + "model": "మోడల్", + "capabilities": "సామర్థ్యాలు", + "context": "సందర్భం", + "output": "గరిష్ట అవుట్‌పుట్", + "flags": "ఫ్లాగ్‌లు", + "healthTest": "హెల్త్ టెస్ట్", + "actions": "చర్యలు", + "test": "పరీక్ష", + "custom": "అనుకూలీకరించిన", + "free": "ఉచితం", + "noFlags": "ధర లేదా సోర్స్ ఫ్లాగ్ ఏదీ నివేదించబడలేదు", + "noCapabilities": "సామర్థ్య మెటాడేటా ఏదీ నివేదించబడలేదు", + "showingModels": "{total} మోడళ్లలో {first}–{last} చూపిస్తోంది", + "showingCombos": "{total} కాంబోలలో {first}–{last} చూపిస్తోంది", + "refreshing": "రిఫ్రెష్ చేస్తోంది…", + "refreshFailed": "రిఫ్రెష్ విఫలమైంది. చివరిగా లోడ్ చేసిన కేటలాగ్‌ను చూపుతోంది.", + "page": "{pageCount} లో పేజీ {page}", + "previous": "మునుపటి", + "next": "తదుపరి", + "combo": "కాంబో", + "members": "సభ్యులు", + "moreMembers": "+{count} మరిన్ని" + }, "combos": { "title": "కాంబోలు", "description": "వెయిటెడ్ రూటింగ్ మరియు ఫాల్బ్యాక్ మద్దతుతో మోడల్ కాంబోలను సృష్టించండి", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index 05f2cc3095dc..e3f193c45727 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "เปิดใช้เลนรับเข้าเสมือนแบบปรับตัวต่อเทนแนนต์สำหรับการส่งไปยังผู้ให้บริการ (#9654): การพุ่งสูงของเทนแนนต์หนึ่งจะไม่ทำให้อีกเทนแนนต์ได้รับ 503 อีกต่อไป ตัวแปรสภาพแวดล้อม OMNIROUTE_CHAT_VIRTUAL_LANES มีผลเหนือการตั้งค่าแดชบอร์ดนี้ การเปลี่ยนแปลงมีผลเมื่อรีสตาร์ทเซิร์ฟเวอร์", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "หน้าผู้ให้บริการในแดชบอร์ด: แสดงป้าย ฟรี เฉพาะสัญญาณที่ผู้ให้บริการรองรับเท่านั้น — เลิกใช้การอนุมานจากชื่อที่แสดง ฟิลด์ฟรีที่ไม่ใช่ค่าบูลีน และคำต่อท้าย :free สำหรับผู้ให้บริการที่ลงทะเบียนแต่ไม่มีระดับใช้งานฟรีที่ระบุไว้ในเอกสาร เมื่อปิด จะยังคงใช้กฎการแสดงป้ายแบบเดิม", "featureFlagProxySkipRecentlyFailedDescription": "พูลพร็อกซีและการหมุนเวียนต่อบัญชีของ opencode จะหยุดนำพร็อกซีที่เพิ่งล้มเหลว (ปฏิเสธการตรวจสอบ TCP หรือได้รับ 429 ผ่านพร็อกซีนั้น) กลับมาให้บริการซ้ำเป็นระยะเวลาต่อโปรเซส ซึ่งจะเพิ่มเป็นสองเท่าทุกครั้งที่เกิดซ้ำจนถึงขีดจำกัด โดยจะไม่มีการบันทึกสถานะพร็อกซี และหากตัวเลือกทั้งหมดถูกพักไว้ การเลือกจะไม่เปลี่ยนแปลง เปิดไว้โดยค่าเริ่มต้น โดย `false` จะคืนค่าการเลือกแบบปกติ", - "featureFlagProxyPoolSharedEgressOrderDescription": "สำหรับผู้ให้บริการที่มีการจัดสรรโควตาตาม egress address ระบบจะจัดลำดับสมาชิกในพูลที่ใช้ egress address เดียวกับสมาชิกที่เพิ่งถูกปฏิเสธให้อยู่ต่ำกว่าสมาชิกที่ทำงานปกติ เป็นเพียงการจัดลำดับเท่านั้น ไม่มีการคัดออก จำเป็นต้องมี PROXY_SKIP_RECENTLY_FAILED ซึ่งสร้างสัญญาณการปฏิเสธที่ระบบจะอ่าน ปิดใช้งานโดยค่าเริ่มต้น: ลำดับการเลือกจะเป็นไปตามการหมุนเวียนปกติอย่างแท้จริง", "featureFlagProxyPoolEgressObservationDescription": "แสดงใต้พูลพร็อกซีในแดชบอร์ดว่ามี IP ขาออกที่ตรวจพบกี่รายการซึ่งให้บริการสมาชิกของพูลในช่วง 24 h ที่ผ่านมา มีการเชื่อมต่อผ่าน IP เหล่านั้นกี่ครั้ง และจำนวนการเชื่อมต่อสูงสุดที่พบภายใต้ IP เดียว ข้อมูลนี้เป็นแบบอ่านอย่างเดียว คำนวณจากบันทึกพร็อกซี และไม่เคยนำไปใช้กำหนดเส้นทาง ปิดไว้โดยค่าเริ่มต้น: ตัวแก้ไขพูลจะไม่เปลี่ยนแปลง และเส้นทางการสังเกตการณ์จะตอบกลับเป็น null", "featureFlagProxyHealthBlockedResetsStreakDescription": "ในการกวาดตรวจสุขภาพพร็อกซี ให้การตรวจสอบที่ถูกเป้าหมายปฏิเสธ (401/403/429: พร็อกซีส่งต่อสำเร็จ แต่ปลายทางปฏิเสธ IP ขาออกนี้) รีเซ็ตจำนวนความล้มเหลวต่อเนื่องของพร็อกซีได้เช่นเดียวกับการตรวจสอบที่ให้บริการสำเร็จ ปิดไว้โดยค่าเริ่มต้น: การปฏิเสธจะยังคงเป็นกลางและคงจำนวนความล้มเหลวต่อเนื่องไว้ 5xx ยังคงถือว่าไม่สามารถสรุปผลได้ในทั้งสองกรณี และการปฏิเสธจะไม่ลบ ปิดใช้งาน หรือเปิดใช้งานพร็อกซีอีกครั้ง", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "อนุญาตให้การล้างข้อมูลอัตโนมัติลบงาน Batch API ที่อยู่ในสถานะสิ้นสุดแล้ว (เสร็จสิ้น/ล้มเหลว/ยกเลิก/หมดอายุ) ซึ่งเก่ากว่า OMNIROUTE_BATCH_RETENTION_DAYS พร้อมจุดตรวจสอบรายบรรทัดของงานเหล่านั้น และล้างเนื้อหา BLOB ของไฟล์ที่อัปโหลดซึ่งเลย expires_at ของไฟล์นั้นแล้ว ค่าเริ่มต้นคือปิด: การติดตั้งที่มีอยู่ทุกแห่งจะยังคงเก็บข้อมูลนี้ไว้เหมือนเดิมทุกประการจนกว่าผู้ดูแลระบบจะเลือกเปิดใช้ ไม่ว่าจะตั้งค่าอย่างไร เส้นทาง DELETE /api/v1/batches/delete-completed ที่ผู้ดูแลระบบเรียกใช้จะไม่ได้รับผลกระทบ เนื่องจากเป็นสัญญา API สาธารณะที่แยกต่างหากและทำงานโดยไม่มีเงื่อนไข", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "มีการอัปเดต: v{current} → v{latest}", "cliproxyapiVersion": "เวอร์ชัน" }, + "modelCatalog": { + "title": "โมเดลและคอมโบ", + "subtitle": "เรียกดูและทดสอบสถานะการทำงานของโมเดลและไปป์ไลน์การกำหนดเส้นทางคอมโบของผู้ให้บริการทั้งหมด", + "refresh": "รีเฟรช", + "modelsTab": "โมเดล", + "combosTab": "คอมโบ", + "catalogSections": "หมวดหมู่แคตตาล็อก", + "loading": "กำลังโหลด...", + "retry": "ลองใหม่อีกครั้ง", + "unableToLoad": "ไม่สามารถโหลดแคตตาล็อกโมเดลได้", + "unableToLoadCombos": "ไม่สามารถโหลดคอมโบได้", + "checkConnection": "ตรวจสอบการเชื่อมต่อและลองใหม่อีกครั้ง", + "noModelsAvailable": "ยังไม่มีโมเดลที่พร้อมใช้งาน", + "noModelsMatch": "ไม่มีโมเดลที่ตรงกับตัวกรองเหล่านี้", + "noCombosAvailable": "ยังไม่มีคอมโบที่พร้อมใช้งาน", + "noCombosMatch": "ไม่มีคอมโบที่ตรงกับตัวกรองเหล่านี้", + "clearFilters": "ล้างตัวกรอง", + "searchModels": "ค้นหาโมเดล", + "searchModelsPlaceholder": "ค้นหาตามโมเดล ผู้ให้บริการ หรือความสามารถ", + "searchCombos": "ค้นหาคอมโบ", + "searchCombosPlaceholder": "ค้นหาตามชื่อคอมโบ โมเดล หรือคำอธิบาย", + "modelCountSingle": "โมเดล", + "modelCountPlural": "โมเดล", + "comboCountSingle": "คอมโบ", + "comboCountPlural": "คอมโบ", + "provider": "ผู้ให้บริการ", + "allProviders": "ผู้ให้บริการทั้งหมด", + "type": "ประเภท", + "allTypes": "ทุกประเภท", + "subtype": "ประเภทย่อย", + "allSubtypes": "ทุกประเภทย่อย", + "capability": "ความสามารถ", + "allCapabilities": "ความสามารถทั้งหมด", + "pricing": "ราคา", + "allPricing": "ราคาทั้งหมด", + "freeOnly": "ฟรีเท่านั้น", + "nonFree": "มาตรฐาน / ไม่ฟรี", + "providerHealth": "สถานะผู้ให้บริการ", + "allHealthStates": "ทุกสถานะการทำงาน", + "healthy": "ปกติ", + "degraded": "ประสิทธิภาพลดลง", + "down": "ไม่พร้อมใช้งาน", + "testResult": "ผลการทดสอบ", + "allResults": "ผลลัพธ์ทั้งหมด", + "untested": "ยังไม่ได้ทดสอบ", + "statusOk": "ปกติ", + "statusSlow": "ช้า", + "statusError": "ข้อผิดพลาด", + "minContext": "บริบทขั้นต่ำ", + "minContextPlaceholder": "เช่น 32000", + "strategy": "กลยุทธ์", + "allStrategies": "กลยุทธ์ทั้งหมด", + "status": "สถานะ", + "allStatuses": "สถานะทั้งหมด", + "active": "ใช้งานอยู่", + "paused": "หยุดชั่วคราว", + "minMembers": "สมาชิกขั้นต่ำ", + "minMembersPlaceholder": "เช่น 1", + "maxMembers": "สมาชิกสูงสุด", + "maxMembersPlaceholder": "เช่น 10", + "testSelected": "ทดสอบรายการที่เลือก ({count})", + "testAllFiltered": "ทดสอบรายการที่กรองทั้งหมด ({count})", + "cancel": "ยกเลิก", + "clearResults": "ล้างผลลัพธ์", + "testing": "กำลังทดสอบ...", + "rateLimited": "ถูกจำกัดอัตราการเรียกใช้", + "quotaExceeded": "เกินโควตา", + "timeout": "หมดเวลา", + "otherError": "ข้อผิดพลาด", + "justNow": "เมื่อสักครู่", + "minutesAgo": "{count} นาทีที่แล้ว", + "hoursAgo": "{count} ชั่วโมงที่แล้ว", + "tableRegion": "ตารางแคตตาล็อกโมเดล", + "combosTableRegion": "ตารางแคตตาล็อกคอมโบ", + "tableCaption": "แคตตาล็อกโมเดลจากผู้ให้บริการทั้งหมด", + "combosTableCaption": "แคตตาล็อกคอมโบพร้อมผลการทดสอบสถานะการทำงาน", + "selectAllModels": "เลือกโมเดลทั้งหมดในหน้านี้", + "selectAllCombos": "เลือกคอมโบทั้งหมดในหน้านี้", + "selectModel": "เลือกโมเดล {name}", + "selectCombo": "เลือกคอมโบ {name}", + "model": "โมเดล", + "capabilities": "ความสามารถ", + "context": "บริบท", + "output": "เอาต์พุตสูงสุด", + "flags": "แฟล็ก", + "healthTest": "การทดสอบความพร้อมใช้งาน", + "actions": "การดำเนินการ", + "test": "ทดสอบ", + "custom": "กำหนดเอง", + "free": "ฟรี", + "noFlags": "ไม่มีการรายงานราคาหรือแฟล็กแหล่งที่มา", + "noCapabilities": "ไม่มีการรายงานข้อมูลเมทาดาทาความสามารถ", + "showingModels": "แสดง {first}–{last} จากทั้งหมด {total} โมเดล", + "showingCombos": "แสดง {first}–{last} จากทั้งหมด {total} คอมโบ", + "refreshing": "กำลังรีเฟรช…", + "refreshFailed": "รีเฟรชไม่สำเร็จ กำลังแสดงแคตตาล็อกที่โหลดล่าสุด", + "page": "หน้า {page} จาก {pageCount}", + "previous": "ก่อนหน้า", + "next": "ถัดไป", + "combo": "คอมโบ", + "members": "สมาชิก", + "moreMembers": "+{count} เพิ่มเติม" + }, "combos": { "title": "คอมโบ", "description": "สร้างโมเดลคอมโบด้วยการกำหนดเส้นทางแบบถ่วงน้ำหนักและการสนับสนุนทางเลือก", diff --git a/src/i18n/messages/tr.json b/src/i18n/messages/tr.json index ec3277753df4..62b2405e6d0c 100644 --- a/src/i18n/messages/tr.json +++ b/src/i18n/messages/tr.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Sağlayıcı gönderimi için kiracı başına uyarlanabilir sanal kabul şeritlerini etkinleştirin (#9654): bir kiracının ani yükü artık diğerinde 503 hatasına neden olmaz. OMNIROUTE_CHAT_VIRTUAL_LANES ortam değişkeni bu panel ayarına göre önceliklidir; değişiklikler sunucu yeniden başlatıldığında geçerli olur.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Kontrol paneli sağlayıcı sayfaları: Ücretsiz rozetini yalnızca sağlayıcının dikkate aldığı sinyallere göre gösterir — belgelenmiş bir ücretsiz katmanı olmayan kayıtlı sağlayıcılarda görünen ad sezgisini, Boole türünde olmayan ücretsiz alanlarını ve :free son eklerini kullanmaz. Kapalı olduğunda geçmiş rozet kuralını korur.", "featureFlagProxySkipRecentlyFailedDescription": "Proxy havuzları ve opencode'un hesap başına rotasyonu, henüz başarısız olmuş bir proxy'nin (reddedilen TCP yoklaması veya proxy üzerinden alınan 429 yanıtı) süreç başına belirlenen ve her tekrarda üst sınıra kadar iki katına çıkan bir süre boyunca yeniden kullanılmasını engeller. Proxy durumuna hiçbir şey yazılmaz; tüm adaylar kenara ayrıldığında seçim değişmeden kalır. Varsayılan olarak açıktır; `false` normal seçimi geri getirir.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Kotası çıkış adresine göre gruplandırılan sağlayıcılar için, yakın zamanda reddedilen bir üyenin gözlemlenen çıkış adresini paylaşan havuz üyesini sağlıklı üyelerin hemen altına yerleştirin. Yalnızca sıralamadır, asla hariç tutulmaz. Okuduğu ret sinyalini üreten PROXY_SKIP_RECENTLY_FAILED gerektirir. Varsayılan olarak kapalıdır: seçim sırası tamamen standart rotasyondur.", "featureFlagProxyPoolEgressObservationDescription": "Kontrol panelinde bir proxy havuzunun altında, son 24 saatte üyelerine kaç farklı gözlemlenen çıkış IP'sinin hizmet verdiğini, bunları kaç bağlantının kullandığını ve tek bir IP'nin arkasında en fazla kaç bağlantı görüldüğünü gösterir. Salt okunurdur, proxy günlüğünden hesaplanır ve yönlendirme için asla kullanılmaz. Varsayılan olarak kapalıdır: havuz düzenleyicisi değişmeden kalır ve gözlem rotası null yanıtını verir.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proxy sağlık taramasında, hedefin reddettiği bir yoklamanın (401/403/429: proxy isteği iletti, hedef bu çıkış IP'sini reddetti) proxy'nin ardışık başarısızlık serisini, başarıyla iletilen bir yoklamada olduğu gibi sıfırlamasını sağlar. Varsayılan olarak kapalıdır: bir ret nötr kalır ve seriyi korur. 5xx her iki durumda da sonuçsuz kalır ve bir ret hiçbir zaman proxy'yi kaldırmaz, devre dışı bırakmaz veya yeniden etkinleştirmez.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Otomatik temizleme işleminin, OMNIROUTE_BATCH_RETENTION_DAYS değerinden daha eski olan ve son duruma ulaşmış (tamamlanmış/başarısız/iptal edilmiş/süresi dolmuş) Batch API işlerini satır bazındaki kontrol noktalarıyla birlikte silmesine ve kendi expires_at sürelerini aşmış yüklenen dosyaların BLOB içeriğini temizlemesine izin verin. Varsayılan olarak kapalıdır: operatör etkinleştirene kadar mevcut tüm kurulumlar bu verileri aynen eskisi gibi saklar. Operatör tarafından tetiklenen DELETE /api/v1/batches/delete-completed rotası her iki durumda da etkilenmez; bu, ayrı ve koşulsuz bir genel API sözleşmesidir.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Güncelleme mevcut: v{current} → v{latest}", "cliproxyapiVersion": "Sürüm" }, + "modelCatalog": { + "title": "Modeller ve Kombolar", + "subtitle": "Tüm sağlayıcılardaki modelleri ve kombo yönlendirme hatlarını inceleyin ve sağlık durumlarını test edin.", + "refresh": "Yenile", + "modelsTab": "Modeller", + "combosTab": "Kombolar", + "catalogSections": "Katalog Bölümleri", + "loading": "Yükleniyor...", + "retry": "Yeniden Dene", + "unableToLoad": "Model kataloğu yüklenemedi.", + "unableToLoadCombos": "Kombolar yüklenemedi.", + "checkConnection": "Bağlantıyı kontrol edin ve tekrar deneyin.", + "noModelsAvailable": "Henüz kullanılabilir model yok.", + "noModelsMatch": "Bu filtrelere uyan model yok.", + "noCombosAvailable": "Henüz kullanılabilir kombo yok.", + "noCombosMatch": "Bu filtrelere uyan kombo yok.", + "clearFilters": "Filtreleri temizle", + "searchModels": "Modellerde ara", + "searchModelsPlaceholder": "Modele, sağlayıcıya veya yeteneğe göre ara", + "searchCombos": "Kombolarda ara", + "searchCombosPlaceholder": "Kombo adına, modellere veya açıklamaya göre ara", + "modelCountSingle": "model", + "modelCountPlural": "modeller", + "comboCountSingle": "kombo", + "comboCountPlural": "kombolar", + "provider": "Sağlayıcı", + "allProviders": "Tüm sağlayıcılar", + "type": "Tür", + "allTypes": "Tüm türler", + "subtype": "Alt tür", + "allSubtypes": "Tüm alt türler", + "capability": "Yetenek", + "allCapabilities": "Tüm yetenekler", + "pricing": "Fiyatlandırma", + "allPricing": "Tüm fiyatlandırmalar", + "freeOnly": "Yalnızca ücretsiz", + "nonFree": "Standart / Ücretli", + "providerHealth": "Sağlayıcı sağlık durumu", + "allHealthStates": "Tüm sağlık durumları", + "healthy": "Sağlıklı", + "degraded": "Performansı Düşük", + "down": "Çalışmıyor", + "testResult": "Test sonucu", + "allResults": "Tüm sonuçlar", + "untested": "Test edilmedi", + "statusOk": "Sorunsuz", + "statusSlow": "Yavaş", + "statusError": "Hata", + "minContext": "Min. bağlam", + "minContextPlaceholder": "ör. 32000", + "strategy": "Strateji", + "allStrategies": "Tüm stratejiler", + "status": "Durum", + "allStatuses": "Tüm durumlar", + "active": "Aktif", + "paused": "Duraklatıldı", + "minMembers": "Min. üye", + "minMembersPlaceholder": "ör. 1", + "maxMembers": "Maks. üye", + "maxMembersPlaceholder": "ör. 10", + "testSelected": "Seçilenleri test et ({count})", + "testAllFiltered": "Filtrelenenlerin tümünü test et ({count})", + "cancel": "İptal", + "clearResults": "Sonuçları temizle", + "testing": "Test ediliyor...", + "rateLimited": "İstek sınırı aşıldı", + "quotaExceeded": "Kota aşıldı", + "timeout": "Zaman aşımına uğradı", + "otherError": "Hata", + "justNow": "Az önce", + "minutesAgo": "{count} dk önce", + "hoursAgo": "{count} sa önce", + "tableRegion": "Model kataloğu tablosu", + "combosTableRegion": "Kombinasyon kataloğu tablosu", + "tableCaption": "Tüm sağlayıcılardaki model kataloğu", + "combosTableCaption": "Sağlık testi sonuçlarıyla kombinasyon kataloğu", + "selectAllModels": "Bu sayfadaki tüm modelleri seç", + "selectAllCombos": "Bu sayfadaki tüm kombinasyonları seç", + "selectModel": "{name} modelini seç", + "selectCombo": "{name} kombinasyonunu seç", + "model": "Model", + "capabilities": "Yetenekler", + "context": "Bağlam", + "output": "Maksimum çıktı", + "flags": "Bayraklar", + "healthTest": "Sağlık Testi", + "actions": "Eylemler", + "test": "Test", + "custom": "Özel", + "free": "Ücretsiz", + "noFlags": "Fiyat veya kaynak bayrağı bildirilmedi", + "noCapabilities": "Yetenek meta verisi bildirilmedi", + "showingModels": "{total} modelden {first}–{last} gösteriliyor", + "showingCombos": "{total} kombodan {first}–{last} gösteriliyor", + "refreshing": "Yenileniyor…", + "refreshFailed": "Yenileme başarısız oldu. Son yüklenen katalog gösteriliyor.", + "page": "Sayfa {page} / {pageCount}", + "previous": "Önceki", + "next": "Sonraki", + "combo": "Kombo", + "members": "Üyeler", + "moreMembers": "+{count} daha" + }, "combos": { "title": "Kombolar", "description": "Ağırlıklı yönlendirme ve yedek model desteğiyle model komboları oluşturun", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index a24c7a0a0918..ad5ee558db0a 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Увімкніть адаптивні віртуальні смуги допуску для кожного тенанта під час надсилання провайдерам (#9654): сплеск навантаження одного тенанта більше не викликає 503 в іншого. Змінна середовища OMNIROUTE_CHAT_VIRTUAL_LANES має пріоритет над цим налаштуванням у панелі; зміни набувають чинності після перезапуску сервера.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Сторінки провайдерів на панелі керування: показувати позначку «Безкоштовно» лише на підставі ознак, які підтримує провайдер. Це скасовує евристику на основі відображуваного імені, небулеві поля безкоштовності та суфікси :free для зареєстрованих провайдерів без документально підтвердженого безкоштовного рівня. Якщо вимкнено, використовується попереднє правило відображення позначки.", "featureFlagProxySkipRecentlyFailedDescription": "Пули проксі та ротація opencode для кожного облікового запису тимчасово припиняють повторно використовувати проксі, який щойно дав збій (відхилена перевірка TCP або отримана через нього відповідь 429), на період у межах процесу, що подвоюється після кожного повторного збою, аж до встановленої межі. Статус проксі не записується; якщо всі кандидати відкладені, вибір залишається незмінним. За замовчуванням увімкнено; `false` відновлює звичайний вибір.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Для провайдерів, чия квота групується за вихідною адресою, ранжувати учасника пулу зі спільною зафіксованою вихідною адресою нещодавно відхиленого учасника одразу під справними учасниками. Лише зміна порядку, без виключення. Потрібен PROXY_SKIP_RECENTLY_FAILED, який генерує сигнал відмови, що ним зчитується. За замовчуванням вимкнено: порядок вибору точно відповідає звичайній ротації.", "featureFlagProxyPoolEgressObservationDescription": "Показувати на інформаційній панелі під пулом проксі, скільки спостережуваних вихідних IP-адрес обслуговували його учасників протягом останніх 24 год, скільки з’єднань їх використовували та найбільшу кількість з’єднань через одну IP-адресу. Лише для читання, обчислюється з журналу проксі та ніколи не використовується для маршрутизації. За замовчуванням вимкнено: редактор пулу залишається без змін, а маршрут спостереження повертає null.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Під час перевірки працездатності проксі дозволити перевірці, яку відхилила ціль (401/403/429: проксі передав запит, а місце призначення відхилило цю вихідну IP-адресу), скидати лічильник послідовних збоїв проксі, як у разі успішно обслугованої перевірки. За замовчуванням вимкнено: відмова залишається нейтральною та не скидає лічильник. Відповідь 5xx в обох випадках залишається невизначеною, а відмова ніколи не призводить до видалення, вимкнення чи повторної активації проксі.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Дозволити автоматичному очищенню видаляти завдання Batch API у кінцевому стані (завершені/невдалі/скасовані/прострочені), старші за OMNIROUTE_BATCH_RETENTION_DAYS, разом із їхніми контрольними точками для кожного рядка, а також очищати вміст BLOB завантажених файлів після настання їхнього власного expires_at. За замовчуванням вимкнено: кожна наявна інсталяція зберігатиме ці дані так само, як і раніше, доки оператор не ввімкне цю функцію. Маршрут DELETE /api/v1/batches/delete-completed, який запускає оператор, у будь-якому разі не змінюється — це окремий безумовний контракт публічного API.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Доступне оновлення: v{current} → v{latest}", "cliproxyapiVersion": "Версія" }, + "modelCatalog": { + "title": "Моделі та комбо", + "subtitle": "Переглядайте та перевіряйте працездатність моделей і конвеєрів маршрутизації комбо для всіх провайдерів.", + "refresh": "Оновити", + "modelsTab": "Моделі", + "combosTab": "Комбо", + "catalogSections": "Розділи каталогу", + "loading": "Завантаження...", + "retry": "Повторити", + "unableToLoad": "Не вдалося завантажити каталог моделей.", + "unableToLoadCombos": "Не вдалося завантажити комбо.", + "checkConnection": "Перевірте з'єднання та спробуйте знову.", + "noModelsAvailable": "Моделі поки недоступні.", + "noModelsMatch": "Жодна модель не відповідає цим фільтрам.", + "noCombosAvailable": "Комбо поки недоступні.", + "noCombosMatch": "Жодне комбо не відповідає цим фільтрам.", + "clearFilters": "Очистити фільтри", + "searchModels": "Пошук моделей", + "searchModelsPlaceholder": "Пошук за моделлю, провайдером або можливістю", + "searchCombos": "Пошук комбо", + "searchCombosPlaceholder": "Пошук за назвою комбо, моделями або описом", + "modelCountSingle": "модель", + "modelCountPlural": "моделі", + "comboCountSingle": "комбо", + "comboCountPlural": "комбо", + "provider": "Провайдер", + "allProviders": "Усі провайдери", + "type": "Тип", + "allTypes": "Усі типи", + "subtype": "Підтип", + "allSubtypes": "Усі підтипи", + "capability": "Можливість", + "allCapabilities": "Усі можливості", + "pricing": "Тарифи", + "allPricing": "Усі тарифи", + "freeOnly": "Лише безкоштовні", + "nonFree": "Стандартні / Платні", + "providerHealth": "Стан провайдера", + "allHealthStates": "Усі стани", + "healthy": "В нормі", + "degraded": "Погіршено", + "down": "Недоступний", + "testResult": "Результат тесту", + "allResults": "Усі результати", + "untested": "Не протестовано", + "statusOk": "OK", + "statusSlow": "Повільно", + "statusError": "Помилка", + "minContext": "Мін. контекст", + "minContextPlaceholder": "напр., 32000", + "strategy": "Стратегія", + "allStrategies": "Усі стратегії", + "status": "Статус", + "allStatuses": "Усі статуси", + "active": "Активний", + "paused": "Призупинено", + "minMembers": "Мін. учасників", + "minMembersPlaceholder": "напр., 1", + "maxMembers": "Макс. учасників", + "maxMembersPlaceholder": "напр., 10", + "testSelected": "Тестувати вибрані ({count})", + "testAllFiltered": "Тестувати всі відфільтровані ({count})", + "cancel": "Скасувати", + "clearResults": "Очистити результати", + "testing": "Тестування...", + "rateLimited": "Ліміт запитів", + "quotaExceeded": "Перевищено квоту", + "timeout": "Час очікування минув", + "otherError": "Помилка", + "justNow": "Щойно", + "minutesAgo": "{count} хв тому", + "hoursAgo": "{count} год тому", + "tableRegion": "Таблиця каталогу моделей", + "combosTableRegion": "Таблиця каталогу комбінацій", + "tableCaption": "Каталог моделей серед усіх провайдерів", + "combosTableCaption": "Каталог комбінацій із результатами перевірки працездатності", + "selectAllModels": "Вибрати всі моделі на цій сторінці", + "selectAllCombos": "Вибрати всі комбінації на цій сторінці", + "selectModel": "Вибрати модель {name}", + "selectCombo": "Вибрати комбінацію {name}", + "model": "Модель", + "capabilities": "Можливості", + "context": "Контекст", + "output": "Макс. вивід", + "flags": "Прапорці", + "healthTest": "Тест працездатності", + "actions": "Дії", + "test": "Тестувати", + "custom": "Користувацький", + "free": "Безкоштовно", + "noFlags": "Немає даних про ціну або прапорець джерела", + "noCapabilities": "Немає метаданих про можливості", + "showingModels": "Показано {first}–{last} з {total} моделей", + "showingCombos": "Показано {first}–{last} з {total} комбо", + "refreshing": "Оновлення…", + "refreshFailed": "Не вдалося оновити. Показано останній завантажений каталог.", + "page": "Сторінка {page} з {pageCount}", + "previous": "Попередня", + "next": "Наступна", + "combo": "Комбо", + "members": "Учасники", + "moreMembers": "+{count} ще" + }, "combos": { "title": "Комбо", "description": "Створюйте комбінації моделей із зваженою маршрутизацією та підтримкою резервного варіанту", diff --git a/src/i18n/messages/ur.json b/src/i18n/messages/ur.json index cea69885fda1..bee446958e72 100644 --- a/src/i18n/messages/ur.json +++ b/src/i18n/messages/ur.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "پرووائیڈر بھیجنے کے لیے فی ٹیننٹ انکولی ورچوئل ایڈمیشن لین فعال کریں (#9654): ایک ٹیننٹ کا اچانک بوجھ اب دوسرے ٹیننٹ کو 503 نہیں دیتا۔ OMNIROUTE_CHAT_VIRTUAL_LANES ماحولیاتی متغیر اس ڈیش بورڈ سیٹنگ پر فوقیت رکھتا ہے؛ تبدیلیاں سرور دوبارہ شروع ہونے پر اثر انداز ہوتی ہیں۔", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "ڈیش بورڈ کے فراہم کنندہ صفحات: مفت بیج صرف ان سگنلز پر دکھائیں جنہیں فراہم کنندہ تسلیم کرتا ہے — یہ ڈسپلے نام پر مبنی اندازے، غیر بولین مفت فیلڈز، اور دستاویزی مفت درجے کے بغیر رجسٹرڈ فراہم کنندگان پر :free لاحقوں کو نظر انداز کرتا ہے۔ غیر فعال کرنے پر تاریخی بیج کا اصول برقرار رہتا ہے۔", "featureFlagProxySkipRecentlyFailedDescription": "پراکسی پولز اور opencode کی فی اکاؤنٹ روٹیشن کسی ایسی پراکسی کو دوبارہ پیش کرنے سے عارضی طور پر روکتی ہے جو ابھی ناکام ہوئی ہو (TCP پروب مسترد ہوا ہو، یا اس کے ذریعے 429 موصول ہوا ہو)۔ یہ فی پروسیس مدت ہر بار ناکامی دہرائے جانے پر دگنی ہوتی ہے، ایک مقررہ حد تک۔ پراکسی کا کوئی اسٹیٹس نہیں لکھا جاتا؛ تمام امیدواروں کو ایک طرف رکھ دیے جانے کی صورت میں انتخاب میں کوئی تبدیلی نہیں آتی۔ بطور ڈیفالٹ فعال؛ `false` سادہ انتخاب بحال کرتا ہے۔", - "featureFlagProxyPoolSharedEgressOrderDescription": "ان فراہم کنندگان کے لیے جن کا کوٹہ egress ایڈریس کے لحاظ سے تقسیم کیا گیا ہے، پول کے ایسے رکن کو جو حال ہی میں مسترد کیے گئے رکن کے مشاہدہ کردہ egress ایڈریس کا اشتراک کرتا ہو، صحت مند ارکان سے بالکل نیچے درجہ دیں۔ صرف ترتیب، کبھی خارج نہیں کیا جاتا۔ PROXY_SKIP_RECENTLY_FAILED درکار ہے، جو مسترد ہونے کا وہ سگنل پیدا کرتا ہے جسے یہ پڑھتا ہے۔ ڈیفالٹ طور پر بند: انتخاب کی ترتیب بالکل سادہ روٹیشن جیسی ہوتی ہے۔", "featureFlagProxyPoolEgressObservationDescription": "ڈیش بورڈ میں کسی پراکسی پول کے تحت دکھائیں کہ گزشتہ 24 گھنٹوں کے دوران کتنے مشاہدہ شدہ ایگریس IPs نے اس کے اراکین کو سروس فراہم کی، کتنے کنکشنز نے انہیں استعمال کیا، اور ایک IP کے پیچھے سب سے زیادہ کتنے اراکین دیکھے گئے۔ صرف پڑھنے کے لیے، پراکسی لاگ سے شمار شدہ، اور روٹنگ کے لیے کبھی استعمال نہیں ہوتا۔ بطور ڈیفالٹ بند: پول ایڈیٹر میں کوئی تبدیلی نہیں ہوتی اور مشاہدے کا روٹ null واپس کرتا ہے۔", "featureFlagProxyHealthBlockedResetsStreakDescription": "پراکسی ہیلتھ سویپ میں، ہدف کی جانب سے مسترد کردہ پروب (401/403/429: پراکسی نے اسے آگے پہنچایا، مگر منزل نے اس ایگریس IP کو مسترد کر دیا) کو پراکسی کی مسلسل ناکامیوں کا سلسلہ اسی طرح ری سیٹ کرنے دیں جیسے پیش کیا گیا پروب کرتا ہے۔ بطور ڈیفالٹ بند: مسترد ہونا غیر جانب دار رہتا ہے اور سلسلے کو برقرار رکھتا ہے۔ 5xx دونوں صورتوں میں غیر فیصلہ کن رہتا ہے، اور مسترد ہونا کبھی بھی کسی پراکسی کو ہٹاتا، غیر فعال کرتا یا دوبارہ فعال نہیں کرتا۔", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "خودکار صفائی کے عمل کو OMNIROUTE_BATCH_RETENTION_DAYS سے زیادہ پرانی اختتامی حالت والی (مکمل/ناکام/منسوخ/میعاد ختم شدہ) Batch API جابز، ان کے ہر سطر کے چیک پوائنٹس سمیت، حذف کرنے دیں اور ان اپ لوڈ شدہ فائلوں کا BLOB مواد صاف کر دیں جن کی اپنی expires_at گزر چکی ہو۔ بطور ڈیفالٹ بند: آپریٹر کے فعال کرنے تک ہر موجودہ انسٹالیشن یہ ڈیٹا بالکل پہلے کی طرح برقرار رکھتی ہے۔ آپریٹر کی جانب سے شروع کیا جانے والا DELETE /api/v1/batches/delete-completed روٹ دونوں صورتوں میں غیر متاثر رہتا ہے — یہ ایک الگ، غیر مشروط عوامی API معاہدہ ہے۔", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "اپ ڈیٹ دستیاب ہے: v{current} → v{latest}", "cliproxyapiVersion": "ورژن" }, + "modelCatalog": { + "title": "ماڈلز اور کمبوز", + "subtitle": "تمام فراہم کنندگان کے ماڈلز اور کمبو روٹنگ پائپ لائنز کو براؤز کریں اور ان کی ہیلتھ ٹیسٹ کریں۔", + "refresh": "ریفریش کریں", + "modelsTab": "ماڈلز", + "combosTab": "کمبوز", + "catalogSections": "کیٹلاگ کے سیکشنز", + "loading": "لوڈ ہو رہا ہے...", + "retry": "دوبارہ کوشش کریں", + "unableToLoad": "ماڈل کیٹلاگ لوڈ نہیں ہو سکا۔", + "unableToLoadCombos": "کمبوز لوڈ نہیں ہو سکے۔", + "checkConnection": "کنکشن چیک کریں اور دوبارہ کوشش کریں۔", + "noModelsAvailable": "ابھی کوئی ماڈل دستیاب نہیں ہے۔", + "noModelsMatch": "ان فلٹرز سے کوئی ماڈل مطابقت نہیں رکھتا۔", + "noCombosAvailable": "ابھی کوئی کمبو دستیاب نہیں ہے۔", + "noCombosMatch": "ان فلٹرز سے کوئی کمبو مطابقت نہیں رکھتا۔", + "clearFilters": "فلٹرز صاف کریں", + "searchModels": "ماڈلز تلاش کریں", + "searchModelsPlaceholder": "ماڈل، فراہم کنندہ، یا صلاحیت کے لحاظ سے تلاش کریں", + "searchCombos": "کمبوز تلاش کریں", + "searchCombosPlaceholder": "کمبو کے نام، ماڈلز، یا تفصیل کے لحاظ سے تلاش کریں", + "modelCountSingle": "ماڈل", + "modelCountPlural": "ماڈلز", + "comboCountSingle": "کمبو", + "comboCountPlural": "کمبوز", + "provider": "فراہم کنندہ", + "allProviders": "تمام فراہم کنندگان", + "type": "قسم", + "allTypes": "تمام اقسام", + "subtype": "ذیلی قسم", + "allSubtypes": "تمام ذیلی اقسام", + "capability": "صلاحیت", + "allCapabilities": "تمام صلاحیتیں", + "pricing": "قیمتیں", + "allPricing": "تمام قیمتیں", + "freeOnly": "صرف مفت", + "nonFree": "معیاری / غیر مفت", + "providerHealth": "فراہم کنندہ کی ہیلتھ", + "allHealthStates": "ہیلتھ کی تمام حالتیں", + "healthy": "صحت مند", + "degraded": "متاثرہ", + "down": "ڈاؤن", + "testResult": "ٹیسٹ کا نتیجہ", + "allResults": "تمام نتائج", + "untested": "غیر جانچا شدہ", + "statusOk": "ٹھیک ہے", + "statusSlow": "سست", + "statusError": "خرابی", + "minContext": "کم از کم کنٹیکسٹ", + "minContextPlaceholder": "مثلاً 32000", + "strategy": "حکمت عملی", + "allStrategies": "تمام حکمت عملیاں", + "status": "حالت", + "allStatuses": "تمام حالتیں", + "active": "فعال", + "paused": "موقوف", + "minMembers": "کم از کم اراکین", + "minMembersPlaceholder": "مثلاً 1", + "maxMembers": "زیادہ سے زیادہ اراکین", + "maxMembersPlaceholder": "مثلاً 10", + "testSelected": "منتخب کردہ ٹیسٹ کریں ({count})", + "testAllFiltered": "تمام فلٹر شدہ ٹیسٹ کریں ({count})", + "cancel": "منسوخ کریں", + "clearResults": "نتائج صاف کریں", + "testing": "ٹیسٹ جاری ہے...", + "rateLimited": "ریٹ محدود", + "quotaExceeded": "کوٹہ ختم ہو گیا", + "timeout": "وقت ختم ہو گیا", + "otherError": "خرابی", + "justNow": "ابھی ابھی", + "minutesAgo": "{count} منٹ پہلے", + "hoursAgo": "{count} گھنٹے پہلے", + "tableRegion": "ماڈل کیٹلاگ ٹیبل", + "combosTableRegion": "کومبوز کیٹلاگ ٹیبل", + "tableCaption": "تمام فراہم کنندگان کا ماڈل کیٹلاگ", + "combosTableCaption": "ہیلتھ ٹیسٹ کے نتائج کے ساتھ کومبوز کیٹلاگ", + "selectAllModels": "اس صفحے پر تمام ماڈلز منتخب کریں", + "selectAllCombos": "اس صفحے پر تمام کومبوز منتخب کریں", + "selectModel": "ماڈل {name} منتخب کریں", + "selectCombo": "کومبو {name} منتخب کریں", + "model": "ماڈل", + "capabilities": "صلاحیتیں", + "context": "سیاق و سباق", + "output": "زیادہ سے زیادہ آؤٹ پٹ", + "flags": "فلیگز", + "healthTest": "ہیلتھ ٹیسٹ", + "actions": "کارروائیاں", + "test": "ٹیسٹ", + "custom": "کسٹم", + "free": "مفت", + "noFlags": "کوئی قیمت یا سورس فلیگ رپورٹ نہیں ہوا", + "noCapabilities": "صلاحیت کا کوئی میٹا ڈیٹا رپورٹ نہیں ہوا", + "showingModels": "{total} ماڈلز میں سے {first}–{last} دکھائے جا رہے ہیں", + "showingCombos": "{total} کمبوز میں سے {first}–{last} دکھائے جا رہے ہیں", + "refreshing": "ریفریش ہو رہا ہے…", + "refreshFailed": "ریفریش ناکام ہو گیا۔ آخری لوڈ کردہ کیٹلاگ دکھایا جا رہا ہے۔", + "page": "صفحہ {page} از {pageCount}", + "previous": "پچھلا", + "next": "اگلا", + "combo": "کمبو", + "members": "ارکان", + "moreMembers": "+{count} مزید" + }, "combos": { "title": "کمبوز", "description": "وزنی روٹنگ اور فال بیک سپورٹ کے ساتھ ماڈل کمبوز بنائیں", diff --git a/src/i18n/messages/uz.json b/src/i18n/messages/uz.json index 0154ddd60a9b..d6dd7283a78e 100644 --- a/src/i18n/messages/uz.json +++ b/src/i18n/messages/uz.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Provayderga joʻnatish uchun har bir ijarachiga moslashuvchan virtual qabul yoʻlaklarini yoqish (#9654): endi bir ijarachining keskin soʻrovlar oqimi boshqasida 503 xatosini keltirib chiqarmaydi. OMNIROUTE_CHAT_VIRTUAL_LANES muhit oʻzgaruvchisi boshqaruv panelidagi ushbu sozlamadan ustun turadi; oʻzgarishlar server qayta ishga tushirilganda kuchga kiradi.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Boshqaruv panelidagi provayder sahifalari: Bepul nishonini faqat provayder qo‘llab-quvvatlaydigan signallarda ko‘rsating — hujjatlashtirilgan bepul tarifi bo‘lmagan ro‘yxatdan o‘tgan provayderlar uchun ko‘rsatiladigan nomga asoslangan evristika, mantiqiy bo‘lmagan bepul maydonlar va :free suffikslari hisobga olinmaydi. O‘chirilsa, tarixiy nishon qoidasi saqlanadi.", "featureFlagProxySkipRecentlyFailedDescription": "Proksi-pullar va opencode’ning har bir hisob bo‘yicha aylantirish mexanizmi hozirgina ishlamay qolgan proksini (TCP tekshiruvini rad etgan yoki u orqali 429 javobi olingan) har bir jarayon uchun takroriy urinish sayin ikki baravar oshib, belgilangan chegaragacha yetadigan muddat davomida qayta taqdim etmaydi. Proksi holati yozib qo‘yilmaydi; barcha nomzodlar chetga surilsa, tanlov o‘zgarmaydi. Standart holatda yoqilgan; `false` oddiy tanlovni tiklaydi.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Kvotasi chiqish manzili boʻyicha taqsimlangan provayderlar uchun yaqinda rad etilgan aʼzoning kuzatilgan chiqish manziliga ega pul aʼzosini sogʻlom aʼzolardan sal pastroqqa joylashtirish. Faqat tartiblash, hech qachon chiqarib tashlanmaydi. U oʻqiydigan rad etish signalini hosil qiluvchi PROXY_SKIP_RECENTLY_FAILED talab etiladi. Standart holatda oʻchiq: tanlash tartibi aynan oddiy rotatsiyadir.", "featureFlagProxyPoolEgressObservationDescription": "Boshqaruv panelida proksi-pul ostida so‘nggi 24 soat ichida uning a’zolariga nechta kuzatilgan chiquvchi IP xizmat ko‘rsatgani, ulardan nechta ulanish foydalangani va bitta IP ortida eng ko‘p nechta a’zo kuzatilganini ko‘rsating. Faqat o‘qish uchun mo‘ljallangan, proksi jurnalidan hisoblanadi va yo‘naltirish uchun hech qachon ishlatilmaydi. Standart holatda o‘chiq: pul muharriri o‘zgarmaydi va kuzatuv marshruti null javobini qaytaradi.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Proksi holatini tekshirish jarayonida maqsad rad etgan tekshiruv (401/403/429: proksi uzatdi, manzil esa ushbu chiquvchi IP’ni rad etdi) muvaffaqiyatli xizmat ko‘rsatilgan tekshiruv kabi proksining ketma-ket muvaffaqiyatsizliklar hisoblagichini tiklashiga ruxsat bering. Standart holatda o‘chiq: rad etish neytral bo‘lib qoladi va hisoblagichni saqlaydi. 5xx har ikki holatda ham noaniq bo‘lib qoladi, rad etish esa proksini hech qachon olib tashlamaydi, o‘chirib qo‘ymaydi yoki qayta faollashtirmaydi.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Avtomatik tozalash jarayoniga OMNIROUTE_BATCH_RETENTION_DAYS muddatidan eski yakuniy holatdagi (completed/failed/cancelled/expired) Batch API vazifalarini ularning har bir qator uchun nazorat nuqtalari bilan birga oʻchirishga va oʻz expires_at muddatidan oʻtgan yuklangan fayllarning BLOB tarkibini tozalashga ruxsat bering. Odatiy holatda oʻchiq: operator bu imkoniyatni yoqmaguncha, barcha mavjud oʻrnatishlarda bu maʼlumotlar avvalgidek saqlanadi. Operator ishga tushiradigan DELETE /api/v1/batches/delete-completed marshrutiga bundan qatʼi nazar taʼsir qilinmaydi — u alohida, shartsiz ommaviy API shartnomasidir.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Yangilanish mavjud: v{current} → v{latest}", "cliproxyapiVersion": "Versiya" }, + "modelCatalog": { + "title": "Modellar va Kombolar", + "subtitle": "Barcha provayderlar boʻyicha modellar va kombo marshrutlash quvurlarini koʻrib chiqing hamda holatini tekshiring.", + "refresh": "Yangilash", + "modelsTab": "Modellar", + "combosTab": "Kombolar", + "catalogSections": "Katalog boʻlimlari", + "loading": "Yuklanmoqda...", + "retry": "Qayta urinish", + "unableToLoad": "Modellar katalogini yuklab boʻlmadi.", + "unableToLoadCombos": "Kombolarni yuklab boʻlmadi.", + "checkConnection": "Ulanishni tekshiring va qayta urinib koʻring.", + "noModelsAvailable": "Hozircha hech qanday model mavjud emas.", + "noModelsMatch": "Ushbu filtrlarga mos keladigan modellar topilmadi.", + "noCombosAvailable": "Hozircha hech qanday kombo mavjud emas.", + "noCombosMatch": "Ushbu filtrlarga mos keladigan kombolar topilmadi.", + "clearFilters": "Filtrlarni tozalash", + "searchModels": "Modellarni qidirish", + "searchModelsPlaceholder": "Model, provayder yoki imkoniyat boʻyicha qidirish", + "searchCombos": "Kombolarni qidirish", + "searchCombosPlaceholder": "Kombo nomi, modellar yoki tavsif boʻyicha qidirish", + "modelCountSingle": "model", + "modelCountPlural": "modellar", + "comboCountSingle": "kombo", + "comboCountPlural": "kombolar", + "provider": "Provayder", + "allProviders": "Barcha provayderlar", + "type": "Turi", + "allTypes": "Barcha turlar", + "subtype": "Quyi turi", + "allSubtypes": "Barcha quyi turlar", + "capability": "Imkoniyat", + "allCapabilities": "Barcha imkoniyatlar", + "pricing": "Narxlar", + "allPricing": "Barcha narxlar", + "freeOnly": "Faqat bepul", + "nonFree": "Standart / Bepul boʻlmagan", + "providerHealth": "Provayder holati", + "allHealthStates": "Barcha holatlar", + "healthy": "Sogʻlom", + "degraded": "Yomonlashgan", + "down": "Ishlamayapti", + "testResult": "Sinov natijasi", + "allResults": "Barcha natijalar", + "untested": "Sinovdan oʻtmagan", + "statusOk": "OK", + "statusSlow": "Sekin", + "statusError": "Xato", + "minContext": "Minimal kontekst", + "minContextPlaceholder": "masalan, 32000", + "strategy": "Strategiya", + "allStrategies": "Barcha strategiyalar", + "status": "Holat", + "allStatuses": "Barcha holatlar", + "active": "Faol", + "paused": "Toʻxtatilgan", + "minMembers": "Minimal aʼzolar", + "minMembersPlaceholder": "masalan, 1", + "maxMembers": "Maksimal aʼzolar", + "maxMembersPlaceholder": "masalan, 10", + "testSelected": "Tanlanganlarni sinash ({count})", + "testAllFiltered": "Barcha filtrlanganlarni sinash ({count})", + "cancel": "Bekor qilish", + "clearResults": "Natijalarni tozalash", + "testing": "Sinovdan oʻtkazilmoqda...", + "rateLimited": "Soʻrovlar soni cheklangan", + "quotaExceeded": "Kvota oshib ketgan", + "timeout": "Kutish vaqti tugadi", + "otherError": "Xato", + "justNow": "Hozirgina", + "minutesAgo": "{count} daqiqa oldin", + "hoursAgo": "{count} soat oldin", + "tableRegion": "Modellar katalogi jadvali", + "combosTableRegion": "Kombinatsiyalar katalogi jadvali", + "tableCaption": "Barcha provayderlar boʻyicha modellar katalogi", + "combosTableCaption": "Holat sinovi natijalari bilan kombinatsiyalar katalogi", + "selectAllModels": "Ushbu sahifadagi barcha modellarni tanlash", + "selectAllCombos": "Ushbu sahifadagi barcha kombinatsiyalarni tanlash", + "selectModel": "{name} modelini tanlash", + "selectCombo": "{name} kombinatsiyasini tanlash", + "model": "Model", + "capabilities": "Imkoniyatlar", + "context": "Kontekst", + "output": "Maksimal chiqish", + "flags": "Flaglar", + "healthTest": "Holat testi", + "actions": "Amallar", + "test": "Sinash", + "custom": "Maxsus", + "free": "Bepul", + "noFlags": "Narx yoki manba flagi bildirilmagan", + "noCapabilities": "Imkoniyat metamaʼlumotlari bildirilmagan", + "showingModels": "{total} ta modeldan {first}–{last} koʻrsatilmoqda", + "showingCombos": "{total} ta kombodan {first}–{last} koʻrsatilmoqda", + "refreshing": "Yangilanmoqda…", + "refreshFailed": "Yangilash amalga oshmadi. Oxirgi yuklangan katalog koʻrsatilmoqda.", + "page": "{pageCount} sahifadan {page}-sahifa", + "previous": "Oldingi", + "next": "Keyingi", + "combo": "Kombo", + "members": "Aʼzolar", + "moreMembers": "Yana +{count} ta" + }, "combos": { "title": "Kombinatsiyalar", "description": "Vaznli yoʻnaltirish va zaxira variantlarini qoʻllab-quvvatlaydigan model kombinatsiyalarini yarating", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index 98350ed8eb8f..c026644d5526 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -3217,6 +3217,109 @@ "cliproxyapiUpdateAvailable": "Có bản cập nhật: v{current} → v{latest}", "cliproxyapiVersion": "Phiên bản" }, + "modelCatalog": { + "title": "Mô hình & Combo", + "subtitle": "Duyệt và kiểm tra tình trạng hoạt động của các mô hình cùng pipeline định tuyến combo trên mọi nhà cung cấp.", + "refresh": "Làm mới", + "modelsTab": "Mô hình", + "combosTab": "Combo", + "catalogSections": "Các mục danh mục", + "loading": "Đang tải...", + "retry": "Thử lại", + "unableToLoad": "Không thể tải danh mục mô hình.", + "unableToLoadCombos": "Không thể tải combo.", + "checkConnection": "Kiểm tra kết nối và thử lại.", + "noModelsAvailable": "Chưa có mô hình nào khả dụng.", + "noModelsMatch": "Không có mô hình nào khớp với bộ lọc này.", + "noCombosAvailable": "Chưa có combo nào khả dụng.", + "noCombosMatch": "Không có combo nào khớp với bộ lọc này.", + "clearFilters": "Xóa bộ lọc", + "searchModels": "Tìm kiếm mô hình", + "searchModelsPlaceholder": "Tìm kiếm theo mô hình, nhà cung cấp hoặc khả năng", + "searchCombos": "Tìm kiếm combo", + "searchCombosPlaceholder": "Tìm kiếm theo tên combo, mô hình hoặc mô tả", + "modelCountSingle": "mô hình", + "modelCountPlural": "mô hình", + "comboCountSingle": "combo", + "comboCountPlural": "combo", + "provider": "Nhà cung cấp", + "allProviders": "Tất cả nhà cung cấp", + "type": "Loại", + "allTypes": "Tất cả các loại", + "subtype": "Loại phụ", + "allSubtypes": "Tất cả các loại phụ", + "capability": "Khả năng", + "allCapabilities": "Tất cả khả năng", + "pricing": "Mức giá", + "allPricing": "Tất cả mức giá", + "freeOnly": "Chỉ miễn phí", + "nonFree": "Tiêu chuẩn / Có phí", + "providerHealth": "Tình trạng nhà cung cấp", + "allHealthStates": "Tất cả trạng thái hoạt động", + "healthy": "Hoạt động tốt", + "degraded": "Bị suy giảm", + "down": "Ngừng hoạt động", + "testResult": "Kết quả kiểm tra", + "allResults": "Tất cả kết quả", + "untested": "Chưa kiểm tra", + "statusOk": "OK", + "statusSlow": "Chậm", + "statusError": "Lỗi", + "minContext": "Ngữ cảnh tối thiểu", + "minContextPlaceholder": "vd: 32000", + "strategy": "Chiến lược", + "allStrategies": "Tất cả chiến lược", + "status": "Trạng thái", + "allStatuses": "Tất cả trạng thái", + "active": "Đang hoạt động", + "paused": "Đã tạm dừng", + "minMembers": "Thành viên tối thiểu", + "minMembersPlaceholder": "vd: 1", + "maxMembers": "Thành viên tối đa", + "maxMembersPlaceholder": "vd: 10", + "testSelected": "Kiểm tra mục đã chọn ({count})", + "testAllFiltered": "Kiểm tra tất cả mục đã lọc ({count})", + "cancel": "Hủy", + "clearResults": "Xóa kết quả", + "testing": "Đang kiểm tra...", + "rateLimited": "Bị giới hạn tần suất", + "quotaExceeded": "Vượt quá hạn ngạch", + "timeout": "Hết thời gian chờ", + "otherError": "Lỗi", + "justNow": "Vừa xong", + "minutesAgo": "{count} phút trước", + "hoursAgo": "{count} giờ trước", + "tableRegion": "Bảng danh mục mô hình", + "combosTableRegion": "Bảng danh mục combo", + "tableCaption": "Danh mục mô hình trên tất cả nhà cung cấp", + "combosTableCaption": "Danh mục combo kèm kết quả kiểm tra tình trạng", + "selectAllModels": "Chọn tất cả mô hình trên trang này", + "selectAllCombos": "Chọn tất cả combo trên trang này", + "selectModel": "Chọn mô hình {name}", + "selectCombo": "Chọn combo {name}", + "model": "Mô hình", + "capabilities": "Khả năng", + "context": "Ngữ cảnh", + "output": "Đầu ra tối đa", + "flags": "Cờ", + "healthTest": "Kiểm tra tình trạng", + "actions": "Thao tác", + "test": "Kiểm tra", + "custom": "Tùy chỉnh", + "free": "Miễn phí", + "noFlags": "Không có báo cáo về giá hoặc cờ nguồn", + "noCapabilities": "Không có báo cáo siêu dữ liệu khả năng", + "showingModels": "Đang hiển thị {first}–{last} trên {total} mô hình", + "showingCombos": "Đang hiển thị {first}–{last} trên {total} combo", + "refreshing": "Đang làm mới…", + "refreshFailed": "Làm mới thất bại. Đang hiển thị danh mục được tải lần cuối.", + "page": "Trang {page} trên {pageCount}", + "previous": "Trước", + "next": "Tiếp", + "combo": "Combo", + "members": "Thành viên", + "moreMembers": "+{count} nữa" + }, "combos": { "title": "Combo", "description": "Tạo các combo mô hình với hỗ trợ định tuyến có trọng số và dự phòng", diff --git a/src/i18n/messages/yo.json b/src/i18n/messages/yo.json index 50209be1deff..fdbce7170af9 100644 --- a/src/i18n/messages/yo.json +++ b/src/i18n/messages/yo.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "Mú àwọn ọ̀nà ìgbàwọlé aláfojúṣe tí ń mú ara wọn bá ipò mu fún tenant kọ̀ọ̀kan ṣiṣẹ́ fún provider dispatch (#9654): ìrujáde tenant kan kò ní fa 503 fún tenant mìíràn mọ́. env var OMNIROUTE_CHAT_VIRTUAL_LANES ni ó ṣáájú àtúnṣe dashboard yìí; àwọn ìyípadà yóò bẹ̀rẹ̀ sí í ṣiṣẹ́ nígbà tí server bá tún bẹ̀rẹ̀.", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "Àwọn ojú-ìwé olùpèsè lórí Dashboard: fi báàjì Ọ̀fẹ́ hàn lórí àwọn àmì tí olùpèsè náà fọwọ́ sí nìkan — èyí yọ ọ̀nà ìfojúrí orúkọ ìfihàn, àwọn ààyè ọ̀fẹ́ tí kì í ṣe Boolean àti àwọn ìparí :free kúrò lórí àwọn olùpèsè tí a forúkọsílẹ̀ tí kò ní ipele ọ̀fẹ́ tí a ṣàkọsílẹ̀. Pípa rẹ̀ yóò pa òfin báàjì ìṣáájú mọ́.", "featureFlagProxySkipRecentlyFailedDescription": "Àwọn àkójọpọ̀ proxy àti yíyí opencode fún àkọọ́lẹ̀ kọ̀ọ̀kan máa ń dáwọ́ lílo proxy kan tí ó ṣẹ̀ṣẹ̀ kùnà dúró (ìdánwò TCP tí a kọ̀, tàbí 429 tí a gbà nípasẹ̀ rẹ̀) fún àkókò kan nínú process kọ̀ọ̀kan, èyí tí yóò di ìlọ́po méjì ní gbogbo ìgbà tí ó tún ṣẹlẹ̀, títí dé òpin tí a yàn. A kì í kọ ipò proxy sílẹ̀; bí a bá fi gbogbo olùdíje sí ẹ̀gbẹ́ kan, yíyan náà kì í yí padà. Ó wà ní títàn ní àkọ́kọ́; `false` máa ń dá yíyan lasán padà.", - "featureFlagProxyPoolSharedEgressOrderDescription": "Fún àwọn olùpèsè tí kótà wọn jẹ́ pípín nípasẹ̀ àdírẹ́sì egress, fi ọmọ ẹgbẹ́ pool tí ó ń pín àdírẹ́sì egress tí a kíyèsí ti ọmọ ẹgbẹ́ tí a kọ̀ láìpẹ́ sí abẹ́ àwọn ọmọ ẹgbẹ́ tí ó dára díẹ̀. Àtòjọ nìkan, a kì í yọ ọ́ kúrò láéláé. Nílò PROXY_SKIP_RECENTLY_FAILED, èyí tí ń mú àmì ìkọ̀sílẹ̀ tí ó ń kà jáde. Kò ṣiṣẹ́ ní àkọ́kọ́: àtòjọ yíyàn jẹ́ ìyípo lásán gangan.", "featureFlagProxyPoolEgressObservationDescription": "Ṣàfihàn, lábẹ́ àkójọpọ̀ proxy kan nínú dashboard, iye àwọn IP egress tí a ṣàkíyèsí tí ó ṣiṣẹ́ fún àwọn ọmọ ẹgbẹ́ rẹ̀ láàárín wákàtí 24 tó kọjá, iye àwọn ìsopọ̀ tí ó lò wọ́n àti iye tó pọ̀ jù tí a rí lẹ́yìn IP kan. Fún kíkà nìkan, a ṣírò rẹ̀ láti inú àkọsílẹ̀ proxy, a kò sì lò ó fún routing láé. Ó wà ní pípa ní àkọ́kọ́: olóòtú àkójọpọ̀ náà kò yí padà, ipa-ọ̀nà àkíyèsí sì ń dá null padà.", "featureFlagProxyHealthBlockedResetsStreakDescription": "Nínú àyẹ̀wò ìlera proxy, jẹ́ kí ìdánwò kan tí ibi àfojúsùn kọ̀ (401/403/429: proxy náà gbé e dé, ibi àfojúsùn sì kọ IP egress yìí) tún iye àwọn ìkùnà tẹ̀léra ti proxy náà bẹ̀rẹ̀, bí ìdánwò tí a dáhùn sí. Ó wà ní pípa ní àkọ́kọ́: ìkọ̀ kan ṣì jẹ́ aláìdásí, ó sì ń pa iye tẹ̀léra náà mọ́. 5xx ṣì jẹ́ aláìdánilójú lọ́nà méjèèjì, ìkọ̀ kò sì lè yọ proxy kan kúrò, mú un má ṣiṣẹ́, tàbí tún mú un ṣiṣẹ́ láé.", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "Jẹ́ kí ìfọ̀mọ́ aládàáṣe pa àwọn iṣẹ́ Batch API tó ti dé òpin (tó parí/tó kùnà/tí a fagilé/tó kọjá àkókò) tí ọjọ́ orí wọn ti ju OMNIROUTE_BATCH_RETENTION_DAYS lọ, pẹ̀lú àwọn ibi ìṣàyẹ̀wò wọn fún ìlà kọ̀ọ̀kan, kí ó sì pa àkóónú BLOB àwọn fáìlì tí a ti rù sókè tí wọ́n ti kọjá expires_at tiwọn. A pa á ní àkọ́kọ́: gbogbo ìfìdásílẹ̀ tó wà tẹ́lẹ̀ yóò pa dátà yìí mọ́ gẹ́gẹ́ bí ó ti rí tẹ́lẹ̀ títí olùṣàkóso yóò fi yàn láti tan án. Ọ̀nà DELETE /api/v1/batches/delete-completed tí olùṣàkóso ń ṣiṣẹ́ kò ní ipa lọ́nàkọnà — ó jẹ́ àdéhùn API gbogbogbò tó yàtọ̀, tí kò gbára lé ipò kankan.", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "Ìmúdójúìwọ̀n wà: v{current} → v{latest}", "cliproxyapiVersion": "Ẹ̀yà" }, + "modelCatalog": { + "title": "Àwọn Àwòṣe & Àwọn Àkópọ̀", + "subtitle": "Wò kiri kí o sì dán ìlera àwọn àwòṣe àti àwọn ọ̀nà ìdarí àkópọ̀ wò kọjá gbogbo olùpèsè.", + "refresh": "Tún sọ di tuntun", + "modelsTab": "Àwọn Àwòṣe", + "combosTab": "Àwọn Àkópọ̀", + "catalogSections": "Àwọn Ìpín Kátálọ́ọ̀gì", + "loading": "Ń gbé e wọlé...", + "retry": "Tún gbìyànjú", + "unableToLoad": "Kò le gbé kátálọ́ọ̀gì àwòṣe wọlé.", + "unableToLoadCombos": "Kò le gbé àwọn àkópọ̀ wọlé.", + "checkConnection": "Yẹ ìsopọ̀ wò kí o sì tún gbìyànjú.", + "noModelsAvailable": "Kò tíì sí àwọn àwòṣe kankan.", + "noModelsMatch": "Kò sí àwọn àwòṣe tí ó bá àwọn àsẹ́kù wọ̀nyí mu.", + "noCombosAvailable": "Kò tíì sí àwọn àkópọ̀ kankan.", + "noCombosMatch": "Kò sí àwọn àkópọ̀ tí ó bá àwọn àsẹ́kù wọ̀nyí mu.", + "clearFilters": "Mú àwọn àsẹ́kù kúrò", + "searchModels": "Wá àwọn àwòṣe", + "searchModelsPlaceholder": "Ṣàwárí nípa àwòṣe, olùpèsè, tàbí agbára", + "searchCombos": "Wá àwọn àkópọ̀", + "searchCombosPlaceholder": "Ṣàwárí nípa orúkọ àkópọ̀, àwọn àwòṣe, tàbí àpèjúwe", + "modelCountSingle": "àwòṣe", + "modelCountPlural": "àwọn àwòṣe", + "comboCountSingle": "àkópọ̀", + "comboCountPlural": "àwọn àkópọ̀", + "provider": "Olùpèsè", + "allProviders": "Gbogbo àwọn olùpèsè", + "type": "Irúfẹ́", + "allTypes": "Gbogbo àwọn irúfẹ́", + "subtype": "Irúfẹ́ abẹ́lé", + "allSubtypes": "Gbogbo àwọn irúfẹ́ abẹ́lé", + "capability": "Agbára", + "allCapabilities": "Gbogbo àwọn agbára", + "pricing": "Iye owó", + "allPricing": "Gbogbo iye owó", + "freeOnly": "Ọ̀fẹ́ nìkan", + "nonFree": "Wọ́pọ̀ / Kì í ṣe ọ̀fẹ́", + "providerHealth": "Ìlera olùpèsè", + "allHealthStates": "Gbogbo àwọn ipò ìlera", + "healthy": "Ní ìlera", + "degraded": "Dínkù", + "down": "Kò ṣiṣẹ́", + "testResult": "Èsì àdánwò", + "allResults": "Gbogbo àwọn èsì", + "untested": "A kò tíì dán wò", + "statusOk": "Ó dára", + "statusSlow": "Ó lọ́ra", + "statusError": "Àṣìṣe", + "minContext": "Àkóónú tó kéré jù", + "minContextPlaceholder": "b.a. 32000", + "strategy": "Ìlànà", + "allStrategies": "Gbogbo àwọn ìlànà", + "status": "Ipò", + "allStatuses": "Gbogbo àwọn ipò", + "active": "Ń ṣiṣẹ́", + "paused": "Dádúró", + "minMembers": "Àwọn ọmọ ẹgbẹ́ tó kéré jù", + "minMembersPlaceholder": "b.a. 1", + "maxMembers": "Àwọn ọmọ ẹgbẹ́ tó pọ̀ jù", + "maxMembersPlaceholder": "b.a. 10", + "testSelected": "Dán àwọn tí a yàn wò ({count})", + "testAllFiltered": "Dán gbogbo àwọn tí a sẹ̀ wò ({count})", + "cancel": "Fagilé", + "clearResults": "Pa àwọn èsì rẹ́", + "testing": "Ń dán an wò...", + "rateLimited": "Ààlà ìwọ̀n ti dé", + "quotaExceeded": "Ìwọ̀n àyè ti kọjá", + "timeout": "Àkókò ti kọjá", + "otherError": "Àṣìṣe", + "justNow": "Ní báyìí gangan", + "minutesAgo": "ìṣẹ́jú {count} sẹ́yìn", + "hoursAgo": "wákàtí {count} sẹ́yìn", + "tableRegion": "Tábìlì àtòjọ àwòṣe", + "combosTableRegion": "Tábìlì àtòjọ àkópọ̀", + "tableCaption": "Àtòjọ àwòṣe kọjá gbogbo àwọn olùpèsè", + "combosTableCaption": "Àtòjọ àkópọ̀ pẹ̀lú àwọn èsì àdánwò ìlera", + "selectAllModels": "Yan gbogbo àwọn àwòṣe lórí ojú-ìwé yìí", + "selectAllCombos": "Yan gbogbo àwọn àkópọ̀ lórí ojú-ìwé yìí", + "selectModel": "Yan àwòṣe {name}", + "selectCombo": "Yan àkópọ̀ {name}", + "model": "Àwòṣe", + "capabilities": "Àwọn agbára", + "context": "Àyíká ọ̀rọ̀", + "output": "Àbájáde tó pọ̀ jù", + "flags": "Àwọn àmì", + "healthTest": "Àyẹ̀wò Ìlera", + "actions": "Àwọn ìgbésẹ̀", + "test": "Àyẹ̀wò", + "custom": "Àṣàkànṣe", + "free": "Ọ̀fẹ́", + "noFlags": "Kò sí iye tàbí àmì orísun tí a ròyìn", + "noCapabilities": "Kò sí mẹ́tádátà agbára tí a ròyìn", + "showingModels": "Ń fi {first}–{last} hàn nínú àwọn àwòṣe {total}", + "showingCombos": "Ń fi {first}–{last} hàn nínú àwọn àpapọ̀ {total}", + "refreshing": "Ń sọ dọ̀tun…", + "refreshFailed": "Ìsọdọ̀tun kùnà. Ń fi àtòjọ tí a gbà wọlé kẹ́yìn hàn.", + "page": "Ojú-ewé {page} nínú {pageCount}", + "previous": "Ti tẹ́lẹ̀", + "next": "Tókàn", + "combo": "Àpapọ̀", + "members": "Àwọn ọmọ ẹgbẹ́", + "moreMembers": "+{count} síi" + }, "combos": { "title": "Àwọn àkójọpọ̀", "description": "Ṣẹ̀dá àwọn àkójọpọ̀ awoṣe pẹ̀lú ìtọ́sọ́nà oníwọ̀n àti àtìlẹ́yìn ìpadàsẹ́yìn", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 28f5a066c4a5..932d50f24ebc 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "为提供者调度启用按租户的自适应虚拟准入通道(#9654):一个租户的突发流量不再导致另一个租户收到 503。OMNIROUTE_CHAT_VIRTUAL_LANES 环境变量优先于此仪表板设置;更改在服务器重启后生效。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "控制面板提供者页面:仅根据提供者认可的信号显示“免费”徽章——对于没有文档说明免费层级的已注册提供者,不再使用显示名称启发式规则、非布尔型免费字段和 :free 后缀。关闭时沿用旧版徽章规则。", "featureFlagProxySkipRecentlyFailedDescription": "代理池和 opencode 的按账户轮换会在每个进程的一段时间内,停止再次提供刚刚失败的代理(TCP 探测被拒绝,或通过该代理收到 429)。每次重复失败时,该时段都会翻倍,直至达到上限。不会写入代理状态;当所有候选代理都被暂时搁置时,选择保持不变。默认开启;设为 `false` 可恢复普通选择。", - "featureFlagProxyPoolSharedEgressOrderDescription": "对于配额按出口地址分桶的提供商,将与最近被拒绝成员共享相同观测出口地址的池成员排在健康成员之后。仅调整排序,绝不排除。需要 PROXY_SKIP_RECENTLY_FAILED,由其生成此功能所读取的拒绝信号。默认关闭:选择顺序完全遵循常规轮询。", "featureFlagProxyPoolEgressObservationDescription": "在仪表板的代理池下显示:过去 24 小时内观察到多少个出口 IP 为其成员提供服务、使用这些 IP 的连接数,以及单个 IP 对应的最大连接数。此信息为只读,根据代理日志计算,绝不用于路由。默认关闭:代理池编辑器保持不变,观测路由返回 null。", "featureFlagProxyHealthBlockedResetsStreakDescription": "在代理健康检查中,如果探测被目标拒绝(401/403/429:代理已转发,但目标拒绝了此出口 IP),则像探测成功一样重置代理的连续失败计数。默认关闭:拒绝保持中性,并保留当前连续失败计数。无论如何,5xx 均保持结果不确定,而且拒绝绝不会导致代理被移除、禁用或重新激活。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "允许自动清理任务删除早于 OMNIROUTE_BATCH_RETENTION_DAYS 的终态(已完成/失败/已取消/已过期)Batch API 作业及其逐行检查点,并清除超过各自 expires_at 的已上传文件的 BLOB 内容。默认关闭:在运维人员选择启用之前,所有现有安装都将继续像以前一样保留这些数据。无论是否启用,运维人员触发的 DELETE /api/v1/batches/delete-completed 路由均不受影响——它是一个独立且无条件执行的公共 API 契约。", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "可用更新:v{current} → v{latest}", "cliproxyapiVersion": "版本" }, + "modelCatalog": { + "title": "模型与组合", + "subtitle": "浏览并对各提供商的模型及组合路由流水线进行健康检测。", + "refresh": "刷新", + "modelsTab": "模型", + "combosTab": "组合", + "catalogSections": "目录分区", + "loading": "加载中...", + "retry": "重试", + "unableToLoad": "无法加载模型目录。", + "unableToLoadCombos": "无法加载组合。", + "checkConnection": "请检查网络连接并重试。", + "noModelsAvailable": "暂无可用的模型。", + "noModelsMatch": "没有符合这些筛选条件的模型。", + "noCombosAvailable": "暂无可用的组合。", + "noCombosMatch": "没有符合这些筛选条件的组合。", + "clearFilters": "清除筛选条件", + "searchModels": "搜索模型", + "searchModelsPlaceholder": "按模型、提供商或能力搜索", + "searchCombos": "搜索组合", + "searchCombosPlaceholder": "按组合名称、模型或描述搜索", + "modelCountSingle": "模型", + "modelCountPlural": "模型", + "comboCountSingle": "组合", + "comboCountPlural": "组合", + "provider": "提供商", + "allProviders": "所有提供商", + "type": "类型", + "allTypes": "所有类型", + "subtype": "子类型", + "allSubtypes": "所有子类型", + "capability": "能力", + "allCapabilities": "所有能力", + "pricing": "定价", + "allPricing": "所有定价", + "freeOnly": "仅免费", + "nonFree": "标准 / 付费", + "providerHealth": "提供商健康状态", + "allHealthStates": "所有健康状态", + "healthy": "健康", + "degraded": "降级", + "down": "宕机", + "testResult": "测试结果", + "allResults": "所有结果", + "untested": "未测试", + "statusOk": "正常", + "statusSlow": "缓慢", + "statusError": "错误", + "minContext": "最小上下文", + "minContextPlaceholder": "例如 32000", + "strategy": "策略", + "allStrategies": "所有策略", + "status": "状态", + "allStatuses": "所有状态", + "active": "已启用", + "paused": "已暂停", + "minMembers": "最小成员数", + "minMembersPlaceholder": "例如 1", + "maxMembers": "最大成员数", + "maxMembersPlaceholder": "例如 10", + "testSelected": "测试所选项 ({count})", + "testAllFiltered": "测试所有筛选项 ({count})", + "cancel": "取消", + "clearResults": "清除结果", + "testing": "测试中...", + "rateLimited": "已限流", + "quotaExceeded": "配额超限", + "timeout": "超时", + "otherError": "错误", + "justNow": "刚刚", + "minutesAgo": "{count} 分钟前", + "hoursAgo": "{count} 小时前", + "tableRegion": "模型目录表格", + "combosTableRegion": "组合目录表格", + "tableCaption": "所有提供商的模型目录", + "combosTableCaption": "包含健康测试结果的组合目录", + "selectAllModels": "选择本页所有模型", + "selectAllCombos": "选择本页所有组合", + "selectModel": "选择模型 {name}", + "selectCombo": "选择组合 {name}", + "model": "模型", + "capabilities": "能力", + "context": "上下文", + "output": "最大输出", + "flags": "标记", + "healthTest": "健康检查", + "actions": "操作", + "test": "测试", + "custom": "自定义", + "free": "免费", + "noFlags": "未报告价格或来源标记", + "noCapabilities": "未报告能力元数据", + "showingModels": "显示第 {first}–{last} 个模型,共 {total} 个", + "showingCombos": "显示第 {first}–{last} 个组合,共 {total} 个", + "refreshing": "正在刷新…", + "refreshFailed": "刷新失败。正在显示上次加载的目录。", + "page": "第 {page} 页,共 {pageCount} 页", + "previous": "上一页", + "next": "下一页", + "combo": "组合", + "members": "成员", + "moreMembers": "+{count} 更多" + }, "combos": { "title": "组合", "description": "创建支持权重路由与故障回退的模型组合", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 9d0425102289..aa480655ed54 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -994,7 +994,6 @@ "featureFlagChatVirtualLanesEnabledDescription": "為提供者調度啟用按租戶的自適應虛擬准入通道(#9654):一個租戶的突發流量不再導致另一個租戶收到 503。OMNIROUTE_CHAT_VIRTUAL_LANES 環境變數優先於此儀表板設定;變更在伺服器重新啟動後生效。", "featureFlagFreeBadgeRequiresProviderFreeTierDescription": "儀表板提供者頁面:僅根據提供者明確認可的訊號顯示「免費」徽章——不再對沒有文件說明免費方案的已註冊提供者使用顯示名稱啟發法、非布林值免費欄位及 :free 後綴。關閉時會沿用過往的徽章規則。", "featureFlagProxySkipRecentlyFailedDescription": "Proxy 集區以及 opencode 的每帳戶輪替機制,會在每個處理程序的一段期間內,停止再次使用剛失敗的 Proxy(TCP 探測遭拒,或透過該 Proxy 收到 429)。每次重複失敗時,這段期間都會加倍,直到達到上限。不會寫入任何 Proxy 狀態;即使所有候選項目都被暫時擱置,選擇結果仍維持不變。預設開啟;設為 `false` 可恢復一般選擇。", - "featureFlagProxyPoolSharedEgressOrderDescription": "對於配額依出口位址劃分的提供者,將與近期遭拒成員共用所觀測出口位址的集區成員排在健康成員之後。僅調整順序,絕不排除。需要 PROXY_SKIP_RECENTLY_FAILED,由其產生所讀取的拒絕信號。預設為關閉:選取順序完全為一般的輪替。", "featureFlagProxyPoolEgressObservationDescription": "在儀表板的 Proxy 集區下方,顯示過去 24 小時內觀察到多少個出口 IP 為其成員提供服務、使用這些 IP 的連線數,以及單一 IP 後方觀察到的最高數量。唯讀,根據 Proxy 記錄計算,絕不會用於路由。預設關閉:集區編輯器維持不變,觀察路由會回傳 null。", "featureFlagProxyHealthBlockedResetsStreakDescription": "在 Proxy 健康狀態掃描中,讓遭目標拒絕的探測(401/403/429:Proxy 已轉送,但目的地拒絕此出口 IP)能像已提供服務的探測一樣,重設 Proxy 的連續失敗次數。預設關閉:拒絕仍視為中性,並保留目前的連續失敗次數。無論此設定為何,5xx 仍視為無法判定,而且拒絕絕不會移除、停用或重新啟用 Proxy。", "featureFlagBatchAndFileAutoCleanupEnabledDescription": "允許自動清理程序刪除早於 OMNIROUTE_BATCH_RETENTION_DAYS 且處於最終狀態(已完成/失敗/已取消/已過期)的 Batch API 作業及其逐行檢查點,並清除已超過各自 expires_at 的上傳檔案 BLOB 內容。預設關閉:在操作員選擇啟用前,所有現有安裝都會完全比照以往保留這些資料。無論是否啟用,操作員觸發的 DELETE /api/v1/batches/delete-completed 路由都不受影響——它是獨立且無條件的公開 API 合約。", @@ -3217,6 +3216,109 @@ "cliproxyapiUpdateAvailable": "可用更新:v{current} → v{latest}", "cliproxyapiVersion": "版本" }, + "modelCatalog": { + "title": "模型與組合", + "subtitle": "瀏覽並健康測試所有提供者的模型與組合路由管線。", + "refresh": "重新整理", + "modelsTab": "模型", + "combosTab": "組合", + "catalogSections": "目錄區段", + "loading": "載入中...", + "retry": "重試", + "unableToLoad": "無法載入模型目錄。", + "unableToLoadCombos": "無法載入組合。", + "checkConnection": "請檢查連線並重試。", + "noModelsAvailable": "尚無可用模型。", + "noModelsMatch": "沒有符合這些篩選條件的模型。", + "noCombosAvailable": "尚無可用組合。", + "noCombosMatch": "沒有符合這些篩選條件的組合。", + "clearFilters": "清除篩選條件", + "searchModels": "搜尋模型", + "searchModelsPlaceholder": "依模型、提供者或功能搜尋", + "searchCombos": "搜尋組合", + "searchCombosPlaceholder": "依組合名稱、模型或描述搜尋", + "modelCountSingle": "模型", + "modelCountPlural": "模型", + "comboCountSingle": "組合", + "comboCountPlural": "組合", + "provider": "提供者", + "allProviders": "所有提供者", + "type": "類型", + "allTypes": "所有類型", + "subtype": "子類型", + "allSubtypes": "所有子類型", + "capability": "功能", + "allCapabilities": "所有功能", + "pricing": "計費方式", + "allPricing": "所有計費方式", + "freeOnly": "僅限免費", + "nonFree": "標準 / 非免費", + "providerHealth": "提供者健全狀況", + "allHealthStates": "所有健全狀態", + "healthy": "正常", + "degraded": "效能降低", + "down": "服務中斷", + "testResult": "測試結果", + "allResults": "所有結果", + "untested": "未測試", + "statusOk": "正常", + "statusSlow": "緩慢", + "statusError": "錯誤", + "minContext": "最小上下文", + "minContextPlaceholder": "例:32000", + "strategy": "策略", + "allStrategies": "所有策略", + "status": "狀態", + "allStatuses": "所有狀態", + "active": "啟用中", + "paused": "已暫停", + "minMembers": "最少成員數", + "minMembersPlaceholder": "例:1", + "maxMembers": "最多成員數", + "maxMembersPlaceholder": "例:10", + "testSelected": "測試所選項目 ({count})", + "testAllFiltered": "測試所有篩選項目 ({count})", + "cancel": "取消", + "clearResults": "清除結果", + "testing": "測試中...", + "rateLimited": "達到速率限制", + "quotaExceeded": "超出配額", + "timeout": "逾時", + "otherError": "錯誤", + "justNow": "剛剛", + "minutesAgo": "{count} 分鐘前", + "hoursAgo": "{count} 小時前", + "tableRegion": "模型目錄表格", + "combosTableRegion": "組合目錄表格", + "tableCaption": "所有提供者的模型目錄", + "combosTableCaption": "包含健全狀態測試結果的組合目錄", + "selectAllModels": "選取此頁面上的所有模型", + "selectAllCombos": "選取此頁面上的所有組合", + "selectModel": "選取模型 {name}", + "selectCombo": "選取組合 {name}", + "model": "模型", + "capabilities": "能力", + "context": "上下文", + "output": "最大輸出", + "flags": "標記", + "healthTest": "健康測試", + "actions": "操作", + "test": "測試", + "custom": "自訂", + "free": "免費", + "noFlags": "未回報價格或來源標記", + "noCapabilities": "未回報能力中繼資料", + "showingModels": "顯示第 {first}–{last} 個模型,共 {total} 個", + "showingCombos": "顯示第 {first}–{last} 個組合,共 {total} 個", + "refreshing": "正在重新整理…", + "refreshFailed": "重新整理失敗。正在顯示上次載入的目錄。", + "page": "第 {page} 頁,共 {pageCount} 頁", + "previous": "上一頁", + "next": "下一頁", + "combo": "組合", + "members": "成員", + "moreMembers": "+{count} 更多" + }, "combos": { "title": "組合", "description": "建立支援權重路由與故障回退的模型組合", diff --git a/tests/unit/dashboard/modelCatalogPage.test.tsx b/tests/unit/dashboard/modelCatalogPage.test.tsx index 61415a1b4657..061a84a758cd 100644 --- a/tests/unit/dashboard/modelCatalogPage.test.tsx +++ b/tests/unit/dashboard/modelCatalogPage.test.tsx @@ -3,10 +3,21 @@ import React, { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import enMessages from "@/i18n/messages/en.json"; + vi.mock("next-intl", () => ({ - useTranslations: () => { - const translate = (key: string) => key; - return Object.assign(translate, { has: () => false }); + useTranslations: (ns: string = "common") => { + const bag = ((enMessages as Record)[ns] || {}) as Record; + const translate = (key: string, params?: Record) => { + let str = bag[key] ?? key; + if (params) { + for (const [pKey, pVal] of Object.entries(params)) { + str = str.replace(new RegExp(`\\{${pKey}\\}`, "g"), String(pVal)); + } + } + return str; + }; + return Object.assign(translate, { has: (key: string) => key in bag }); }, })); diff --git a/tests/unit/dashboard/modelsCombosCatalog.test.tsx b/tests/unit/dashboard/modelsCombosCatalog.test.tsx index 13dec81f123f..57f8d5d94391 100644 --- a/tests/unit/dashboard/modelsCombosCatalog.test.tsx +++ b/tests/unit/dashboard/modelsCombosCatalog.test.tsx @@ -3,10 +3,21 @@ import React, { act } from "react"; import { createRoot, type Root } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import enMessages from "@/i18n/messages/en.json"; + vi.mock("next-intl", () => ({ - useTranslations: () => { - const translate = (key: string) => key; - return Object.assign(translate, { has: () => false }); + useTranslations: (ns: string = "common") => { + const bag = ((enMessages as Record)[ns] || {}) as Record; + const translate = (key: string, params?: Record) => { + let str = bag[key] ?? key; + if (params) { + for (const [pKey, pVal] of Object.entries(params)) { + str = str.replace(new RegExp(`\\{${pKey}\\}`, "g"), String(pVal)); + } + } + return str; + }; + return Object.assign(translate, { has: (key: string) => key in bag }); }, })); From a1844f7fef61f486ffa8f7a52c73f5faa310bccb Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 16:42:49 +0300 Subject: [PATCH 04/16] fix(dashboard): address catalog review findings Test runner (useCatalogTestRunner): - Abort the active bulk run and any per-row tests on unmount; no further scheduling, state updates or localStorage writes afterwards. - Load stored results in a mount effect instead of a useState initializer. - Bulk combo tests use the run's AbortSignal, so Cancel also aborts tests in flight. Only the run that still owns the runner may advance progress or reset running state, so a cancelled run's late completions cannot end or hijack the next run. - Honour stoppedEarly from /api/models/test-all: models the server never tested stay untested instead of being stored as errors. - Response mapping moved to catalogTestResponses.ts; no English fallback text is stored, the badge renders translated messages instead. Page and components: - URL filters and the active tab are applied after mount (SSR-safe); deep links and Back/Forward keep working. - Tabs extracted to CatalogTabs with Arrow/Home/End keys, roving tabindex and focus following selection. - Confirm dialog before bulk runs of more than 50 models or 20 combos; exact duplicate targets are dropped before counting and batching. - New "min max output" filter bound to the existing minOutput param. - Numeric URL params and inputs accept whole numbers >= 0 only. - Per-row Test buttons are disabled while a bulk run is active; the progress bar has an accessible name and value text; error details are available to screen readers; test time is shown as a relative age. - combo-ref steps count as combo members. Tests: fake timers and deferred promises instead of real waits; new unit suites for bulk utils, URL state and response mapping; UI coverage for unmount abort, cancel/restart, stoppedEarly, >100-model batching with at most 2 calls in flight, confirm dialog, keyboard tabs, filter URL sync, single combo test and unsafe numeric params. --- .../dashboard/models/CatalogBulkActionBar.tsx | 27 +- .../dashboard/models/CatalogTabs.tsx | 84 ++ .../dashboard/models/CatalogTestBadge.tsx | 62 +- .../dashboard/models/ComboCatalogFilters.tsx | 5 +- .../dashboard/models/ComboCatalogTable.tsx | 10 +- .../dashboard/models/ModelCatalogFilters.tsx | 20 +- .../dashboard/models/ModelCatalogTable.tsx | 9 +- .../dashboard/models/catalogBulkUtils.ts | 88 ++ .../dashboard/models/catalogTestResponses.ts | 232 +++++ .../dashboard/models/catalogUrlState.ts | 145 +++ .../dashboard/models/comboCatalogUtils.ts | 27 +- src/app/(dashboard)/dashboard/models/page.tsx | 316 +++---- .../dashboard/models/useCatalogTestRunner.ts | 539 ++++------- src/i18n/messages/en.json | 18 +- .../unit/dashboard/catalogBulkUtils.test.tsx | 131 +++ .../dashboard/catalogTestResponses.test.tsx | 158 ++++ tests/unit/dashboard/catalogUrlState.test.tsx | 146 +++ .../unit/dashboard/comboCatalogUtils.test.tsx | 38 + .../unit/dashboard/modelCatalogPage.test.tsx | 16 +- .../dashboard/modelsCombosCatalog.test.tsx | 850 ++++++++++++------ 20 files changed, 2077 insertions(+), 844 deletions(-) create mode 100644 src/app/(dashboard)/dashboard/models/CatalogTabs.tsx create mode 100644 src/app/(dashboard)/dashboard/models/catalogBulkUtils.ts create mode 100644 src/app/(dashboard)/dashboard/models/catalogTestResponses.ts create mode 100644 src/app/(dashboard)/dashboard/models/catalogUrlState.ts create mode 100644 tests/unit/dashboard/catalogBulkUtils.test.tsx create mode 100644 tests/unit/dashboard/catalogTestResponses.test.tsx create mode 100644 tests/unit/dashboard/catalogUrlState.test.tsx diff --git a/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx index 6a025cee225b..e8103a2c00c1 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogBulkActionBar.tsx @@ -14,7 +14,6 @@ export default function CatalogBulkActionBar({ onTestFiltered, onCancel, onClearResults, - entityLabel: _entityLabel = "models", }: { selectedCount: number; filteredCount: number; @@ -25,10 +24,18 @@ export default function CatalogBulkActionBar({ onTestFiltered: () => void; onCancel: () => void; onClearResults: () => void; - entityLabel?: "models" | "combos"; }) { const t = useTranslations("modelCatalog"); const percent = progress.total > 0 ? Math.round((progress.completed / progress.total) * 100) : 0; + const counts = { completed: progress.completed, total: progress.total }; + const progressText = + progress.kind === "combos" + ? t("testingProgressCombos", counts) + : t("testingProgressModels", counts); + const cancelledText = + progress.kind === "combos" + ? t("testsCancelledCombos", counts) + : t("testsCancelledModels", counts); return (
@@ -70,22 +77,30 @@ export default function CatalogBulkActionBar({ )}
- {running && ( + {running ? (
-
+
- - {progress.message || `${percent}%`} +
+ ) : ( + progress.cancelled && ( +

+ {cancelledText} +

+ ) )}
); diff --git a/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx b/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx new file mode 100644 index 000000000000..0a142f55b286 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { useRef, type KeyboardEvent } from "react"; +import type { CatalogTab } from "./catalogUrlState"; + +const TAB_ORDER: CatalogTab[] = ["models", "combos"]; + +export function catalogTabId(tab: CatalogTab): string { + return `tab-${tab}`; +} + +export function catalogPanelId(tab: CatalogTab): string { + return `panel-${tab}`; +} + +/** WAI-ARIA tabs: roving tabindex, Arrow/Home/End move selection and focus together. */ +export default function CatalogTabs({ + activeTab, + onSelect, + labels, + ariaLabel, +}: { + activeTab: CatalogTab; + onSelect: (tab: CatalogTab) => void; + labels: Record; + ariaLabel: string; +}) { + const tabRefs = useRef>>({}); + + const handleKeyDown = (event: KeyboardEvent, index: number) => { + let next: number; + switch (event.key) { + case "ArrowRight": + next = (index + 1) % TAB_ORDER.length; + break; + case "ArrowLeft": + next = (index - 1 + TAB_ORDER.length) % TAB_ORDER.length; + break; + case "Home": + next = 0; + break; + case "End": + next = TAB_ORDER.length - 1; + break; + default: + return; + } + event.preventDefault(); + const tab = TAB_ORDER[next]; + onSelect(tab); + tabRefs.current[tab]?.focus(); + }; + + return ( +
+ {TAB_ORDER.map((tab, index) => { + const selected = tab === activeTab; + return ( + + ); + })} +
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx index 239d775bd07b..3ed699b6942b 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx @@ -4,24 +4,39 @@ import { useTranslations } from "next-intl"; import { Badge } from "@/shared/components"; import type { CatalogTestResult } from "./catalogTestStorage"; +type TestAge = + | { unit: "justNow" } + | { unit: "minutes"; count: number } + | { unit: "hours"; count: number } + | { unit: "date" }; + function formatLatency(ms?: number): string { if (typeof ms !== "number" || Number.isNaN(ms)) return ""; if (ms < 1000) return `${Math.round(ms)}ms`; return `${(ms / 1000).toFixed(1)}s`; } -function formatTestTime(timestamp?: number): string { - if (!timestamp) return ""; +function formatAbsoluteTime(timestamp: number): string { try { - return new Date(timestamp).toLocaleTimeString([], { - hour: "2-digit", - minute: "2-digit", + return new Date(timestamp).toLocaleString([], { + dateStyle: "short", + timeStyle: "short", }); } catch { return ""; } } +/** Results are loaded after mount, so this only ever runs in the browser. */ +function testAge(testedAt: number, now = Date.now()): TestAge { + const minutes = Math.floor(Math.max(0, now - testedAt) / 60_000); + if (minutes < 1) return { unit: "justNow" }; + if (minutes < 60) return { unit: "minutes", count: minutes }; + const hours = Math.floor(minutes / 60); + if (hours < 24) return { unit: "hours", count: hours }; + return { unit: "date" }; +} + export default function CatalogTestBadge({ result, loading = false, @@ -63,14 +78,36 @@ export default function CatalogTestBadge({ return t("otherError"); }; + // Sanitized API text when the server sent one, otherwise a translated fallback. + const getErrorDetail = () => { + if (result.status !== "error") return undefined; + if (result.error) return result.error; + if (typeof result.statusCode === "number" && result.statusCode >= 400) { + return t("httpError", { status: result.statusCode }); + } + return t("testFailedNoDetail"); + }; + const label = getLabel(); + const errorDetail = getErrorDetail(); const latencyStr = formatLatency(result.latencyMs); - const timeStr = formatTestTime(result.testedAt); + const hasTime = typeof result.testedAt === "number" && result.testedAt > 0; + const absoluteTime = hasTime ? formatAbsoluteTime(result.testedAt) : ""; + + const getAgeLabel = () => { + if (!hasTime) return ""; + const age = testAge(result.testedAt); + if (age.unit === "justNow") return t("justNow"); + if (age.unit === "minutes") return t("minutesAgo", { count: age.count }); + if (age.unit === "hours") return t("hoursAgo", { count: age.count }); + return absoluteTime; + }; + const ageLabel = getAgeLabel(); return (
@@ -80,7 +117,16 @@ export default function CatalogTestBadge({ {latencyStr} )}
- {timeStr && {timeStr}} + {ageLabel && ( + + )} + {errorDetail && {t("errorDetail", { detail: errorDetail })}}
); } diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx index fb806522ef09..bc81072b9906 100644 --- a/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx @@ -2,6 +2,7 @@ import { useTranslations } from "next-intl"; import { Button, Input } from "@/shared/components"; +import { parseNonNegativeInt } from "./catalogUrlState"; import type { ComboCatalogFilters } from "./comboCatalogUtils"; function humanize(value: string): string { @@ -106,7 +107,7 @@ export default function ComboCatalogFiltersComponent({ value={filters.minMembers ?? ""} onChange={(e) => onChange({ - minMembers: e.target.value ? Number(e.target.value) : undefined, + minMembers: parseNonNegativeInt(e.target.value), }) } className="h-9 w-full rounded-control border border-black/10 bg-white px-2.5 text-xs text-text-main focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary dark:border-white/10 dark:bg-white/5" @@ -122,7 +123,7 @@ export default function ComboCatalogFiltersComponent({ value={filters.maxMembers ?? ""} onChange={(e) => onChange({ - maxMembers: e.target.value ? Number(e.target.value) : undefined, + maxMembers: parseNonNegativeInt(e.target.value), }) } className="h-9 w-full rounded-control border border-black/10 bg-white px-2.5 text-xs text-text-main focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary dark:border-white/10 dark:bg-white/5" diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx index cf71a825ad57..5f4fb0c188d3 100644 --- a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx @@ -71,6 +71,7 @@ export default function ComboCatalogTable({ onTestCombo, onPrevious, onNext, + bulkRunning = false, }: { rows: ComboCatalogRow[]; sortField: ComboSortField; @@ -88,6 +89,8 @@ export default function ComboCatalogTable({ onTestCombo: (comboName: string) => void; onPrevious: () => void; onNext: () => void; + /** A bulk run owns the runner; per-row tests wait until it ends. */ + bulkRunning?: boolean; }) { const t = useTranslations("modelCatalog"); const allOnPageSelected = rows.length > 0 && rows.every((row) => selectedIds.has(row.id)); @@ -214,7 +217,10 @@ export default function ComboCatalogTable({ className="inline-block max-w-[150px] truncate rounded bg-black/5 px-1.5 py-0.5 font-mono text-[10px] text-text-muted dark:bg-white/5" title={m.model} > - {m.label || m.model.split("/").pop()} + {m.label || + (m.kind === "combo-ref" + ? t("comboRefMember", { name: m.model }) + : m.model.split("/").pop())} ))} {combo.models.length > 3 && ( @@ -237,7 +243,7 @@ export default function ComboCatalogTable({
- {/* Tab Navigation */} -
- - -
+ {/* Models Tab Content */} {activeTab === "models" && (
@@ -574,7 +458,6 @@ export default function ModelCatalogPage() { onTestFiltered={handleTestAllFiltered} onCancel={cancelTest} onClearResults={clearResults} - entityLabel="models" /> {modelsLoading && models.length === 0 ? ( @@ -655,6 +538,7 @@ export default function ModelCatalogPage() { activeTestingKey={activeItemKey} onTestModel={testSingleModel} providerHealthMap={providerHealthMap} + bulkRunning={running} /> )} @@ -665,8 +549,8 @@ export default function ModelCatalogPage() { {activeTab === "combos" && (
@@ -689,7 +573,6 @@ export default function ModelCatalogPage() { onTestFiltered={handleTestAllFiltered} onCancel={cancelTest} onClearResults={clearResults} - entityLabel="combos" /> {combosLoading && combos.length === 0 ? ( @@ -756,11 +639,26 @@ export default function ModelCatalogPage() { onNext={() => setRequestedComboPage((c) => Math.min(comboPage.pageCount - 1, c + 1)) } + bulkRunning={running} /> )}
)} + + setPendingBulkRun(null)} + onConfirm={confirmPendingBulkRun} + title={t("bulkConfirmTitle")} + message={ + pendingBulkRun?.kind === "combos" + ? t("bulkConfirmCombos", { count: pendingBulkRun.targets.length }) + : t("bulkConfirmModels", { count: pendingBulkRun?.targets.length ?? 0 }) + } + confirmText={t("bulkConfirmStart")} + variant="primary" + /> ); } diff --git a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts index af28723ab181..df99c0dad4a4 100644 --- a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts +++ b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts @@ -1,413 +1,258 @@ "use client"; -import { useCallback, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { + buildModelBatches, + BULK_CONCURRENCY, + dedupeComboTargets, + dedupeModelTargets, + runWithConcurrency, + type ComboTestTarget, + type ModelTestTarget, +} from "./catalogBulkUtils"; +import { + mapBatchResponse, + mapComboResponse, + mapRequestFailure, + mapSingleModelResponse, + readJsonBody, + type BatchModelTestResponse, + type ComboTestResponse, + type SingleModelTestResponse, +} from "./catalogTestResponses"; import { - classifyError, clearCatalogTestResults, getComboTestKey, getModelTestKey, loadCatalogTestResults, - normalizeTestStatus, saveBatchTestResults, - saveSingleTestResult, type CatalogTestResult, } from "./catalogTestStorage"; -interface SingleModelTestResponse { - status?: string; - latencyMs?: number; - error?: string; - statusCode?: number; - rateLimited?: boolean; -} - -interface BatchModelTestResponse { - results?: Record< - string, - { - status: string; - latencyMs: number; - error?: string; - statusCode?: number; - rateLimited?: boolean; - isQuota?: boolean; - isTimeout?: boolean; - } - >; -} - -interface ComboTestTargetResult { - model: string; - provider?: string; - status?: string; - latencyMs?: number; - error?: string; - statusCode?: number; -} - -interface ComboTestResponse { - comboName?: string; - resolvedBy?: string | null; - results?: ComboTestTargetResult[]; - error?: string; -} +export type BulkRunKind = "models" | "combos"; export interface ProgressState { + kind: BulkRunKind; completed: number; total: number; - message: string; + cancelled: boolean; } -async function runWithConcurrency( - items: T[], - limit: number, - signal: AbortSignal, - worker: (item: T) => Promise -): Promise { - let index = 0; - const executing = new Set>(); - - while (index < items.length && !signal.aborted) { - while (executing.size < limit && index < items.length && !signal.aborted) { - const item = items[index++]; - const task: Promise = (async () => { - try { - if (!signal.aborted) { - await worker(item); - } - } finally { - executing.delete(task); - } - })(); - executing.add(task); - } - if (executing.size > 0) { - await Promise.race(executing); - } - } - await Promise.all(executing); -} +const IDLE_PROGRESS: ProgressState = { kind: "models", completed: 0, total: 0, cancelled: false }; +const JSON_HEADERS = { "Content-Type": "application/json" }; export function useCatalogTestRunner() { - const [testResults, setTestResults] = useState>(() => - loadCatalogTestResults() - ); + const [testResults, setTestResults] = useState>({}); const [running, setRunning] = useState(false); const [activeItemKey, setActiveItemKey] = useState(null); - const [progress, setProgress] = useState({ - completed: 0, - total: 0, - message: "", - }); + const [progress, setProgress] = useState(IDLE_PROGRESS); + + const mountedRef = useRef(false); + /** Controller of the bulk run that currently owns `running`/`progress`; null when idle. */ + const runControllerRef = useRef(null); + /** Controllers of per-row tests, aborted on unmount. */ + const singleControllersRef = useRef(new Set()); + + useEffect(() => { + mountedRef.current = true; + const runRef = runControllerRef; + const singleControllers = singleControllersRef.current; + // Stored results only exist in the browser, so load them after mount (the pattern + // DashboardLayout uses for its sidebar state) to keep the first render equal to the SSR HTML. + const timer = window.setTimeout(() => { + if (mountedRef.current) setTestResults(loadCatalogTestResults()); + }, 0); + return () => { + mountedRef.current = false; + window.clearTimeout(timer); + runRef.current?.abort(); + runRef.current = null; + for (const controller of singleControllers) controller.abort(); + singleControllers.clear(); + }; + }, []); - const abortControllerRef = useRef(null); + /** Store results unless the owning request was cancelled or the page is gone. */ + const persist = useCallback((results: CatalogTestResult[], signal: AbortSignal) => { + if (!mountedRef.current || signal.aborted || results.length === 0) return; + setTestResults({ ...saveBatchTestResults(results) }); + }, []); - const cancelTest = useCallback(() => { - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - abortControllerRef.current = null; + const releaseActiveKey = useCallback((key: string, signal: AbortSignal) => { + if (!mountedRef.current || signal.aborted) return; + setActiveItemKey((current) => (current === key ? null : current)); + }, []); + + const withSingleController = useCallback(async (work: (signal: AbortSignal) => Promise) => { + const controller = new AbortController(); + singleControllersRef.current.add(controller); + try { + await work(controller.signal); + } finally { + singleControllersRef.current.delete(controller); } - setRunning(false); - setActiveItemKey(null); - setProgress((prev) => ({ - ...prev, - message: "Cancelled", - })); }, []); - const testSingleModel = useCallback( - async (providerId: string, modelId: string): Promise => { - const key = getModelTestKey(providerId, modelId); + const runComboTest = useCallback( + async (comboName: string, signal: AbortSignal) => { + const key = getComboTestKey(comboName); setActiveItemKey(key); - - const controller = new AbortController(); try { - const res = await fetch("/api/models/test", { + const res = await fetch("/api/combos/test", { method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ providerId, modelId }), - signal: controller.signal, + headers: JSON_HEADERS, + body: JSON.stringify({ comboName }), + signal, }); - - const data: unknown = await res.json().catch(() => null); - const json = ( - typeof data === "object" && data !== null ? data : {} - ) as SingleModelTestResponse; - - const status = normalizeTestStatus( - typeof json.status === "string" ? json.status : res.ok ? "ok" : "error", - typeof json.latencyMs === "number" ? json.latencyMs : undefined - ); - - const errorClass = classifyError( - json.error, - typeof json.statusCode === "number" ? json.statusCode : res.status, - { rateLimited: json.rateLimited } + const body = await readJsonBody(res); + persist([mapComboResponse(comboName, res, body, Date.now())], signal); + } catch (failure) { + persist( + [mapRequestFailure({ targetType: "combo", comboName }, failure, Date.now())], + signal ); - - const result: CatalogTestResult = { - id: key, - targetType: "model", - providerId, - modelId, - status, - latencyMs: json.latencyMs, - testedAt: Date.now(), - error: json.error, - errorClass, - statusCode: json.statusCode ?? res.status, - }; - - const updated = saveSingleTestResult(result); - setTestResults({ ...updated }); - return result; - } catch (err) { - const errorText = err instanceof Error ? err.message : String(err); - const result: CatalogTestResult = { - id: key, - targetType: "model", - providerId, - modelId, - status: "error", - testedAt: Date.now(), - error: errorText, - errorClass: classifyError(errorText), - }; - const updated = saveSingleTestResult(result); - setTestResults({ ...updated }); - return result; } finally { - setActiveItemKey((current) => (current === key ? null : current)); + releaseActiveKey(key, signal); } }, - [] + [persist, releaseActiveKey] ); - const testSingleCombo = useCallback(async (comboName: string): Promise => { - const key = getComboTestKey(comboName); - setActiveItemKey(key); - - const controller = new AbortController(); - try { - const res = await fetch("/api/combos/test", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ comboName }), - signal: controller.signal, - }); - - const data: unknown = await res.json().catch(() => null); - const json = (typeof data === "object" && data !== null ? data : {}) as ComboTestResponse; + const testSingleModel = useCallback( + (providerId: string, modelId: string) => + withSingleController(async (signal) => { + const key = getModelTestKey(providerId, modelId); + setActiveItemKey(key); + try { + const res = await fetch("/api/models/test", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ providerId, modelId }), + signal, + }); + const body = await readJsonBody(res); + persist([mapSingleModelResponse(providerId, modelId, res, body, Date.now())], signal); + } catch (failure) { + persist( + [mapRequestFailure({ targetType: "model", providerId, modelId }, failure, Date.now())], + signal + ); + } finally { + releaseActiveKey(key, signal); + } + }), + [persist, releaseActiveKey, withSingleController] + ); - const okResult = json.results?.find((r) => r.status === "ok"); - const status = - res.ok && (json.resolvedBy || okResult) - ? normalizeTestStatus("ok", okResult?.latencyMs) - : "error"; + const testSingleCombo = useCallback( + (comboName: string) => withSingleController((signal) => runComboTest(comboName, signal)), + [runComboTest, withSingleController] + ); - const lastError = - json.results?.find((r) => r.error)?.error || - json.error || - (status === "error" ? "Combo test failed" : undefined); - const latencyMs = okResult?.latencyMs ?? json.results?.[0]?.latencyMs; - const statusCode = okResult?.statusCode ?? json.results?.[0]?.statusCode ?? res.status; + const startRun = useCallback((kind: BulkRunKind, total: number) => { + runControllerRef.current?.abort(); + const controller = new AbortController(); + runControllerRef.current = controller; + setRunning(true); + setProgress({ kind, completed: 0, total, cancelled: false }); + return controller; + }, []); - const result: CatalogTestResult = { - id: key, - targetType: "combo", - comboName, - status, - latencyMs, - testedAt: Date.now(), - error: lastError, - errorClass: classifyError(lastError, statusCode), - statusCode, - }; + /** Only the run that still owns the runner may move the progress bar or end the run. */ + const advanceRun = useCallback((controller: AbortController, count: number) => { + if (!mountedRef.current || runControllerRef.current !== controller) return; + setProgress((current) => ({ + ...current, + completed: Math.min(current.completed + count, current.total), + })); + }, []); - const updated = saveSingleTestResult(result); - setTestResults({ ...updated }); - return result; - } catch (err) { - const errorText = err instanceof Error ? err.message : String(err); - const result: CatalogTestResult = { - id: key, - targetType: "combo", - comboName, - status: "error", - testedAt: Date.now(), - error: errorText, - errorClass: classifyError(errorText), - }; - const updated = saveSingleTestResult(result); - setTestResults({ ...updated }); - return result; - } finally { - setActiveItemKey((current) => (current === key ? null : current)); - } + const finishRun = useCallback((controller: AbortController) => { + if (runControllerRef.current !== controller) return; + runControllerRef.current = null; + if (mountedRef.current) setRunning(false); }, []); const testBulkModels = useCallback( - async (models: Array<{ providerId: string; modelId: string }>) => { - if (models.length === 0) return; - - const controller = new AbortController(); - abortControllerRef.current = controller; - setRunning(true); - - const byProvider = new Map(); - for (const m of models) { - const list = byProvider.get(m.providerId) || []; - list.push(m.modelId); - byProvider.set(m.providerId, list); - } - - const batches: Array<{ providerId: string; modelIds: string[] }> = []; - for (const [providerId, modelIds] of byProvider.entries()) { - for (let i = 0; i < modelIds.length; i += 100) { - batches.push({ providerId, modelIds: modelIds.slice(i, i + 100) }); - } - } - - const totalModels = models.length; - let completedCount = 0; - setProgress({ - completed: 0, - total: totalModels, - message: `Testing 0 of ${totalModels} models...`, - }); - + async (targets: ModelTestTarget[]) => { + const unique = dedupeModelTargets(targets); + if (unique.length === 0) return; + const controller = startRun("models", unique.length); + const { signal } = controller; try { - await runWithConcurrency(batches, 2, controller.signal, async (batch) => { - if (controller.signal.aborted) return; - - try { - const res = await fetch("/api/models/test-all", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - providerId: batch.providerId, - modelIds: batch.modelIds, - respectRateLimit: true, - }), - signal: controller.signal, - }); - - const data: unknown = await res.json().catch(() => null); - const json = ( - typeof data === "object" && data !== null ? data : {} - ) as BatchModelTestResponse; - - const mappedResults: CatalogTestResult[] = []; - const resultsRecord = json.results ?? {}; - - for (const modelId of batch.modelIds) { - const entry = resultsRecord[modelId]; - if (entry) { - mappedResults.push({ - id: getModelTestKey(batch.providerId, modelId), - targetType: "model", + await runWithConcurrency( + buildModelBatches(unique), + BULK_CONCURRENCY, + signal, + async (batch) => { + try { + const res = await fetch("/api/models/test-all", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ providerId: batch.providerId, - modelId, - status: normalizeTestStatus(entry.status, entry.latencyMs), - latencyMs: entry.latencyMs, - testedAt: Date.now(), - error: entry.error, - errorClass: classifyError(entry.error, entry.statusCode, { - rateLimited: entry.rateLimited, - isQuota: entry.isQuota, - isTimeout: entry.isTimeout, - }), - statusCode: entry.statusCode, - }); - } else { - mappedResults.push({ - id: getModelTestKey(batch.providerId, modelId), - targetType: "model", - providerId: batch.providerId, - modelId, - status: "error", - testedAt: Date.now(), - error: res.ok ? "No test result reported" : `HTTP ${res.status}`, - errorClass: classifyError(undefined, res.status), - statusCode: res.status, - }); - } - } - - const updated = saveBatchTestResults(mappedResults); - setTestResults({ ...updated }); - } catch (batchErr) { - if (!controller.signal.aborted) { - const errText = batchErr instanceof Error ? batchErr.message : String(batchErr); - const failedResults = batch.modelIds.map((modelId) => ({ - id: getModelTestKey(batch.providerId, modelId), - targetType: "model" as const, - providerId: batch.providerId, - modelId, - status: "error" as const, - testedAt: Date.now(), - error: errText, - errorClass: classifyError(errText), - })); - const updated = saveBatchTestResults(failedResults); - setTestResults({ ...updated }); + modelIds: batch.modelIds, + respectRateLimit: true, + }), + signal, + }); + const body = await readJsonBody(res); + persist(mapBatchResponse(batch, res, body, Date.now()), signal); + } catch (failure) { + const testedAt = Date.now(); + persist( + batch.modelIds.map((modelId) => + mapRequestFailure( + { targetType: "model", providerId: batch.providerId, modelId }, + failure, + testedAt + ) + ), + signal + ); + } finally { + advanceRun(controller, batch.modelIds.length); } - } finally { - completedCount += batch.modelIds.length; - setProgress({ - completed: Math.min(completedCount, totalModels), - total: totalModels, - message: `Testing ${Math.min(completedCount, totalModels)} of ${totalModels} models...`, - }); } - }); + ); } finally { - setRunning(false); - abortControllerRef.current = null; + finishRun(controller); } }, - [] + [advanceRun, finishRun, persist, startRun] ); const testBulkCombos = useCallback( - async (combos: Array<{ comboName: string }>) => { - if (combos.length === 0) return; - - const controller = new AbortController(); - abortControllerRef.current = controller; - setRunning(true); - - const totalCombos = combos.length; - let completedCount = 0; - setProgress({ - completed: 0, - total: totalCombos, - message: `Testing 0 of ${totalCombos} combos...`, - }); - + async (targets: ComboTestTarget[]) => { + const unique = dedupeComboTargets(targets); + if (unique.length === 0) return; + const controller = startRun("combos", unique.length); try { - await runWithConcurrency(combos, 2, controller.signal, async (item) => { - if (controller.signal.aborted) return; - + await runWithConcurrency(unique, BULK_CONCURRENCY, controller.signal, async (target) => { try { - await testSingleCombo(item.comboName); + // The run's signal, so Cancel also aborts combo tests already in flight. + await runComboTest(target.comboName, controller.signal); } finally { - completedCount += 1; - setProgress({ - completed: Math.min(completedCount, totalCombos), - total: totalCombos, - message: `Testing ${Math.min(completedCount, totalCombos)} of ${totalCombos} combos...`, - }); + advanceRun(controller, 1); } }); } finally { - setRunning(false); - abortControllerRef.current = null; + finishRun(controller); } }, - [testSingleCombo] + [advanceRun, finishRun, runComboTest, startRun] ); + const cancelTest = useCallback(() => { + const controller = runControllerRef.current; + if (!controller) return; + runControllerRef.current = null; + controller.abort(); + setRunning(false); + setActiveItemKey(null); + setProgress((current) => ({ ...current, cancelled: true })); + }, []); + const clearResults = useCallback(() => { clearCatalogTestResults(); setTestResults({}); diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index ce3c1de396fb..c6f5e58557c1 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -3318,7 +3318,23 @@ "next": "Next", "combo": "Combo", "members": "Members", - "moreMembers": "+{count} more" + "moreMembers": "+{count} more", + "minMaxOutput": "Min max output", + "minMaxOutputPlaceholder": "e.g. 4096", + "bulkTestProgress": "Bulk test progress", + "testingProgressModels": "Testing {completed} of {total} models…", + "testingProgressCombos": "Testing {completed} of {total} combos…", + "testsCancelledModels": "Tests cancelled after {completed} of {total} models", + "testsCancelledCombos": "Tests cancelled after {completed} of {total} combos", + "bulkConfirmTitle": "Start bulk test?", + "bulkConfirmModels": "This sends {count} model tests to your providers and may use quota. Continue?", + "bulkConfirmCombos": "This runs {count} combo tests and may use provider quota. Continue?", + "bulkConfirmStart": "Start tests", + "errorDetail": "Error details: {detail}", + "httpError": "Request failed with HTTP {status}", + "testFailedNoDetail": "Test failed without an error message", + "additionalCapabilities": "Additional capabilities: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combos", diff --git a/tests/unit/dashboard/catalogBulkUtils.test.tsx b/tests/unit/dashboard/catalogBulkUtils.test.tsx new file mode 100644 index 000000000000..07c01a40a44b --- /dev/null +++ b/tests/unit/dashboard/catalogBulkUtils.test.tsx @@ -0,0 +1,131 @@ +import { describe, expect, it } from "vitest"; +import { + buildModelBatches, + dedupeComboTargets, + dedupeModelTargets, + runWithConcurrency, +} from "@/app/(dashboard)/dashboard/models/catalogBulkUtils"; + +function deferred() { + let resolve: () => void = () => undefined; + const promise = new Promise((resolvePromise) => { + resolve = resolvePromise; + }); + return { promise, resolve }; +} + +async function settle() { + for (let index = 0; index < 5; index += 1) await Promise.resolve(); +} + +describe("dedupeModelTargets", () => { + it("drops exact (providerId, modelId) duplicates and keeps first-seen order", () => { + expect( + dedupeModelTargets([ + { providerId: "alpha", modelId: "chat" }, + { providerId: "beta", modelId: "chat" }, + { providerId: "alpha", modelId: "chat" }, + { providerId: "alpha", modelId: "embed" }, + ]) + ).toEqual([ + { providerId: "alpha", modelId: "chat" }, + { providerId: "beta", modelId: "chat" }, + { providerId: "alpha", modelId: "embed" }, + ]); + }); + + it("does not merge pairs that only collide when joined with a separator", () => { + expect( + dedupeModelTargets([ + { providerId: "a:b", modelId: "c" }, + { providerId: "a", modelId: "b:c" }, + ]) + ).toHaveLength(2); + }); +}); + +describe("dedupeComboTargets", () => { + it("drops duplicate combo names", () => { + expect( + dedupeComboTargets([{ comboName: "one" }, { comboName: "two" }, { comboName: "one" }]) + ).toEqual([{ comboName: "one" }, { comboName: "two" }]); + }); +}); + +describe("buildModelBatches", () => { + it("groups by provider and splits each provider into chunks of at most 100 ids", () => { + const targets = [ + ...Array.from({ length: 230 }, (_, index) => ({ providerId: "big", modelId: `m${index}` })), + { providerId: "small", modelId: "only" }, + ]; + const batches = buildModelBatches(targets); + expect(batches.map((batch) => [batch.providerId, batch.modelIds.length])).toEqual([ + ["big", 100], + ["big", 100], + ["big", 30], + ["small", 1], + ]); + expect(batches[2].modelIds[0]).toBe("m200"); + }); + + it("honours a custom batch size", () => { + const batches = buildModelBatches( + [ + { providerId: "p", modelId: "a" }, + { providerId: "p", modelId: "b" }, + { providerId: "p", modelId: "c" }, + ], + 2 + ); + expect(batches.map((batch) => batch.modelIds)).toEqual([["a", "b"], ["c"]]); + }); +}); + +describe("runWithConcurrency", () => { + it("never runs more than the limit at once and processes every item", async () => { + const gates = [deferred(), deferred(), deferred(), deferred()]; + const started: number[] = []; + let inFlight = 0; + let maxInFlight = 0; + const controller = new AbortController(); + + const run = runWithConcurrency([0, 1, 2, 3], 2, controller.signal, async (item) => { + started.push(item); + inFlight += 1; + maxInFlight = Math.max(maxInFlight, inFlight); + await gates[item].promise; + inFlight -= 1; + }); + + await settle(); + expect(started).toEqual([0, 1]); + gates[1].resolve(); + await settle(); + expect(started).toEqual([0, 1, 2]); + gates[0].resolve(); + gates[2].resolve(); + gates[3].resolve(); + await run; + + expect(started).toEqual([0, 1, 2, 3]); + expect(maxInFlight).toBe(2); + }); + + it("stops scheduling new items once the signal aborts", async () => { + const gates = [deferred(), deferred(), deferred()]; + const started: number[] = []; + const controller = new AbortController(); + + const run = runWithConcurrency([0, 1, 2], 1, controller.signal, async (item) => { + started.push(item); + await gates[item].promise; + }); + + await settle(); + controller.abort(); + gates[0].resolve(); + await run; + + expect(started).toEqual([0]); + }); +}); diff --git a/tests/unit/dashboard/catalogTestResponses.test.tsx b/tests/unit/dashboard/catalogTestResponses.test.tsx new file mode 100644 index 000000000000..d8e16e589008 --- /dev/null +++ b/tests/unit/dashboard/catalogTestResponses.test.tsx @@ -0,0 +1,158 @@ +import { describe, expect, it } from "vitest"; +import { + mapBatchResponse, + mapComboResponse, + mapRequestFailure, + mapSingleModelResponse, +} from "@/app/(dashboard)/dashboard/models/catalogTestResponses"; + +const OK = { ok: true, status: 200 }; +const TESTED_AT = 1_000; + +describe("mapBatchResponse", () => { + const batch = { providerId: "alpha", modelIds: ["a", "b", "c"] }; + + it("stores only the models the server reported when it stopped early", () => { + const results = mapBatchResponse( + batch, + OK, + { + results: { + a: { status: "ok", latencyMs: 120 }, + b: { status: "error", latencyMs: 30, rateLimited: true, statusCode: 429 }, + }, + stoppedEarly: true, + stopReason: "consecutive_rate_limits", + }, + TESTED_AT + ); + + expect(results.map((result) => [result.modelId, result.status, result.errorClass])).toEqual([ + ["a", "ok", undefined], + ["b", "error", "rate-limited"], + ]); + expect(results.some((result) => result.modelId === "c")).toBe(false); + }); + + it("marks every model as failed with the API error text when the request fails", () => { + const results = mapBatchResponse( + batch, + { ok: false, status: 400 }, + { error: { message: "Invalid request" } }, + TESTED_AT + ); + expect(results).toHaveLength(3); + expect(results[0]).toMatchObject({ + id: "model:alpha:a", + status: "error", + error: "Invalid request", + errorClass: "other", + statusCode: 400, + testedAt: TESTED_AT, + }); + }); + + it("stores no English fallback text when a failed request has no error message", () => { + const [first] = mapBatchResponse(batch, { ok: false, status: 503 }, {}, TESTED_AT); + expect(first.error).toBeUndefined(); + expect(first.statusCode).toBe(503); + expect(first.errorClass).toBe("other"); + }); +}); + +describe("mapSingleModelResponse", () => { + it("maps ok and slow results without an error class", () => { + expect( + mapSingleModelResponse("alpha", "chat", OK, { status: "ok", latencyMs: 90 }, TESTED_AT) + ).toMatchObject({ status: "ok", latencyMs: 90, errorClass: undefined, statusCode: 200 }); + expect( + mapSingleModelResponse("alpha", "chat", OK, { status: "ok", latencyMs: 6_000 }, TESTED_AT) + .status + ).toBe("slow"); + }); + + it("classifies failures and keeps the sanitized API error", () => { + expect( + mapSingleModelResponse( + "alpha", + "chat", + { ok: false, status: 429 }, + { status: "error", error: "Too many requests", rateLimited: true }, + TESTED_AT + ) + ).toMatchObject({ + status: "error", + error: "Too many requests", + errorClass: "rate-limited", + statusCode: 429, + }); + }); +}); + +describe("mapComboResponse", () => { + it("maps a resolved combo to ok with the resolving target latency", () => { + expect( + mapComboResponse( + "fast", + OK, + { + resolvedBy: "alpha/chat", + results: [ + { model: "beta/x", status: "error", error: "Timeout", latencyMs: 10 }, + { model: "alpha/chat", status: "ok", latencyMs: 210, statusCode: 200 }, + ], + }, + TESTED_AT + ) + ).toMatchObject({ + id: "combo:fast", + targetType: "combo", + status: "ok", + latencyMs: 210, + errorClass: undefined, + }); + }); + + it("maps a failed combo without inventing English error text", () => { + const result = mapComboResponse( + "fast", + OK, + { resolvedBy: null, results: [{ model: "alpha/chat", status: "error", statusCode: 500 }] }, + TESTED_AT + ); + expect(result.status).toBe("error"); + expect(result.error).toBeUndefined(); + expect(result.errorClass).toBe("other"); + expect(result.statusCode).toBe(500); + }); + + it("keeps the API error text when the combo request fails", () => { + const result = mapComboResponse( + "fast", + { ok: false, status: 404 }, + { error: "Combo not found" }, + TESTED_AT + ); + expect(result).toMatchObject({ status: "error", error: "Combo not found", statusCode: 404 }); + }); +}); + +describe("mapRequestFailure", () => { + it("records a network failure for a model or combo target", () => { + expect( + mapRequestFailure( + { targetType: "model", providerId: "alpha", modelId: "chat" }, + new TypeError("Failed to fetch"), + TESTED_AT + ) + ).toMatchObject({ + id: "model:alpha:chat", + status: "error", + error: "Failed to fetch", + errorClass: "other", + }); + expect( + mapRequestFailure({ targetType: "combo", comboName: "fast" }, "boom", TESTED_AT) + ).toMatchObject({ id: "combo:fast", targetType: "combo", error: "boom" }); + }); +}); diff --git a/tests/unit/dashboard/catalogUrlState.test.tsx b/tests/unit/dashboard/catalogUrlState.test.tsx new file mode 100644 index 000000000000..404f3caabb04 --- /dev/null +++ b/tests/unit/dashboard/catalogUrlState.test.tsx @@ -0,0 +1,146 @@ +import { describe, expect, it } from "vitest"; +import { + buildCatalogSearchParams, + DEFAULT_COMBO_FILTERS, + DEFAULT_MODEL_FILTERS, + hasActiveComboFilters, + hasActiveModelFilters, + parseCatalogTab, + parseComboFilters, + parseModelFilters, + parseNonNegativeInt, +} from "@/app/(dashboard)/dashboard/models/catalogUrlState"; + +describe("parseNonNegativeInt", () => { + it("accepts non-negative whole numbers", () => { + expect(parseNonNegativeInt("0")).toBe(0); + expect(parseNonNegativeInt("32000")).toBe(32000); + expect(parseNonNegativeInt(" 42 ")).toBe(42); + }); + + it("rejects empty, NaN, negative, fractional, exponent and unsafe values", () => { + for (const raw of [ + null, + undefined, + "", + " ", + "abc", + "NaN", + "-5", + "1.5", + "1e3", + "9".repeat(20), + ]) { + expect(parseNonNegativeInt(raw)).toBeUndefined(); + } + }); +}); + +describe("parseCatalogTab", () => { + it("defaults to models for anything but combos", () => { + expect(parseCatalogTab(new URLSearchParams("tab=combos"))).toBe("combos"); + expect(parseCatalogTab(new URLSearchParams("tab=other"))).toBe("models"); + expect(parseCatalogTab(new URLSearchParams(""))).toBe("models"); + }); +}); + +describe("parseModelFilters", () => { + it("returns the defaults for an empty query", () => { + expect(parseModelFilters(new URLSearchParams(""))).toEqual(DEFAULT_MODEL_FILTERS); + }); + + it("reads every model filter param", () => { + expect( + parseModelFilters( + new URLSearchParams( + "query=chat&provider=alpha&type=chat&subtype=code&capability=tools&pricing=free&health=down&testResult=slow&minContext=8000&minOutput=4096" + ) + ) + ).toEqual({ + query: "chat", + providerId: "alpha", + type: "chat", + subtype: "code", + capability: "tools", + pricing: "free", + providerHealth: "down", + testResult: "slow", + minContextLength: 8000, + minMaxOutputTokens: 4096, + }); + }); + + it("drops invalid numeric and enumerated values instead of filtering on them", () => { + const filters = parseModelFilters( + new URLSearchParams("minContext=abc&minOutput=-5&pricing=cheap&health=?&testResult=maybe") + ); + expect(filters).toEqual(DEFAULT_MODEL_FILTERS); + expect(hasActiveModelFilters(filters)).toBe(false); + }); +}); + +describe("parseComboFilters", () => { + it("reads combo params and ignores invalid member counts", () => { + expect( + parseComboFilters( + new URLSearchParams( + "tab=combos&query=fast&strategy=priority&status=paused&testResult=error&minMembers=2&maxMembers=-1" + ) + ) + ).toEqual({ + query: "fast", + strategy: "priority", + status: "paused", + testResult: "error", + minMembers: 2, + maxMembers: undefined, + }); + }); + + it("only reads the shared query/testResult params when the combos tab is active", () => { + expect(parseComboFilters(new URLSearchParams("query=fast&testResult=ok"))).toEqual( + DEFAULT_COMBO_FILTERS + ); + expect(parseComboFilters(new URLSearchParams("cQuery=deep&cTestResult=ok")).query).toBe("deep"); + }); + + it("drops an unknown status", () => { + expect(parseComboFilters(new URLSearchParams("tab=combos&status=zombie")).status).toBe("all"); + }); +}); + +describe("buildCatalogSearchParams", () => { + it("round-trips model filters", () => { + const filters = { + ...DEFAULT_MODEL_FILTERS, + query: "vision", + providerId: "beta", + minMaxOutputTokens: 8000, + }; + const params = buildCatalogSearchParams("models", filters, DEFAULT_COMBO_FILTERS); + expect(params.toString()).toBe("query=vision&provider=beta&minOutput=8000"); + expect(parseModelFilters(params)).toEqual(filters); + }); + + it("round-trips combo filters with the tab param", () => { + const filters = { ...DEFAULT_COMBO_FILTERS, strategy: "fusion", minMembers: 2, maxMembers: 5 }; + const params = buildCatalogSearchParams("combos", DEFAULT_MODEL_FILTERS, filters); + expect(params.get("tab")).toBe("combos"); + expect(parseComboFilters(params)).toEqual(filters); + }); + + it("writes nothing for default filters on the models tab", () => { + expect( + buildCatalogSearchParams("models", DEFAULT_MODEL_FILTERS, DEFAULT_COMBO_FILTERS).toString() + ).toBe(""); + }); +}); + +describe("hasActive*Filters", () => { + it("detects any non-default filter", () => { + expect(hasActiveModelFilters(DEFAULT_MODEL_FILTERS)).toBe(false); + expect(hasActiveModelFilters({ ...DEFAULT_MODEL_FILTERS, minMaxOutputTokens: 0 })).toBe(true); + expect(hasActiveComboFilters(DEFAULT_COMBO_FILTERS)).toBe(false); + expect(hasActiveComboFilters({ ...DEFAULT_COMBO_FILTERS, maxMembers: 3 })).toBe(true); + }); +}); diff --git a/tests/unit/dashboard/comboCatalogUtils.test.tsx b/tests/unit/dashboard/comboCatalogUtils.test.tsx index 84d510cbc063..0ab30c53a31c 100644 --- a/tests/unit/dashboard/comboCatalogUtils.test.tsx +++ b/tests/unit/dashboard/comboCatalogUtils.test.tsx @@ -36,6 +36,7 @@ const sampleCombos: ComboCatalogRow[] = [ { id: "combo-3", name: "gamma-fusion", + displayName: "gamma-fusion", strategy: "fusion", description: "Parallel judge panel", models: [{ model: "m1" }], @@ -80,6 +81,43 @@ describe("flattenCombos", () => { expect(result[1].memberCount).toBe(2); }); + it("counts combo-ref steps as members for nested combos", () => { + const rawCombos = [ + { + id: "c-nested", + name: "nested-combo", + strategy: "pipeline", + models: [ + { model: "direct-model-1" }, + { kind: "combo-ref", comboName: "sub-combo-1" }, + { kind: "combo-ref", comboName: "sub-combo-2" }, + ], + isActive: true, + }, + ]; + + const result = flattenCombos(rawCombos); + expect(result).toHaveLength(1); + expect(result[0].memberCount).toBe(3); + expect(result[0].models[1]).toEqual({ model: "sub-combo-1", kind: "combo-ref" }); + expect(result[0].models[2]).toEqual({ model: "sub-combo-2", kind: "combo-ref" }); + + const filters = { query: "", strategy: "all", status: "all", testResult: "all" }; + expect(filterCatalogCombos(result, { ...filters, minMembers: 3 })).toEqual(result); + expect(filterCatalogCombos(result, { ...filters, maxMembers: 2 })).toEqual([]); + }); + + it("keeps a combo-ref label when the step provides one", () => { + const [row] = flattenCombos([ + { + id: "c-labelled", + name: "labelled", + models: [{ kind: "combo-ref", comboName: "inner", label: "Inner fallback" }], + }, + ]); + expect(row.models).toEqual([{ model: "inner", kind: "combo-ref", label: "Inner fallback" }]); + }); + it("handles empty or invalid inputs", () => { expect(flattenCombos(null)).toEqual([]); expect(flattenCombos(undefined)).toEqual([]); diff --git a/tests/unit/dashboard/modelCatalogPage.test.tsx b/tests/unit/dashboard/modelCatalogPage.test.tsx index 061a84a758cd..ffea51883507 100644 --- a/tests/unit/dashboard/modelCatalogPage.test.tsx +++ b/tests/unit/dashboard/modelCatalogPage.test.tsx @@ -28,21 +28,31 @@ describe("ModelCatalogPage", () => { let root: Root; beforeEach(() => { + vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout", "setInterval", "clearInterval"] }); ( globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean } ).IS_REACT_ACT_ENVIRONMENT = true; container = document.createElement("div"); document.body.appendChild(container); root = createRoot(container); + window.history.replaceState(null, "", "/dashboard/models"); }); afterEach(() => { act(() => root.unmount()); container.remove(); + vi.useRealTimers(); vi.restoreAllMocks(); vi.unstubAllGlobals(); }); + /** Mount effects are deferred with setTimeout; run them and settle the fetch promises. */ + async function flush() { + await act(async () => { + await vi.runAllTimersAsync(); + }); + } + it("loads all provider models and only labels flags the API actually reports", async () => { vi.stubGlobal( "fetch", @@ -81,7 +91,7 @@ describe("ModelCatalogPage", () => { act(() => { root.render(); }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 0))); + await flush(); expect(fetch).toHaveBeenCalledWith("/api/models/catalog", expect.anything()); expect(container.textContent).toContain("Alpha Labs"); @@ -105,7 +115,7 @@ describe("ModelCatalogPage", () => { providerFilter.value = "all"; providerFilter.dispatchEvent(new Event("change", { bubbles: true })); }); - const modelSort = [...container.querySelectorAll("th button")].find( + const modelSort = [...container.querySelectorAll("th button")].find( (button) => button.textContent === "Model" )!; act(() => modelSort.click()); @@ -120,7 +130,7 @@ describe("ModelCatalogPage", () => { act(() => { root.render(); }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 0))); + await flush(); expect(container.querySelector('[role="alert"]')?.textContent).toContain( "Unable to load the model catalog." diff --git a/tests/unit/dashboard/modelsCombosCatalog.test.tsx b/tests/unit/dashboard/modelsCombosCatalog.test.tsx index 57f8d5d94391..629a93051d79 100644 --- a/tests/unit/dashboard/modelsCombosCatalog.test.tsx +++ b/tests/unit/dashboard/modelsCombosCatalog.test.tsx @@ -1,6 +1,7 @@ // @vitest-environment jsdom import React, { act } from "react"; import { createRoot, type Root } from "react-dom/client"; +import { renderToString } from "react-dom/server"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import enMessages from "@/i18n/messages/en.json"; @@ -24,14 +25,197 @@ vi.mock("next-intl", () => ({ import ModelCatalogPage from "@/app/(dashboard)/dashboard/models/page"; import { CATALOG_TEST_RESULTS_KEY, + getComboTestKey, getModelTestKey, } from "@/app/(dashboard)/dashboard/models/catalogTestStorage"; +type RouteHandler = (init?: RequestInit) => Promise; + +interface CatalogModelFixture { + id: string; + name: string; + type: string; + [key: string]: unknown; +} + +type CatalogFixture = Record; + +interface TestAllBody { + providerId: string; + modelIds: string[]; + respectRateLimit: boolean; +} + +interface PendingCall
{ + body: TBody; + signal: AbortSignal | null | undefined; + resolve: () => void; +} + +interface Deferred { + promise: Promise; + resolve: (value: T) => void; +} + +function deferred(): Deferred { + let resolve: (value: T) => void = () => undefined; + const promise = new Promise((resolvePromise) => { + resolve = resolvePromise; + }); + return { promise, resolve }; +} + +function jsonResponse(body: unknown, status = 200): Response { + return { + ok: status >= 200 && status < 300, + status, + json: async () => body, + } as unknown as Response; +} + +const DEFAULT_CATALOG: CatalogFixture = { + alpha: { + provider: "Alpha Labs", + models: [ + { + id: "alpha-chat", + name: "Alpha Chat", + type: "chat", + subtype: "general", + free: true, + context_length: 128_000, + max_output_tokens: 16_384, + capabilities: { tools: true, vision: true }, + }, + { id: "alpha-embed", name: "Alpha Embed", type: "embedding", context_length: 8_192 }, + ], + }, + beta: { + provider: "Beta AI", + models: [ + { + id: "beta-coder", + name: "Beta Coder", + type: "chat", + subtype: "code", + max_output_tokens: 4_096, + capabilities: { reasoning: true }, + }, + ], + }, +}; + +const DEFAULT_COMBOS = [ + { + id: "c-1", + name: "combo-1", + displayName: "First Combo", + strategy: "priority", + description: "Fallback chain", + models: [{ model: "alpha/alpha-chat" }, { model: "beta/beta-coder" }], + isActive: true, + }, + { + id: "c-2", + name: "combo-2", + displayName: "Second Combo", + strategy: "round-robin", + models: [{ model: "alpha/alpha-embed" }], + isActive: false, + }, +]; + +function okResultsFor(body: TestAllBody, latencyMs = 140) { + return Object.fromEntries(body.modelIds.map((id) => [id, { status: "ok", latencyMs }])); +} + +function installFetch( + options: { + catalog?: CatalogFixture; + combos?: unknown[]; + testAll?: RouteHandler; + modelTest?: RouteHandler; + comboTest?: RouteHandler; + } = {} +) { + const fetchMock = vi.fn((input: RequestInfo | URL, init?: RequestInit) => { + const url = String(input); + if (url.includes("/api/models/catalog")) { + return Promise.resolve(jsonResponse({ catalog: options.catalog ?? DEFAULT_CATALOG })); + } + if (url.includes("/api/providers/health-matrix")) { + return Promise.resolve( + jsonResponse({ + providers: [ + { provider: "alpha", state: "healthy" }, + { provider: "beta", state: "degraded" }, + ], + }) + ); + } + if (url.includes("/api/models/test-all")) { + if (options.testAll) return options.testAll(init); + const body = JSON.parse(String(init?.body)) as TestAllBody; + return Promise.resolve(jsonResponse({ results: okResultsFor(body) })); + } + if (url.includes("/api/models/test")) { + if (options.modelTest) return options.modelTest(init); + return Promise.resolve(jsonResponse({ status: "ok", latencyMs: 185 })); + } + if (url.includes("/api/combos/test")) { + if (options.comboTest) return options.comboTest(init); + return Promise.resolve( + jsonResponse({ + comboName: "combo-1", + resolvedBy: "alpha/alpha-chat", + results: [{ model: "alpha-chat", provider: "alpha", status: "ok", latencyMs: 210 }], + }) + ); + } + if (url.includes("/api/combos")) { + return Promise.resolve(jsonResponse({ combos: options.combos ?? DEFAULT_COMBOS })); + } + return Promise.reject(new Error(`Unhandled mock url: ${url}`)); + }); + vi.stubGlobal("fetch", fetchMock); + return fetchMock; +} + +/** Deferred /api/models/test-all handler that records bodies, signals and concurrency. */ +function deferredTestAll() { + const calls: Array> = []; + const state = { inFlight: 0, maxInFlight: 0 }; + const handler: RouteHandler = (init) => { + const body = JSON.parse(String(init?.body)) as TestAllBody; + const response = deferred(); + state.inFlight += 1; + state.maxInFlight = Math.max(state.maxInFlight, state.inFlight); + let settled = false; + calls.push({ + body, + signal: init?.signal, + resolve: () => { + if (settled) return; + settled = true; + state.inFlight -= 1; + response.resolve(jsonResponse({ results: okResultsFor(body, 90) })); + }, + }); + return response.promise; + }; + return { calls, state, handler }; +} + +function readStoredResults(): Record { + return JSON.parse(localStorage.getItem(CATALOG_TEST_RESULTS_KEY) || "{}"); +} + describe("Models and Combos Catalog Page UI", () => { let container: HTMLDivElement; let root: Root; beforeEach(() => { + vi.useFakeTimers({ toFake: ["setTimeout", "clearTimeout", "setInterval", "clearInterval"] }); ( globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean } ).IS_REACT_ACT_ENVIRONMENT = true; @@ -45,147 +229,68 @@ describe("Models and Combos Catalog Page UI", () => { afterEach(() => { act(() => root.unmount()); container.remove(); + vi.useRealTimers(); vi.restoreAllMocks(); vi.unstubAllGlobals(); localStorage.clear(); }); - const setupMockFetch = () => { - const fetchMock = vi.fn().mockImplementation((url: string, init?: RequestInit) => { - const urlStr = typeof url === "string" ? url : String(url); - - if (urlStr.includes("/api/models/catalog")) { - return Promise.resolve({ - ok: true, - json: async () => ({ - catalog: { - alpha: { - provider: "Alpha Labs", - models: [ - { - id: "alpha-chat", - name: "Alpha Chat", - type: "chat", - subtype: "general", - free: true, - context_length: 128_000, - capabilities: { tools: true, vision: true }, - }, - { - id: "alpha-embed", - name: "Alpha Embed", - type: "embedding", - context_length: 8_192, - }, - ], - }, - beta: { - provider: "Beta AI", - models: [ - { - id: "beta-coder", - name: "Beta Coder", - type: "chat", - subtype: "code", - capabilities: { reasoning: true }, - }, - ], - }, - }, - }), - }); - } - - if (urlStr.includes("/api/combos/test")) { - return Promise.resolve({ - ok: true, - json: async () => ({ - comboName: "combo-1", - strategy: "priority", - resolvedBy: "alpha/alpha-chat", - results: [{ model: "alpha-chat", provider: "alpha", status: "ok", latencyMs: 210 }], - testedAt: new Date().toISOString(), - }), - }); - } - - if (urlStr.includes("/api/combos")) { - return Promise.resolve({ - ok: true, - json: async () => ({ - combos: [ - { - id: "c-1", - name: "combo-1", - displayName: "First Combo", - strategy: "priority", - description: "Fallback chain", - models: [{ model: "alpha/alpha-chat" }, { model: "beta/beta-coder" }], - isActive: true, - }, - { - id: "c-2", - name: "combo-2", - displayName: "Second Combo", - strategy: "round-robin", - models: [{ model: "alpha/alpha-embed" }], - isActive: false, - }, - ], - total: 2, - }), - }); - } - - if (urlStr.includes("/api/providers/health-matrix")) { - return Promise.resolve({ - ok: true, - json: async () => ({ - providers: [ - { provider: "alpha", state: "healthy" }, - { provider: "beta", state: "degraded" }, - ], - }), - }); - } - - if (urlStr.includes("/api/models/test-all")) { - const body = init?.body ? JSON.parse(String(init.body)) : {}; - const results: Record = {}; - for (const mid of body.modelIds || []) { - results[mid] = { status: "ok", latencyMs: 140 }; - } - return Promise.resolve({ - ok: true, - json: async () => ({ results }), - }); - } - - if (urlStr.includes("/api/models/test")) { - return Promise.resolve({ - ok: true, - json: async () => ({ - status: "ok", - latencyMs: 185, - responseText: "Hello from test", - }), - }); - } + /** Runs pending timers (mount effects are deferred) and settles resolved fetch promises. */ + async function flush() { + await act(async () => { + await vi.runAllTimersAsync(); + }); + } - return Promise.reject(new Error(`Unhandled mock url: ${urlStr}`)); + async function renderPage() { + await act(async () => { + root.render(); }); + await flush(); + } + + function query(selector: string): T | null { + return container.querySelector(selector) as T | null; + } + + function buttonByText(text: string, scope: ParentNode = container): HTMLButtonElement | null { + return ( + [...scope.querySelectorAll("button")].find( + (button) => button.textContent?.trim() === text + ) ?? null + ); + } - vi.stubGlobal("fetch", fetchMock); - return fetchMock; - }; + function inputByLabel(text: string): HTMLInputElement { + const label = [...container.querySelectorAll("label")].find((element) => + element.textContent?.trim().startsWith(text) + ); + const input = label?.querySelector("input") ?? null; + expect(input).not.toBeNull(); + return input as HTMLInputElement; + } + + function setInputValue(input: HTMLInputElement, value: string) { + const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set; + setter?.call(input, value); + input.dispatchEvent(new Event("input", { bubbles: true })); + } + + function bodyRows(): HTMLTableRowElement[] { + return [...container.querySelectorAll("tbody tr")]; + } + + async function click(element: HTMLElement | null) { + expect(element).not.toBeNull(); + await act(async () => { + element?.click(); + }); + await flush(); + } it("renders tabs and switches between Models and Combos with deep linking", async () => { - setupMockFetch(); - - act(() => { - root.render(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + installFetch(); + await renderPage(); expect(container.textContent).toContain("Alpha Labs"); const tabs = container.querySelectorAll('[role="tab"]'); @@ -194,46 +299,149 @@ describe("Models and Combos Catalog Page UI", () => { expect(tabs[1].textContent).toContain("Combos"); expect(tabs[0].getAttribute("aria-selected")).toBe("true"); - // Click combos tab - act(() => { - (tabs[1] as HTMLElement).click(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + await click(tabs[1] as HTMLElement); expect(tabs[1].getAttribute("aria-selected")).toBe("true"); expect(window.location.search).toContain("tab=combos"); expect(container.textContent).toContain("First Combo"); }); - it("restores active tab from deep link query parameter ?tab=combos", async () => { - setupMockFetch(); - window.history.replaceState(null, "", "/dashboard/models?tab=combos"); + it("restores the active tab and filters from the URL after mount", async () => { + installFetch(); + window.history.replaceState(null, "", "/dashboard/models?tab=combos&status=paused"); - act(() => { - root.render(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + await renderPage(); const tabs = container.querySelectorAll('[role="tab"]'); expect(tabs[1].getAttribute("aria-selected")).toBe("true"); - expect(container.textContent).toContain("First Combo"); + expect(container.textContent).toContain("Second Combo"); + expect(container.textContent).not.toContain("First Combo"); }); - it("executes single model test and displays status badge and latency", async () => { - const fetchMock = setupMockFetch(); + it("server-renders defaults without reading the URL or stored results", () => { + installFetch(); + window.history.replaceState(null, "", "/dashboard/models?tab=combos&provider=beta"); + const key = getModelTestKey("alpha", "alpha-chat"); + localStorage.setItem( + CATALOG_TEST_RESULTS_KEY, + JSON.stringify({ + [key]: { id: key, targetType: "model", status: "ok", latencyMs: 99, testedAt: Date.now() }, + }) + ); - act(() => { - root.render(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + const host = document.createElement("div"); + host.innerHTML = renderToString(); + + const tabs = host.querySelectorAll('[role="tab"]'); + expect(tabs[0].getAttribute("aria-selected")).toBe("true"); + expect(tabs[1].getAttribute("aria-selected")).toBe("false"); + expect(host.querySelector("[data-testid='clear-test-results-btn']")).toBeNull(); + }); + + it("moves selection and focus between tabs with the arrow, Home and End keys", async () => { + installFetch(); + await renderPage(); + + const modelsTab = query("#tab-models"); + const combosTab = query("#tab-combos"); + expect(modelsTab).not.toBeNull(); + expect(combosTab).not.toBeNull(); + + const press = async (target: HTMLElement, key: string) => { + await act(async () => { + target.focus(); + target.dispatchEvent(new KeyboardEvent("keydown", { key, bubbles: true })); + }); + await flush(); + }; + + await press(modelsTab as HTMLElement, "ArrowRight"); + expect(combosTab?.getAttribute("aria-selected")).toBe("true"); + expect(combosTab?.tabIndex).toBe(0); + expect(modelsTab?.tabIndex).toBe(-1); + expect(document.activeElement).toBe(combosTab); + expect(window.location.search).toContain("tab=combos"); + const comboPanel = query('[role="tabpanel"]'); + expect(comboPanel?.getAttribute("aria-labelledby")).toBe("tab-combos"); + + await press(combosTab as HTMLElement, "ArrowRight"); + expect(modelsTab?.getAttribute("aria-selected")).toBe("true"); + expect(document.activeElement).toBe(modelsTab); + + await press(modelsTab as HTMLElement, "End"); + expect(combosTab?.getAttribute("aria-selected")).toBe("true"); + expect(document.activeElement).toBe(combosTab); - const testButtons = container.querySelectorAll("button[data-testid^='test-model-']"); - expect(testButtons.length).toBeGreaterThan(0); + await press(combosTab as HTMLElement, "Home"); + expect(modelsTab?.getAttribute("aria-selected")).toBe("true"); + expect(document.activeElement).toBe(modelsTab); + await press(modelsTab as HTMLElement, "ArrowLeft"); + expect(combosTab?.getAttribute("aria-selected")).toBe("true"); + expect(query('[role="tabpanel"]')?.getAttribute("aria-labelledby")).toBe("tab-combos"); + }); + + it("updates the URL query and visible rows when filters change", async () => { + installFetch(); + await renderPage(); + expect(bodyRows()).toHaveLength(3); + + const minOutput = inputByLabel("Min max output"); + await act(async () => setInputValue(minOutput, "8000")); + await flush(); + + expect(new URLSearchParams(window.location.search).get("minOutput")).toBe("8000"); + expect(bodyRows()).toHaveLength(1); + expect(query("tbody")?.textContent).toContain("Alpha Chat"); + + await act(async () => setInputValue(minOutput, "")); + const providerFilter = query("select"); + expect(providerFilter).not.toBeNull(); await act(async () => { - (testButtons[0] as HTMLElement).click(); + if (!providerFilter) return; + providerFilter.value = "beta"; + providerFilter.dispatchEvent(new Event("change", { bubbles: true })); }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 20))); + await flush(); + + const params = new URLSearchParams(window.location.search); + expect(params.get("provider")).toBe("beta"); + expect(params.has("minOutput")).toBe(false); + expect(bodyRows()).toHaveLength(1); + expect(query("tbody")?.textContent).toContain("Beta Coder"); + }); + + it("ignores NaN and negative numeric URL params", async () => { + installFetch(); + window.history.replaceState(null, "", "/dashboard/models?minContext=abc&minOutput=-5"); + await renderPage(); + + expect(buttonByText("Clear filters")).toBeNull(); + expect(inputByLabel("Min context").value).toBe(""); + expect(inputByLabel("Min max output").value).toBe(""); + expect(bodyRows()).toHaveLength(3); + }); + + it("ignores NaN and negative member-count URL params on the combos tab", async () => { + installFetch(); + window.history.replaceState( + null, + "", + "/dashboard/models?tab=combos&minMembers=-1&maxMembers=x" + ); + await renderPage(); + + expect(buttonByText("Clear filters")).toBeNull(); + expect(inputByLabel("Min members").value).toBe(""); + expect(inputByLabel("Max members").value).toBe(""); + expect(bodyRows()).toHaveLength(2); + }); + + it("executes a single model test and displays the status badge and latency", async () => { + const fetchMock = installFetch(); + await renderPage(); + + await click(query("button[data-testid='test-model-alpha-chat']")); expect(fetchMock).toHaveBeenCalledWith( "/api/models/test", @@ -242,142 +450,274 @@ describe("Models and Combos Catalog Page UI", () => { body: JSON.stringify({ providerId: "alpha", modelId: "alpha-chat" }), }) ); + const saved = readStoredResults(); + expect(saved[getModelTestKey("alpha", "alpha-chat")]?.status).toBe("ok"); + expect(bodyRows()[0].textContent).toContain("185ms"); + expect(bodyRows()[0].textContent).toContain("Just now"); + }); - // Verify localStorage has saved result - const saved = JSON.parse(localStorage.getItem(CATALOG_TEST_RESULTS_KEY) || "{}"); - const key = getModelTestKey("alpha", "alpha-chat"); - expect(saved[key]).toBeDefined(); - expect(saved[key].status).toBe("ok"); - expect(saved[key].latencyMs).toBe(185); + it("executes a single combo test and displays the status badge and latency", async () => { + const fetchMock = installFetch(); + window.history.replaceState(null, "", "/dashboard/models?tab=combos"); + await renderPage(); + + await click(query("button[data-testid='test-combo-combo-1']")); + + expect(fetchMock).toHaveBeenCalledWith( + "/api/combos/test", + expect.objectContaining({ method: "POST", body: JSON.stringify({ comboName: "combo-1" }) }) + ); + const firstRow = bodyRows().find((row) => row.textContent?.includes("First Combo")); + expect(firstRow?.textContent).toContain("OK"); + expect(firstRow?.textContent).toContain("210ms"); + expect(readStoredResults()[getComboTestKey("combo-1")]?.status).toBe("ok"); }); - it("restores previously stored test results from localStorage on mount", async () => { - const key = getModelTestKey("alpha", "alpha-chat"); + it("restores stored results on mount with relative test times and screen-reader error text", async () => { + const okKey = getModelTestKey("alpha", "alpha-chat"); + const quotaKey = getModelTestKey("alpha", "alpha-embed"); + const httpKey = getModelTestKey("beta", "beta-coder"); localStorage.setItem( CATALOG_TEST_RESULTS_KEY, JSON.stringify({ - [key]: { - id: key, + [okKey]: { + id: okKey, targetType: "model", - providerId: "alpha", - modelId: "alpha-chat", status: "ok", latencyMs: 123, + testedAt: Date.now() - 5 * 60_000, + }, + [quotaKey]: { + id: quotaKey, + targetType: "model", + status: "error", + error: "Upstream quota exhausted", + errorClass: "quota", + testedAt: Date.now() - 3 * 3_600_000, + }, + [httpKey]: { + id: httpKey, + targetType: "model", + status: "error", + errorClass: "other", + statusCode: 503, testedAt: Date.now(), }, }) ); + installFetch(); + await renderPage(); - setupMockFetch(); - - act(() => { - root.render(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + const [chatRow, embedRow, coderRow] = bodyRows(); + expect(chatRow.textContent).toContain("123ms"); + expect(chatRow.textContent).toContain("5m ago"); + expect(embedRow.textContent).toContain("Quota exceeded"); + expect(embedRow.textContent).toContain("3h ago"); - // Badge showing ok or latency should be visible in the row - expect(container.textContent).toContain("123ms"); + const quotaDetail = [...embedRow.querySelectorAll(".sr-only")].find((element) => + element.textContent?.includes("Upstream quota exhausted") + ); + expect(quotaDetail).not.toBeUndefined(); + const httpDetail = [...coderRow.querySelectorAll(".sr-only")].find((element) => + element.textContent?.includes("HTTP 503") + ); + expect(httpDetail).not.toBeUndefined(); }); - it("runs bulk model testing batching per provider with concurrency <= 2 and max 100 ids", async () => { - const fetchMock = setupMockFetch(); - - act(() => { - root.render(); + it("confirms large bulk runs, batches ≤100 ids per provider and keeps ≤2 calls in flight", async () => { + const bigModels = Array.from({ length: 120 }, (_, index) => ({ + id: `big-${String(index).padStart(3, "0")}`, + name: `Big ${index}`, + type: "chat", + })); + const testAll = deferredTestAll(); + installFetch({ + catalog: { + big: { provider: "Provider Big", models: bigModels }, + two: { provider: "Provider Two", models: [{ id: "two-1", name: "Two", type: "chat" }] }, + three: { + provider: "Provider Three", + models: [{ id: "three-1", name: "Three", type: "chat" }], + }, + }, + testAll: testAll.handler, }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + await renderPage(); - const testAllFilteredBtn = container.querySelector( - "button[data-testid='test-all-filtered-btn']" - ) as HTMLElement; - expect(testAllFilteredBtn).toBeDefined(); + await click(query("button[data-testid='test-all-filtered-btn']")); - await act(async () => { - testAllFilteredBtn.click(); - }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 30))); + const dialog = document.querySelector('[role="dialog"]'); + expect(dialog).not.toBeNull(); + expect(dialog?.textContent).toContain("122"); + expect(testAll.calls).toHaveLength(0); - const testAllCalls = fetchMock.mock.calls.filter((call) => - String(call[0]).includes("/api/models/test-all") + await click(buttonByText("Start tests", dialog ?? container)); + expect(document.querySelector('[role="dialog"]')).toBeNull(); + expect(testAll.calls).toHaveLength(2); + + const progress = query('[role="progressbar"]'); + expect(progress).not.toBeNull(); + expect(progress?.getAttribute("aria-label")).toBe("Bulk test progress"); + expect(progress?.getAttribute("aria-valuetext")).toBe("Testing 0 of 122 models…"); + expect(query("button[data-testid='test-model-big-000']")?.disabled).toBe( + true ); - expect(testAllCalls.length).toBeGreaterThanOrEqual(1); - for (const call of testAllCalls) { - const body = JSON.parse(String(call[1]?.body)); - expect(body.modelIds.length).toBeLessThanOrEqual(100); - expect(body.respectRateLimit).toBe(true); - expect(typeof body.providerId).toBe("string"); + for (let index = 0; index < testAll.calls.length; index += 1) { + testAll.calls[index].resolve(); + await flush(); } + + expect(testAll.calls).toHaveLength(4); + expect(testAll.state.maxInFlight).toBe(2); + for (const call of testAll.calls) { + expect(call.body.modelIds.length).toBeLessThanOrEqual(100); + expect(call.body.respectRateLimit).toBe(true); + } + const bigBatches = testAll.calls.filter((call) => call.body.providerId === "big"); + expect(bigBatches.map((call) => call.body.modelIds.length).sort((a, b) => b - a)).toEqual([ + 100, 20, + ]); + const sentIds = testAll.calls.flatMap((call) => call.body.modelIds); + expect(new Set(sentIds).size).toBe(122); + expect(sentIds).toHaveLength(122); + + expect(query("button[data-testid='cancel-tests-btn']")).toBeNull(); + expect(Object.keys(readStoredResults())).toHaveLength(122); + expect(query("button[data-testid='test-model-big-000']")?.disabled).toBe( + false + ); }); - it("stops bulk scheduling when Cancel is clicked", async () => { - let callCount = 0; - vi.stubGlobal( - "fetch", - vi.fn().mockImplementation((url: string) => { - const urlStr = String(url); - if (urlStr.includes("/api/models/catalog")) { - // Provide 5 providers to ensure multiple batches - return Promise.resolve({ - ok: true, - json: async () => ({ - catalog: { - p1: { provider: "P1", models: [{ id: "m1", name: "m1", type: "chat" }] }, - p2: { provider: "P2", models: [{ id: "m2", name: "m2", type: "chat" }] }, - p3: { provider: "P3", models: [{ id: "m3", name: "m3", type: "chat" }] }, - p4: { provider: "P4", models: [{ id: "m4", name: "m4", type: "chat" }] }, - }, - }), - }); - } - if (urlStr.includes("/api/providers/health-matrix")) { - return Promise.resolve({ ok: true, json: async () => ({ providers: [] }) }); - } - if (urlStr.includes("/api/combos")) { - return Promise.resolve({ ok: true, json: async () => ({ combos: [], total: 0 }) }); - } - if (urlStr.includes("/api/models/test-all")) { - callCount++; - // Simulate latency - return new Promise((resolve) => { - setTimeout( - () => - resolve({ - ok: true, - json: async () => ({ results: { m1: { status: "ok", latencyMs: 50 } } }), - }), - 50 - ); - }); - } - return Promise.reject(new Error("unexpected")); - }) + it("asks for confirmation before testing more than 20 combos and can be dismissed", async () => { + const combos = Array.from({ length: 21 }, (_, index) => ({ + id: `c-${index}`, + name: `combo-${index}`, + strategy: "priority", + models: [{ model: "alpha/alpha-chat" }], + isActive: true, + })); + const fetchMock = installFetch({ combos }); + window.history.replaceState(null, "", "/dashboard/models?tab=combos"); + await renderPage(); + + await click(query("button[data-testid='test-all-filtered-btn']")); + const dialog = document.querySelector('[role="dialog"]'); + expect(dialog?.textContent).toContain("21"); + + await click(buttonByText("Cancel", dialog ?? container)); + expect(document.querySelector('[role="dialog"]')).toBeNull(); + expect(fetchMock.mock.calls.some((call) => String(call[0]).includes("/api/combos/test"))).toBe( + false ); + }); - act(() => { - root.render(); + it("keeps models the server did not test (stoppedEarly) untested", async () => { + installFetch({ + testAll: async (init) => { + const body = JSON.parse(String(init?.body)) as TestAllBody; + if (body.providerId === "alpha") { + return jsonResponse({ + results: { + "alpha-chat": { status: "error", latencyMs: 20, rateLimited: true, statusCode: 429 }, + }, + stoppedEarly: true, + stopReason: "consecutive_rate_limits", + }); + } + return jsonResponse({ results: okResultsFor(body) }); + }, }); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 10))); + await renderPage(); - const testAllFilteredBtn = container.querySelector( - "button[data-testid='test-all-filtered-btn']" - ) as HTMLElement; + await click(query("button[data-testid='test-all-filtered-btn']")); - act(() => { - testAllFilteredBtn.click(); + const saved = readStoredResults(); + expect(saved[getModelTestKey("alpha", "alpha-chat")]?.status).toBe("error"); + expect(saved[getModelTestKey("beta", "beta-coder")]?.status).toBe("ok"); + expect(saved[getModelTestKey("alpha", "alpha-embed")]).toBeUndefined(); + expect(Object.keys(saved)).toHaveLength(2); + }); + + it("aborts a running bulk test on unmount and schedules nothing afterwards", async () => { + const testAll = deferredTestAll(); + installFetch({ + catalog: { + p1: { provider: "P1", models: [{ id: "m1", name: "m1", type: "chat" }] }, + p2: { provider: "P2", models: [{ id: "m2", name: "m2", type: "chat" }] }, + p3: { provider: "P3", models: [{ id: "m3", name: "m3", type: "chat" }] }, + }, + testAll: testAll.handler, }); + await renderPage(); - const cancelBtn = container.querySelector( - "button[data-testid='cancel-tests-btn']" - ) as HTMLElement; - expect(cancelBtn).toBeDefined(); + await click(query("button[data-testid='test-all-filtered-btn']")); + expect(testAll.calls).toHaveLength(2); + + act(() => root.unmount()); + expect(testAll.calls.every((call) => call.signal?.aborted === true)).toBe(true); - act(() => { - cancelBtn.click(); + for (const call of testAll.calls) call.resolve(); + await flush(); + + expect(testAll.calls).toHaveLength(2); + expect(localStorage.getItem(CATALOG_TEST_RESULTS_KEY)).toBeNull(); + }); + + it("cancels run A, and A's late completions leave run B running and cancellable", async () => { + const comboCalls: Array> = []; + installFetch({ + comboTest: (init) => { + const body = JSON.parse(String(init?.body)) as { comboName: string }; + const response = deferred(); + comboCalls.push({ + body, + signal: init?.signal, + resolve: () => + response.resolve( + jsonResponse({ + comboName: body.comboName, + resolvedBy: "alpha/alpha-chat", + results: [{ model: "alpha-chat", status: "ok", latencyMs: 50 }], + }) + ), + }); + return response.promise; + }, }); + window.history.replaceState(null, "", "/dashboard/models?tab=combos"); + await renderPage(); + + // Run A + await click(query("button[data-testid='test-all-filtered-btn']")); + expect(comboCalls).toHaveLength(2); + expect(query('[role="progressbar"]')?.getAttribute("aria-valuetext")).toBe( + "Testing 0 of 2 combos…" + ); + await click(query("button[data-testid='cancel-tests-btn']")); + expect(comboCalls.every((call) => call.signal?.aborted === true)).toBe(true); + expect(query("button[data-testid='cancel-tests-btn']")).toBeNull(); + expect(container.textContent).toContain("Tests cancelled after 0 of 2"); + + // Run B + await click(query("button[data-testid='test-all-filtered-btn']")); + expect(comboCalls).toHaveLength(4); + + // A's late completions + comboCalls[0].resolve(); + comboCalls[1].resolve(); + await flush(); + + expect(query("button[data-testid='cancel-tests-btn']")).not.toBeNull(); + expect(query('[role="progressbar"]')).not.toBeNull(); + expect(query("button[data-testid='test-combo-combo-1']")?.disabled).toBe( + true + ); + expect(localStorage.getItem(CATALOG_TEST_RESULTS_KEY)).toBeNull(); - await act(async () => new Promise((resolve) => window.setTimeout(resolve, 80))); - // Should have aborted and not called all 4 providers - expect(callCount).toBeLessThan(4); + await click(query("button[data-testid='cancel-tests-btn']")); + expect(comboCalls[2].signal?.aborted).toBe(true); + expect(comboCalls[3].signal?.aborted).toBe(true); + expect(query("button[data-testid='cancel-tests-btn']")).toBeNull(); }); }); From 96348ad30ab2e7577f1628f1ed59d3c9f8ada2c8 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 16:43:10 +0300 Subject: [PATCH 05/16] i18n(dashboard): translate catalog review-fix labels across all 66 locales Adds the 16 new modelCatalog keys (min max output filter, bulk progress and cancel status, bulk confirm dialog, error detail and HTTP fallback text, additional capabilities label, nested combo member label) to every locale with real translations; no __MISSING__ markers remain. --- src/i18n/messages/am.json | 18 +++++++++++++++++- src/i18n/messages/ar.json | 18 +++++++++++++++++- src/i18n/messages/az.json | 18 +++++++++++++++++- src/i18n/messages/bg.json | 18 +++++++++++++++++- src/i18n/messages/bn.json | 18 +++++++++++++++++- src/i18n/messages/bs.json | 18 +++++++++++++++++- src/i18n/messages/cs.json | 18 +++++++++++++++++- src/i18n/messages/da.json | 18 +++++++++++++++++- src/i18n/messages/de.json | 18 +++++++++++++++++- src/i18n/messages/el.json | 18 +++++++++++++++++- src/i18n/messages/es.json | 18 +++++++++++++++++- src/i18n/messages/et.json | 18 +++++++++++++++++- src/i18n/messages/fa.json | 18 +++++++++++++++++- src/i18n/messages/fi.json | 18 +++++++++++++++++- src/i18n/messages/fr.json | 18 +++++++++++++++++- src/i18n/messages/ga.json | 18 +++++++++++++++++- src/i18n/messages/gu.json | 18 +++++++++++++++++- src/i18n/messages/ha.json | 18 +++++++++++++++++- src/i18n/messages/he.json | 18 +++++++++++++++++- src/i18n/messages/hi.json | 18 +++++++++++++++++- src/i18n/messages/hr.json | 18 +++++++++++++++++- src/i18n/messages/hu.json | 18 +++++++++++++++++- src/i18n/messages/hy.json | 18 +++++++++++++++++- src/i18n/messages/id.json | 18 +++++++++++++++++- src/i18n/messages/ig.json | 18 +++++++++++++++++- src/i18n/messages/it.json | 18 +++++++++++++++++- src/i18n/messages/ja.json | 18 +++++++++++++++++- src/i18n/messages/ka.json | 18 +++++++++++++++++- src/i18n/messages/km.json | 18 +++++++++++++++++- src/i18n/messages/kn.json | 18 +++++++++++++++++- src/i18n/messages/ko.json | 18 +++++++++++++++++- src/i18n/messages/lt.json | 18 +++++++++++++++++- src/i18n/messages/lv.json | 18 +++++++++++++++++- src/i18n/messages/ml.json | 18 +++++++++++++++++- src/i18n/messages/mr.json | 18 +++++++++++++++++- src/i18n/messages/ms.json | 18 +++++++++++++++++- src/i18n/messages/mt.json | 18 +++++++++++++++++- src/i18n/messages/my.json | 18 +++++++++++++++++- src/i18n/messages/ne.json | 18 +++++++++++++++++- src/i18n/messages/nl.json | 18 +++++++++++++++++- src/i18n/messages/no.json | 18 +++++++++++++++++- src/i18n/messages/or.json | 18 +++++++++++++++++- src/i18n/messages/pa.json | 18 +++++++++++++++++- src/i18n/messages/phi.json | 18 +++++++++++++++++- src/i18n/messages/pl.json | 18 +++++++++++++++++- src/i18n/messages/pt-BR.json | 18 +++++++++++++++++- src/i18n/messages/pt.json | 18 +++++++++++++++++- src/i18n/messages/ro.json | 18 +++++++++++++++++- src/i18n/messages/ru.json | 18 +++++++++++++++++- src/i18n/messages/si.json | 18 +++++++++++++++++- src/i18n/messages/sk.json | 18 +++++++++++++++++- src/i18n/messages/sl.json | 18 +++++++++++++++++- src/i18n/messages/sr.json | 18 +++++++++++++++++- src/i18n/messages/sv.json | 18 +++++++++++++++++- src/i18n/messages/sw.json | 18 +++++++++++++++++- src/i18n/messages/ta.json | 18 +++++++++++++++++- src/i18n/messages/te.json | 18 +++++++++++++++++- src/i18n/messages/th.json | 18 +++++++++++++++++- src/i18n/messages/tr.json | 18 +++++++++++++++++- src/i18n/messages/uk-UA.json | 18 +++++++++++++++++- src/i18n/messages/ur.json | 18 +++++++++++++++++- src/i18n/messages/uz.json | 18 +++++++++++++++++- src/i18n/messages/vi.json | 18 +++++++++++++++++- src/i18n/messages/yo.json | 18 +++++++++++++++++- src/i18n/messages/zh-CN.json | 18 +++++++++++++++++- src/i18n/messages/zh-TW.json | 18 +++++++++++++++++- 66 files changed, 1122 insertions(+), 66 deletions(-) diff --git a/src/i18n/messages/am.json b/src/i18n/messages/am.json index 1538a5d3a22f..7c13d0743ea8 100644 --- a/src/i18n/messages/am.json +++ b/src/i18n/messages/am.json @@ -3317,7 +3317,23 @@ "next": "ቀጣይ", "combo": "ጥምረት", "members": "አባላት", - "moreMembers": "+{count} ተጨማሪ" + "moreMembers": "+{count} ተጨማሪ", + "minMaxOutput": "ዝቅተኛው ከፍተኛ ውጤት", + "minMaxOutputPlaceholder": "ለምሳሌ፡ 4096", + "bulkTestProgress": "የጅምላ ሙከራ ሂደት", + "testingProgressModels": "ከ{total} ሞዴሎች ውስጥ {completed} በመሞከር ላይ…", + "testingProgressCombos": "ከ{total} ጥምረቶች ውስጥ {completed} በመሞከር ላይ…", + "testsCancelledModels": "ከ{total} ሞዴሎች ውስጥ {completed} ከተሞከሩ በኋላ ሙከራዎች ተሰርዘዋል", + "testsCancelledCombos": "ከ{total} ጥምረቶች ውስጥ {completed} ከተሞከሩ በኋላ ሙከራዎች ተሰርዘዋል", + "bulkConfirmTitle": "የጅምላ ሙከራ ይጀመር?", + "bulkConfirmModels": "ይህ ወደ አቅራቢዎችዎ {count} የሞዴል ሙከራዎችን ይልካል እንዲሁም ኮታ ሊጠቀም ይችላል። ይቀጥል?", + "bulkConfirmCombos": "ይህ {count} የጥምረት ሙከራዎችን ያካሂዳል እንዲሁም የአቅራቢ ኮታ ሊጠቀም ይችላል። ይቀጥል?", + "bulkConfirmStart": "ሙከራዎችን ጀምር", + "errorDetail": "የስህተት ዝርዝሮች፡ {detail}", + "httpError": "ጥያቄው በHTTP {status} አልተሳካም", + "testFailedNoDetail": "ሙከራው ያለ ምንም የስህተት መልእክት አልተሳካም", + "additionalCapabilities": "ተጨማሪ አቅሞች፡ {list}", + "comboRefMember": "ጥምረት → {name}" }, "combos": { "title": "ጥምረቶች", diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 21771bf5b534..dee7f8d4ce71 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -3317,7 +3317,23 @@ "next": "التالي", "combo": "توليفة", "members": "الأعضاء", - "moreMembers": "+{count} المزيد" + "moreMembers": "+{count} المزيد", + "minMaxOutput": "الحد الأدنى للحد الأقصى للإخراج", + "minMaxOutputPlaceholder": "مثال: 4096", + "bulkTestProgress": "تقدم الاختبار المجمع", + "testingProgressModels": "جارٍ اختبار {completed} من أصل {total} نموذج…", + "testingProgressCombos": "جارٍ اختبار {completed} من أصل {total} تركيبة…", + "testsCancelledModels": "تم إلغاء الاختبارات بعد {completed} من أصل {total} نموذج", + "testsCancelledCombos": "تم إلغاء الاختبارات بعد {completed} من أصل {total} تركيبة", + "bulkConfirmTitle": "بدء الاختبار المجمع؟", + "bulkConfirmModels": "سيؤدي هذا إلى إرسال {count} من اختبارات النماذج إلى موفريك وقد يستهلك من الحصة. متابعة؟", + "bulkConfirmCombos": "سيؤدي هذا إلى تشغيل {count} من اختبارات التراكيب وقد يستهلك من حصة الموفر. متابعة؟", + "bulkConfirmStart": "بدء الاختبارات", + "errorDetail": "تفاصيل الخطأ: {detail}", + "httpError": "فشل الطلب برمز HTTP {status}", + "testFailedNoDetail": "فشل الاختبار بدون رسالة خطأ", + "additionalCapabilities": "إمكانيات إضافية: {list}", + "comboRefMember": "تركيبة → {name}" }, "combos": { "title": "المجموعات", diff --git a/src/i18n/messages/az.json b/src/i18n/messages/az.json index 4f13c10dc4e8..e2f4f664091e 100644 --- a/src/i18n/messages/az.json +++ b/src/i18n/messages/az.json @@ -3317,7 +3317,23 @@ "next": "Növbəti", "combo": "Kombo", "members": "Üzvlər", - "moreMembers": "+{count} daha" + "moreMembers": "+{count} daha", + "minMaxOutput": "Minimum maksimum çıxış", + "minMaxOutputPlaceholder": "məs. 4096", + "bulkTestProgress": "Kütləvi test gedişatı", + "testingProgressModels": "{total} modeldən {completed} modeli test edilir…", + "testingProgressCombos": "{total} kombodan {completed} kombosu test edilir…", + "testsCancelledModels": "{total} modeldən {completed} modeli tamamlandıqdan sonra testlər ləğv edildi", + "testsCancelledCombos": "{total} kombodan {completed} kombosu tamamlandıqdan sonra testlər ləğv edildi", + "bulkConfirmTitle": "Kütləvi test başladılsın?", + "bulkConfirmModels": "Bu, provayderlərinizə {count} model testi göndərir və kvotadan istifadə edə bilər. Davam edilsin?", + "bulkConfirmCombos": "Bu, {count} kombo testini icra edir və provayder kvotasından istifadə edə bilər. Davam edilsin?", + "bulkConfirmStart": "Testləri başlat", + "errorDetail": "Xəta təfərrüatları: {detail}", + "httpError": "Sorğu HTTP {status} ilə uğursuz oldu", + "testFailedNoDetail": "Test xəta mesajı olmadan uğursuz oldu", + "additionalCapabilities": "Əlavə imkanlar: {list}", + "comboRefMember": "Kombo → {name}" }, "combos": { "title": "Kombinasiyalar", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index e3111968bb06..b19b19efef8f 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -3317,7 +3317,23 @@ "next": "Следваща", "combo": "Комбинация", "members": "Членове", - "moreMembers": "+{count} още" + "moreMembers": "+{count} още", + "minMaxOutput": "Минимален максимален изход", + "minMaxOutputPlaceholder": "напр. 4096", + "bulkTestProgress": "Напредък на груповото тестване", + "testingProgressModels": "Тестване на {completed} от {total} модела…", + "testingProgressCombos": "Тестване на {completed} от {total} комбинации…", + "testsCancelledModels": "Тестовете са анулирани след {completed} от {total} модела", + "testsCancelledCombos": "Тестовете са анулирани след {completed} от {total} комбинации", + "bulkConfirmTitle": "Стартиране на групов тест?", + "bulkConfirmModels": "Това ще изпрати {count} теста на модели към вашите доставчици и може да изразходи квота. Продължаване?", + "bulkConfirmCombos": "Това ще изпълни {count} теста на комбинации и може да изразходи квота на доставчик. Продължаване?", + "bulkConfirmStart": "Стартиране на тестовете", + "errorDetail": "Подробности за грешката: {detail}", + "httpError": "Заявката е неуспешна с HTTP {status}", + "testFailedNoDetail": "Тестът е неуспешен без съобщение за грешка", + "additionalCapabilities": "Допълнителни възможности: {list}", + "comboRefMember": "Комбинация → {name}" }, "combos": { "title": "Комбота", diff --git a/src/i18n/messages/bn.json b/src/i18n/messages/bn.json index 75eabcf94e75..e77539916901 100644 --- a/src/i18n/messages/bn.json +++ b/src/i18n/messages/bn.json @@ -3317,7 +3317,23 @@ "next": "পরবর্তী", "combo": "কম্বো", "members": "সদস্য", - "moreMembers": "+{count} আরও" + "moreMembers": "+{count} আরও", + "minMaxOutput": "ন্যূনতম সর্বোচ্চ আউটপুট", + "minMaxOutputPlaceholder": "যেমন: 4096", + "bulkTestProgress": "বাল্ক পরীক্ষার অগ্রগতি", + "testingProgressModels": "{total}-এর মধ্যে {completed}টি মডেল পরীক্ষা করা হচ্ছে…", + "testingProgressCombos": "{total}-এর মধ্যে {completed}টি কম্বো পরীক্ষা করা হচ্ছে…", + "testsCancelledModels": "{total}-এর মধ্যে {completed}টি মডেলের পর পরীক্ষা বাতিল করা হয়েছে", + "testsCancelledCombos": "{total}-এর মধ্যে {completed}টি কম্বোর পর পরীক্ষা বাতিল করা হয়েছে", + "bulkConfirmTitle": "বাল্ক পরীক্ষা শুরু করবেন?", + "bulkConfirmModels": "এটি আপনার প্রোভাইডারদের কাছে {count}টি মডেল পরীক্ষা পাঠাবে এবং কোটা ব্যবহার করতে পারে। এগিয়ে যাবেন?", + "bulkConfirmCombos": "এটি {count}টি কম্বো পরীক্ষা চালাবে এবং প্রোভাইডার কোটা ব্যবহার করতে পারে। এগিয়ে যাবেন?", + "bulkConfirmStart": "পরীক্ষা শুরু করুন", + "errorDetail": "ত্রুটির বিবরণ: {detail}", + "httpError": "HTTP {status} সহ অনুরোধ ব্যর্থ হয়েছে", + "testFailedNoDetail": "কোনো ত্রুটি বার্তা ছাড়াই পরীক্ষা ব্যর্থ হয়েছে", + "additionalCapabilities": "অতিরিক্ত সক্ষমতা: {list}", + "comboRefMember": "কম্বো → {name}" }, "combos": { "title": "কম্বোসমূহ", diff --git a/src/i18n/messages/bs.json b/src/i18n/messages/bs.json index df30d91ec0e0..15f1a2fabafc 100644 --- a/src/i18n/messages/bs.json +++ b/src/i18n/messages/bs.json @@ -3317,7 +3317,23 @@ "next": "Sljedeća", "combo": "Kombinacija", "members": "Članovi", - "moreMembers": "+{count} više" + "moreMembers": "+{count} više", + "minMaxOutput": "Minimalni maksimalni izlaz", + "minMaxOutputPlaceholder": "npr. 4096", + "bulkTestProgress": "Napredak grupnog testiranja", + "testingProgressModels": "Testiranje {completed} od {total} modela…", + "testingProgressCombos": "Testiranje {completed} od {total} kombinacija…", + "testsCancelledModels": "Testovi su otkazani nakon {completed} od {total} modela", + "testsCancelledCombos": "Testovi su otkazani nakon {completed} od {total} kombinacija", + "bulkConfirmTitle": "Pokrenuti grupno testiranje?", + "bulkConfirmModels": "Ovo šalje {count} testova modela vašim pružaocima usluga i može potrošiti kvotu. Želite li nastaviti?", + "bulkConfirmCombos": "Ovo pokreće {count} testova kombinacija i može potrošiti kvotu pružaoca usluga. Želite li nastaviti?", + "bulkConfirmStart": "Pokreni testove", + "errorDetail": "Detalji greške: {detail}", + "httpError": "Zahtjev nije uspio sa statusom HTTP {status}", + "testFailedNoDetail": "Test nije uspio bez poruke o grešci", + "additionalCapabilities": "Dodatne mogućnosti: {list}", + "comboRefMember": "Kombinacija → {name}" }, "combos": { "title": "Kombinacije", diff --git a/src/i18n/messages/cs.json b/src/i18n/messages/cs.json index c6cd89ac2d95..f639d22b9af5 100644 --- a/src/i18n/messages/cs.json +++ b/src/i18n/messages/cs.json @@ -3317,7 +3317,23 @@ "next": "Další", "combo": "Kombinace", "members": "Členové", - "moreMembers": "+{count} dalších" + "moreMembers": "+{count} dalších", + "minMaxOutput": "Minimální maximální výstup", + "minMaxOutputPlaceholder": "např. 4096", + "bulkTestProgress": "Průběh hromadného testování", + "testingProgressModels": "Testování {completed} z {total} modelů…", + "testingProgressCombos": "Testování {completed} z {total} kombinací…", + "testsCancelledModels": "Testy byly zrušeny po {completed} z {total} modelů", + "testsCancelledCombos": "Testy byly zrušeny po {completed} z {total} kombinací", + "bulkConfirmTitle": "Spustit hromadný test?", + "bulkConfirmModels": "Tímto odešlete {count} testů modelů vašim poskytovatelům, což může spotřebovat kvótu. Pokračovat?", + "bulkConfirmCombos": "Tímto se spustí {count} testů kombinací, což může spotřebovat kvótu poskytovatele. Pokračovat?", + "bulkConfirmStart": "Spustit testy", + "errorDetail": "Podrobnosti chyby: {detail}", + "httpError": "Požadavek selhal s kódem HTTP {status}", + "testFailedNoDetail": "Test selhal bez chybové zprávy", + "additionalCapabilities": "Další schopnosti: {list}", + "comboRefMember": "Kombinace → {name}" }, "combos": { "title": "Komba", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index f4658112c841..138a525dd359 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -3317,7 +3317,23 @@ "next": "Næste", "combo": "Kombination", "members": "Medlemmer", - "moreMembers": "+{count} flere" + "moreMembers": "+{count} flere", + "minMaxOutput": "Min. maks. output", + "minMaxOutputPlaceholder": "f.eks. 4096", + "bulkTestProgress": "Fremskridt for massetest", + "testingProgressModels": "Tester {completed} af {total} modeller…", + "testingProgressCombos": "Tester {completed} af {total} kombinationer…", + "testsCancelledModels": "Test afbrudt efter {completed} af {total} modeller", + "testsCancelledCombos": "Test afbrudt efter {completed} af {total} kombinationer", + "bulkConfirmTitle": "Start massetest?", + "bulkConfirmModels": "Dette sender {count} modeltests til dine udbydere og kan bruge kvote. Fortsæt?", + "bulkConfirmCombos": "Dette kører {count} kombinationstests og kan bruge udbyderkvote. Fortsæt?", + "bulkConfirmStart": "Start test", + "errorDetail": "Fejldetaljer: {detail}", + "httpError": "Anmodning mislykkedes med HTTP {status}", + "testFailedNoDetail": "Test mislykkedes uden en fejlmeddelelse", + "additionalCapabilities": "Yderligere funktioner: {list}", + "comboRefMember": "Kombination → {name}" }, "combos": { "title": "Kombinationer", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 0644c626b113..35af316c3077 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -3317,7 +3317,23 @@ "next": "Weiter", "combo": "Kombination", "members": "Mitglieder", - "moreMembers": "+{count} weitere" + "moreMembers": "+{count} weitere", + "minMaxOutput": "Min. maximale Ausgabe", + "minMaxOutputPlaceholder": "z. B. 4096", + "bulkTestProgress": "Bulk-Test-Fortschritt", + "testingProgressModels": "{completed} von {total} Modellen werden getestet…", + "testingProgressCombos": "{completed} von {total} Combos werden getestet…", + "testsCancelledModels": "Tests nach {completed} von {total} Modellen abgebrochen", + "testsCancelledCombos": "Tests nach {completed} von {total} Combos abgebrochen", + "bulkConfirmTitle": "Bulk-Test starten?", + "bulkConfirmModels": "Dies sendet {count} Modelltests an Ihre Anbieter und verbraucht möglicherweise Kontingent. Fortfahren?", + "bulkConfirmCombos": "Dies führt {count} Combo-Tests aus und verbraucht möglicherweise Anbieter-Kontingent. Fortfahren?", + "bulkConfirmStart": "Tests starten", + "errorDetail": "Fehlerdetails: {detail}", + "httpError": "Anfrage fehlgeschlagen mit HTTP {status}", + "testFailedNoDetail": "Test ohne Fehlermeldung fehlgeschlagen", + "additionalCapabilities": "Zusätzliche Fähigkeiten: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Kombinationen", diff --git a/src/i18n/messages/el.json b/src/i18n/messages/el.json index a4397106ad13..3ecfbf698d0d 100644 --- a/src/i18n/messages/el.json +++ b/src/i18n/messages/el.json @@ -3317,7 +3317,23 @@ "next": "Επόμενο", "combo": "Συνδυασμός", "members": "Μέλη", - "moreMembers": "+{count} ακόμη" + "moreMembers": "+{count} ακόμη", + "minMaxOutput": "Ελάχιστη μέγιστη έξοδος", + "minMaxOutputPlaceholder": "π.χ. 4096", + "bulkTestProgress": "Πρόοδος μαζικού ελέγχου", + "testingProgressModels": "Έλεγχος {completed} από {total} μοντέλα…", + "testingProgressCombos": "Έλεγχος {completed} από {total} συνδυασμούς…", + "testsCancelledModels": "Οι έλεγχοι ακυρώθηκαν μετά από {completed} από {total} μοντέλα", + "testsCancelledCombos": "Οι έλεγχοι ακυρώθηκαν μετά από {completed} από {total} συνδυασμούς", + "bulkConfirmTitle": "Έναρξη μαζικού ελέγχου;", + "bulkConfirmModels": "Αυτό θα στείλει {count} δοκιμές μοντέλων στους παρόχους σας και ενδέχεται να καταναλώσει όριο χρήσης. Συνέχεια;", + "bulkConfirmCombos": "Αυτό θα εκτελέσει {count} δοκιμές συνδυασμών και ενδέχεται να καταναλώσει όριο χρήσης παρόχου. Συνέχεια;", + "bulkConfirmStart": "Έναρξη δοκιμών", + "errorDetail": "Λεπτομέρειες σφάλματος: {detail}", + "httpError": "Το αίτημα απέτυχε με HTTP {status}", + "testFailedNoDetail": "Η δοκιμή απέτυχε χωρίς μήνυμα σφάλματος", + "additionalCapabilities": "Πρόσθετες δυνατότητες: {list}", + "comboRefMember": "Συνδυασμός → {name}" }, "combos": { "title": "Συνδυασμοί", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 445d52f001ff..4e8c82e0dc5d 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -3317,7 +3317,23 @@ "next": "Siguiente", "combo": "Combo", "members": "Miembros", - "moreMembers": "+{count} más" + "moreMembers": "+{count} más", + "minMaxOutput": "Mínimo de salida máxima", + "minMaxOutputPlaceholder": "p. ej., 4096", + "bulkTestProgress": "Progreso de la prueba masiva", + "testingProgressModels": "Probando {completed} de {total} modelos…", + "testingProgressCombos": "Probando {completed} de {total} combinaciones…", + "testsCancelledModels": "Pruebas canceladas tras {completed} de {total} modelos", + "testsCancelledCombos": "Pruebas canceladas tras {completed} de {total} combinaciones", + "bulkConfirmTitle": "¿Iniciar prueba masiva?", + "bulkConfirmModels": "Esto envía {count} pruebas de modelos a tus proveedores y puede consumir cuota. ¿Continuar?", + "bulkConfirmCombos": "Esto ejecuta {count} pruebas de combinaciones y puede consumir cuota del proveedor. ¿Continuar?", + "bulkConfirmStart": "Iniciar pruebas", + "errorDetail": "Detalles del error: {detail}", + "httpError": "La solicitud falló con HTTP {status}", + "testFailedNoDetail": "La prueba falló sin un mensaje de error", + "additionalCapabilities": "Capacidades adicionales: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "combos", diff --git a/src/i18n/messages/et.json b/src/i18n/messages/et.json index 08dcc987dc72..f4dea008ce44 100644 --- a/src/i18n/messages/et.json +++ b/src/i18n/messages/et.json @@ -3317,7 +3317,23 @@ "next": "Järgmine", "combo": "Kombo", "members": "Liikmed", - "moreMembers": "+{count} veel" + "moreMembers": "+{count} veel", + "minMaxOutput": "Minimaalne maksimaalne väljund", + "minMaxOutputPlaceholder": "nt 4096", + "bulkTestProgress": "Hulgitestimise edenemine", + "testingProgressModels": "Testitakse {completed}/{total} mudelit…", + "testingProgressCombos": "Testitakse {completed}/{total} kombinatsiooni…", + "testsCancelledModels": "Testid tühistati pärast {completed}/{total} mudelit", + "testsCancelledCombos": "Testid tühistati pärast {completed}/{total} kombinatsiooni", + "bulkConfirmTitle": "Kas alustada hulgitesti?", + "bulkConfirmModels": "See saadab teie teenusepakkujatele {count} mudelitesti ja võib kvooti kulutada. Kas jätkata?", + "bulkConfirmCombos": "See käitab {count} kombinatsioonitesti ja võib kulutada teenusepakkuja kvooti. Kas jätkata?", + "bulkConfirmStart": "Alusta teste", + "errorDetail": "Vea üksikasjad: {detail}", + "httpError": "Päring ebaõnnestus HTTP-staatusega {status}", + "testFailedNoDetail": "Test ebaõnnestus ilma veateateta", + "additionalCapabilities": "Täiendavad võimekused: {list}", + "comboRefMember": "Kombinatsioon → {name}" }, "combos": { "title": "Kombinatsioonid", diff --git a/src/i18n/messages/fa.json b/src/i18n/messages/fa.json index a7435baf52a1..2d10889c1711 100644 --- a/src/i18n/messages/fa.json +++ b/src/i18n/messages/fa.json @@ -3317,7 +3317,23 @@ "next": "بعدی", "combo": "ترکیب", "members": "اعضا", - "moreMembers": "+{count} مورد دیگر" + "moreMembers": "+{count} مورد دیگر", + "minMaxOutput": "حداقلِ حداکثر خروجی", + "minMaxOutputPlaceholder": "مثلاً 4096", + "bulkTestProgress": "پیشرفت آزمایش گروهی", + "testingProgressModels": "در حال آزمایش {completed} از {total} مدل…", + "testingProgressCombos": "در حال آزمایش {completed} از {total} ترکیب…", + "testsCancelledModels": "آزمایش‌ها پس از {completed} از {total} مدل لغو شدند", + "testsCancelledCombos": "آزمایش‌ها پس از {completed} از {total} ترکیب لغو شدند", + "bulkConfirmTitle": "شروع آزمایش گروهی؟", + "bulkConfirmModels": "این اقدام {count} آزمایش مدل را به ارائه‌دهندگان شما ارسال می‌کند و ممکن است از سهمیه استفاده کند. ادامه می‌دهید؟", + "bulkConfirmCombos": "این اقدام {count} آزمایش ترکیب را اجرا می‌کند و ممکن است از سهمیه ارائه‌دهنده استفاده کند. ادامه می‌دهید؟", + "bulkConfirmStart": "شروع آزمایش‌ها", + "errorDetail": "جزئیات خطا: {detail}", + "httpError": "درخواست با HTTP {status} ناموفق بود", + "testFailedNoDetail": "آزمایش بدون پیام خطا با شکست مواجه شد", + "additionalCapabilities": "قابلیت‌های اضافی: {list}", + "comboRefMember": "ترکیب → {name}" }, "combos": { "title": "ترکیبها", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index 2dd126b62874..be847cc65563 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -3317,7 +3317,23 @@ "next": "Seuraava", "combo": "Yhdistelmä", "members": "Jäsenet", - "moreMembers": "+{count} lisää" + "moreMembers": "+{count} lisää", + "minMaxOutput": "Pienin maksimituloste", + "minMaxOutputPlaceholder": "esim. 4096", + "bulkTestProgress": "Massatestauksen edistyminen", + "testingProgressModels": "Testataan {completed}/{total} mallia…", + "testingProgressCombos": "Testataan {completed}/{total} yhdistelmää…", + "testsCancelledModels": "Testit peruutettu {completed}/{total} mallin jälkeen", + "testsCancelledCombos": "Testit peruutettu {completed}/{total} yhdistelmän jälkeen", + "bulkConfirmTitle": "Aloitetaanko massatestaus?", + "bulkConfirmModels": "Tämä lähettää {count} mallitestiä palveluntarjoajillesi ja saattaa kuluttaa kiintiötä. Jatketaanko?", + "bulkConfirmCombos": "Tämä suorittaa {count} yhdistelmätestiä ja saattaa kuluttaa palveluntarjoajan kiintiötä. Jatketaanko?", + "bulkConfirmStart": "Aloita testit", + "errorDetail": "Virheen tiedot: {detail}", + "httpError": "Pyyntö epäonnistui: HTTP {status}", + "testFailedNoDetail": "Testi epäonnistui ilman virheilmoitusta", + "additionalCapabilities": "Lisäominaisuudet: {list}", + "comboRefMember": "Yhdistelmä → {name}" }, "combos": { "title": "Yhdistelmät", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 570b0a1c777b..18bbb1cf303b 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -3317,7 +3317,23 @@ "next": "Suivant", "combo": "Combo", "members": "Membres", - "moreMembers": "+{count} autres" + "moreMembers": "+{count} autres", + "minMaxOutput": "Sortie max min", + "minMaxOutputPlaceholder": "ex. 4096", + "bulkTestProgress": "Progression du test en masse", + "testingProgressModels": "Test de {completed} sur {total} modèles…", + "testingProgressCombos": "Test de {completed} sur {total} combinaisons…", + "testsCancelledModels": "Tests annulés après {completed} sur {total} modèles", + "testsCancelledCombos": "Tests annulés après {completed} sur {total} combinaisons", + "bulkConfirmTitle": "Démarrer le test en masse ?", + "bulkConfirmModels": "Cela envoie {count} tests de modèles à vos fournisseurs et peut consommer du quota. Continuer ?", + "bulkConfirmCombos": "Cela exécute {count} tests de combinaisons et peut consommer le quota du fournisseur. Continuer ?", + "bulkConfirmStart": "Démarrer les tests", + "errorDetail": "Détails de l'erreur : {detail}", + "httpError": "La requête a échoué avec HTTP {status}", + "testFailedNoDetail": "Le test a échoué sans message d'erreur", + "additionalCapabilities": "Capacités supplémentaires : {list}", + "comboRefMember": "Combinaison → {name}" }, "combos": { "title": "Combinaisons", diff --git a/src/i18n/messages/ga.json b/src/i18n/messages/ga.json index c52d808d8e78..ccf9f518c04f 100644 --- a/src/i18n/messages/ga.json +++ b/src/i18n/messages/ga.json @@ -3317,7 +3317,23 @@ "next": "Ar aghaidh", "combo": "Teaglaim", "members": "Baill", - "moreMembers": "+{count} eile" + "moreMembers": "+{count} eile", + "minMaxOutput": "Aschur uasta íosta", + "minMaxOutputPlaceholder": "m.sh. 4096", + "bulkTestProgress": "Dul chun cinn na mórthástála", + "testingProgressModels": "Ag tástáil {completed} as {total} samhail…", + "testingProgressCombos": "Ag tástáil {completed} as {total} teaglaim…", + "testsCancelledModels": "Tástálacha curtha ar ceal tar éis {completed} as {total} samhail", + "testsCancelledCombos": "Tástálacha curtha ar ceal tar éis {completed} as {total} teaglaim", + "bulkConfirmTitle": "Tosaigh mórthástáil?", + "bulkConfirmModels": "Seolann sé seo {count} tástáil samhla chuig do sholáthraithe agus d'fhéadfadh sé cuóta a úsáid. Leanúint ar aghaidh?", + "bulkConfirmCombos": "Ritheann sé seo {count} tástáil teaglaime agus d'fhéadfadh sé cuóta soláthraí a úsáid. Leanúint ar aghaidh?", + "bulkConfirmStart": "Tosaigh tástálacha", + "errorDetail": "Sonraí na hearráide: {detail}", + "httpError": "Theip ar an iarratas le HTTP {status}", + "testFailedNoDetail": "Theip ar an tástáil gan teachtaireacht earráide", + "additionalCapabilities": "Cumais bhreise: {list}", + "comboRefMember": "Teaglaim → {name}" }, "combos": { "title": "Teaglamaí", diff --git a/src/i18n/messages/gu.json b/src/i18n/messages/gu.json index 8431589cb078..bef6cdea7103 100644 --- a/src/i18n/messages/gu.json +++ b/src/i18n/messages/gu.json @@ -3317,7 +3317,23 @@ "next": "આગળનું", "combo": "કૉમ્બો", "members": "સભ્યો", - "moreMembers": "+{count} વધુ" + "moreMembers": "+{count} વધુ", + "minMaxOutput": "ન્યૂનતમ મહત્તમ આઉટપુટ", + "minMaxOutputPlaceholder": "દા.ત. 4096", + "bulkTestProgress": "બલ્ક ટેસ્ટ પ્રગતિ", + "testingProgressModels": "{total} માંથી {completed} મોડેલોનું પરીક્ષણ કરી રહ્યાં છીએ…", + "testingProgressCombos": "{total} માંથી {completed} કૉમ્બોઝનું પરીક્ષણ કરી રહ્યાં છીએ…", + "testsCancelledModels": "{total} માંથી {completed} મોડેલો પછી પરીક્ષણો રદ કરવામાં આવ્યા", + "testsCancelledCombos": "{total} માંથી {completed} કૉમ્બોઝ પછી પરીક્ષણો રદ કરવામાં આવ્યા", + "bulkConfirmTitle": "શું બલ્ક ટેસ્ટ શરૂ કરવો છે?", + "bulkConfirmModels": "આ તમારા પ્રદાતાઓને {count} મોડેલ પરીક્ષણો મોકલે છે અને ક્વોટાનો ઉપયોગ કરી શકે છે. ચાલુ રાખવું છે?", + "bulkConfirmCombos": "આ {count} કૉમ્બો પરીક્ષણો ચલાવે છે અને પ્રદાતાના ક્વોટાનો ઉપયોગ કરી શકે છે. ચાલુ રાખવું છે?", + "bulkConfirmStart": "પરીક્ષણો શરૂ કરો", + "errorDetail": "ભૂલની વિગતો: {detail}", + "httpError": "HTTP {status} સાથે વિનંતી નિષ્ફળ રહી", + "testFailedNoDetail": "ભૂલ સંદેશ વિના પરીક્ષણ નિષ્ફળ ગયું", + "additionalCapabilities": "વધારાની ક્ષમતાઓ: {list}", + "comboRefMember": "કૉમ્બો → {name}" }, "combos": { "title": "કોમ્બોઝ", diff --git a/src/i18n/messages/ha.json b/src/i18n/messages/ha.json index 5890767ad419..14c0e219d487 100644 --- a/src/i18n/messages/ha.json +++ b/src/i18n/messages/ha.json @@ -3317,7 +3317,23 @@ "next": "Na gaba", "combo": "Haɗi", "members": "Membobi", - "moreMembers": "+{count} ƙari" + "moreMembers": "+{count} ƙari", + "minMaxOutput": "Mafi ƙarancin iyakar fitarwa", + "minMaxOutputPlaceholder": "misali 4096", + "bulkTestProgress": "Ci gaban gwajin rukuni", + "testingProgressModels": "Ana gwada samfura {completed} cikin {total}…", + "testingProgressCombos": "Ana gwada haɗe-haɗe {completed} cikin {total}…", + "testsCancelledModels": "An soke gwaje-gwaje bayan samfura {completed} cikin {total}", + "testsCancelledCombos": "An soke gwaje-gwaje bayan haɗe-haɗe {completed} cikin {total}", + "bulkConfirmTitle": "Fara gwajin rukuni?", + "bulkConfirmModels": "Wannan zai aika gwajin samfuri {count} zuwa ga masu samarwa ɗinka kuma yana iya amfani da quota. Ci gaba?", + "bulkConfirmCombos": "Wannan zai gudanar da gwajin haɗe-haɗe {count} kuma yana iya amfani da quota na mai samarwa. Ci gaba?", + "bulkConfirmStart": "Fara gwaje-gwaje", + "errorDetail": "Cikakkun bayanan kuskure: {detail}", + "httpError": "Buƙata ta gaza tare da HTTP {status}", + "testFailedNoDetail": "Gwaji ya gaza ba tare da saƙon kuskure ba", + "additionalCapabilities": "Ƙarin damammaki: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Haɗe-haɗe", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index 4e56e6cc8b9c..af12bbd329ca 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -3317,7 +3317,23 @@ "next": "הבא", "combo": "שילוב", "members": "חברים", - "moreMembers": "+{count} נוספים" + "moreMembers": "+{count} נוספים", + "minMaxOutput": "מינימום פלט מרבי", + "minMaxOutputPlaceholder": "למשל, 4096", + "bulkTestProgress": "התקדמות בדיקה מרוכזת", + "testingProgressModels": "בודק {completed} מתוך {total} מודלים…", + "testingProgressCombos": "בודק {completed} מתוך {total} שילובים…", + "testsCancelledModels": "הבדיקות בוטלו לאחר {completed} מתוך {total} מודלים", + "testsCancelledCombos": "הבדיקות בוטלו לאחר {completed} מתוך {total} שילובים", + "bulkConfirmTitle": "להתחיל בדיקה מרוכזת?", + "bulkConfirmModels": "פעולה זו שולחת {count} בדיקות מודל לספקים שלך ועשויה לנצל מכסה. להמשיך?", + "bulkConfirmCombos": "פעולה זו מריצה {count} בדיקות שילוב ועשויה לנצל מכסת ספק. להמשיך?", + "bulkConfirmStart": "התחלת בדיקות", + "errorDetail": "פרטי שגיאה: {detail}", + "httpError": "הבקשה נכשלה עם HTTP {status}", + "testFailedNoDetail": "הבדיקה נכשלה ללא הודעת שגיאה", + "additionalCapabilities": "יכולות נוספות: {list}", + "comboRefMember": "שילוב → {name}" }, "combos": { "title": "שילובים", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index d08230af4506..adc2728b80b6 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -3317,7 +3317,23 @@ "next": "अगला", "combo": "कॉम्बो", "members": "सदस्य", - "moreMembers": "+{count} और" + "moreMembers": "+{count} और", + "minMaxOutput": "न्यूनतम अधिकतम आउटपुट", + "minMaxOutputPlaceholder": "उदा. 4096", + "bulkTestProgress": "बल्क परीक्षण प्रगति", + "testingProgressModels": "{total} में से {completed} मॉडल्स का परीक्षण किया जा रहा है…", + "testingProgressCombos": "{total} में से {completed} कॉम्बो का परीक्षण किया जा रहा है…", + "testsCancelledModels": "{total} में से {completed} मॉडल्स के बाद परीक्षण रद्द कर दिए गए", + "testsCancelledCombos": "{total} में से {completed} कॉम्बो के बाद परीक्षण रद्द कर दिए गए", + "bulkConfirmTitle": "बल्क परीक्षण शुरू करें?", + "bulkConfirmModels": "यह आपके providers को {count} मॉडल परीक्षण भेजता है और इससे quota का उपयोग हो सकता है। जारी रखें?", + "bulkConfirmCombos": "यह {count} कॉम्बो परीक्षण चलाता है और इससे provider quota का उपयोग हो सकता है। जारी रखें?", + "bulkConfirmStart": "परीक्षण शुरू करें", + "errorDetail": "त्रुटि विवरण: {detail}", + "httpError": "अनुरोध HTTP {status} के साथ विफल रहा", + "testFailedNoDetail": "बिना किसी त्रुटि संदेश के परीक्षण विफल रहा", + "additionalCapabilities": "अतिरिक्त क्षमताएं: {list}", + "comboRefMember": "कॉम्बो → {name}" }, "combos": { "title": "संयोजन", diff --git a/src/i18n/messages/hr.json b/src/i18n/messages/hr.json index e722306039a0..aef379881e9f 100644 --- a/src/i18n/messages/hr.json +++ b/src/i18n/messages/hr.json @@ -3317,7 +3317,23 @@ "next": "Sljedeće", "combo": "Kombinacija", "members": "Članovi", - "moreMembers": "+{count} više" + "moreMembers": "+{count} više", + "minMaxOutput": "Minimalni maksimalni izlaz", + "minMaxOutputPlaceholder": "npr. 4096", + "bulkTestProgress": "Napredak masovnog testiranja", + "testingProgressModels": "Testiranje {completed} od {total} modela…", + "testingProgressCombos": "Testiranje {completed} od {total} kombinacija…", + "testsCancelledModels": "Testovi su otkazani nakon {completed} od {total} modela", + "testsCancelledCombos": "Testovi su otkazani nakon {completed} od {total} kombinacija", + "bulkConfirmTitle": "Pokrenuti masovno testiranje?", + "bulkConfirmModels": "Ovo šalje {count} testova modela vašim pružateljima usluga i može potrošiti kvotu. Nastaviti?", + "bulkConfirmCombos": "Ovo pokreće {count} testova kombinacija i može potrošiti kvotu pružatelja usluga. Nastaviti?", + "bulkConfirmStart": "Pokreni testove", + "errorDetail": "Pojedinosti o pogrešci: {detail}", + "httpError": "Zahtjev nije uspio uz HTTP {status}", + "testFailedNoDetail": "Test nije uspio bez poruke o pogrešci", + "additionalCapabilities": "Dodatne mogućnosti: {list}", + "comboRefMember": "Kombinacija → {name}" }, "combos": { "title": "Kombinacije", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index efa5d7d025d7..a35d5ab38c8d 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -3317,7 +3317,23 @@ "next": "Következő", "combo": "Kombináció", "members": "Tagok", - "moreMembers": "+{count} további" + "moreMembers": "+{count} további", + "minMaxOutput": "Min. maximális kimenet", + "minMaxOutputPlaceholder": "pl. 4096", + "bulkTestProgress": "Tömeges tesztelés folyamata", + "testingProgressModels": "{completed} / {total} modell tesztelése…", + "testingProgressCombos": "{completed} / {total} kombináció tesztelése…", + "testsCancelledModels": "A tesztek megszakítva {completed} / {total} modell után", + "testsCancelledCombos": "A tesztek megszakítva {completed} / {total} kombináció után", + "bulkConfirmTitle": "Elindítja a tömeges tesztet?", + "bulkConfirmModels": "Ez {count} modelltesztet küld a szolgáltatóknak, és kvótát használhat fel. Folytatja?", + "bulkConfirmCombos": "Ez {count} kombinációs tesztet futtat, és szolgáltatói kvótát használhat fel. Folytatja?", + "bulkConfirmStart": "Tesztek indítása", + "errorDetail": "Hiba részletei: {detail}", + "httpError": "A kérés meghiúsult HTTP {status} hibakóddal", + "testFailedNoDetail": "A teszt hibaüzenet nélkül hiúsult meg", + "additionalCapabilities": "További képességek: {list}", + "comboRefMember": "Kombináció → {name}" }, "combos": { "title": "Kombók", diff --git a/src/i18n/messages/hy.json b/src/i18n/messages/hy.json index f1f7466e848d..4c6794886c83 100644 --- a/src/i18n/messages/hy.json +++ b/src/i18n/messages/hy.json @@ -3317,7 +3317,23 @@ "next": "Հաջորդ", "combo": "Համադրություն", "members": "Անդամներ", - "moreMembers": "+{count} ավելին" + "moreMembers": "+{count} ավելին", + "minMaxOutput": "Նվազագույն առավելագույն ելք", + "minMaxOutputPlaceholder": "օր․՝ 4096", + "bulkTestProgress": "Զանգվածային թեստավորման ընթացքը", + "testingProgressModels": "Թեստավորվում է {total} մոդելից {completed}-ը…", + "testingProgressCombos": "Թեստավորվում է {total} համակցությունից {completed}-ը…", + "testsCancelledModels": "Թեստերը չեղարկվել են {total} մոդելից {completed}-ից հետո", + "testsCancelledCombos": "Թեստերը չեղարկվել են {total} համակցությունից {completed}-ից հետո", + "bulkConfirmTitle": "Սկսե՞լ զանգվածային թեստավորումը։", + "bulkConfirmModels": "Սա կուղարկի մոդելի {count} թեստ ձեր մատակարարներին և կարող է ծախսել քվոտա։ Շարունակե՞լ։", + "bulkConfirmCombos": "Սա կգործարկի համակցության {count} թեստ և կարող է ծախսել մատակարարի քվոտա։ Շարունակե՞լ։", + "bulkConfirmStart": "Սկսել թեստերը", + "errorDetail": "Սխալի մանրամասներ՝ {detail}", + "httpError": "Հարցումը ձախողվեց HTTP {status} կոդով", + "testFailedNoDetail": "Թեստը ձախողվեց առանց սխալի հաղորդագրության", + "additionalCapabilities": "Լրացուցիչ հնարավորություններ՝ {list}", + "comboRefMember": "Համակցություն → {name}" }, "combos": { "title": "Կոմբինացիաներ", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index 3ed745bf1f60..298a788bb09f 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -3317,7 +3317,23 @@ "next": "Berikutnya", "combo": "Kombo", "members": "Anggota", - "moreMembers": "+{count} lagi" + "moreMembers": "+{count} lagi", + "minMaxOutput": "Output maks minimum", + "minMaxOutputPlaceholder": "cth. 4096", + "bulkTestProgress": "Progres pengujian massal", + "testingProgressModels": "Menguji {completed} dari {total} model…", + "testingProgressCombos": "Menguji {completed} dari {total} kombo…", + "testsCancelledModels": "Pengujian dibatalkan setelah {completed} dari {total} model", + "testsCancelledCombos": "Pengujian dibatalkan setelah {completed} dari {total} kombo", + "bulkConfirmTitle": "Mulai pengujian massal?", + "bulkConfirmModels": "Ini akan mengirimkan {count} pengujian model ke penyedia Anda dan dapat menggunakan kuota. Lanjutkan?", + "bulkConfirmCombos": "Ini akan menjalankan {count} pengujian kombo dan dapat menggunakan kuota penyedia. Lanjutkan?", + "bulkConfirmStart": "Mulai pengujian", + "errorDetail": "Detail kesalahan: {detail}", + "httpError": "Permintaan gagal dengan HTTP {status}", + "testFailedNoDetail": "Pengujian gagal tanpa pesan kesalahan", + "additionalCapabilities": "Kemampuan tambahan: {list}", + "comboRefMember": "Kombo → {name}" }, "combos": { "title": "kombo", diff --git a/src/i18n/messages/ig.json b/src/i18n/messages/ig.json index e2c29628aff9..49a10c636904 100644 --- a/src/i18n/messages/ig.json +++ b/src/i18n/messages/ig.json @@ -3317,7 +3317,23 @@ "next": "Na-esote", "combo": "Ngwakọta", "members": "Ndị otu", - "moreMembers": "+{count} ọzọ" + "moreMembers": "+{count} ọzọ", + "minMaxOutput": "Mmepụta kacha nta na kacha elu", + "minMaxOutputPlaceholder": "d.k. 4096", + "bulkTestProgress": "Ọganihu nnwale n'ogbe", + "testingProgressModels": "Na-anwale {completed} n'ime ụdị {total}…", + "testingProgressCombos": "Na-anwale {completed} n'ime ngwakọta {total}…", + "testsCancelledModels": "A kagburu nnwale mgbe {completed} n'ime ụdị {total} gasịrị", + "testsCancelledCombos": "A kagburu nnwale mgbe {completed} n'ime ngwakọta {total} gasịrị", + "bulkConfirmTitle": "Bido nnwale n'ogbe?", + "bulkConfirmModels": "Nke a na-eziga ule ụdị {count} nye ndị na-eweta ọrụ gị ma nwee ike iji quota. Gaa n'ihu?", + "bulkConfirmCombos": "Nke a na-agba ule ngwakọta {count} ma nwee ike iji quota onye na-eweta ọrụ. Gaa n'ihu?", + "bulkConfirmStart": "Bido nnwale", + "errorDetail": "Nkọwa njehie: {detail}", + "httpError": "Arịrịọ dara na HTTP {status}", + "testFailedNoDetail": "Nnwale dara na-enweghị ozi njehie", + "additionalCapabilities": "Ikike ndị ọzọ: {list}", + "comboRefMember": "Ngwakọta → {name}" }, "combos": { "title": "Ngwakọta", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 29cc1819c40b..41e0460d3924 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -3317,7 +3317,23 @@ "next": "Successivo", "combo": "Combo", "members": "Membri", - "moreMembers": "+{count} altri" + "moreMembers": "+{count} altri", + "minMaxOutput": "Min output massimo", + "minMaxOutputPlaceholder": "es. 4096", + "bulkTestProgress": "Avanzamento test in blocco", + "testingProgressModels": "Test di {completed} su {total} modelli…", + "testingProgressCombos": "Test di {completed} su {total} combinazioni…", + "testsCancelledModels": "Test annullati dopo {completed} su {total} modelli", + "testsCancelledCombos": "Test annullati dopo {completed} su {total} combinazioni", + "bulkConfirmTitle": "Avviare il test in blocco?", + "bulkConfirmModels": "Questa operazione invia {count} test di modelli ai tuoi provider e potrebbe consumare quota. Continuare?", + "bulkConfirmCombos": "Questa operazione esegue {count} test di combinazioni e potrebbe consumare quota del provider. Continuare?", + "bulkConfirmStart": "Avvia test", + "errorDetail": "Dettagli errore: {detail}", + "httpError": "Richiesta non riuscita con HTTP {status}", + "testFailedNoDetail": "Test non riuscito senza un messaggio di errore", + "additionalCapabilities": "Funzionalità aggiuntive: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combinazioni", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index 3ba9d1a13a39..7cd6acdebc1c 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -3317,7 +3317,23 @@ "next": "次へ", "combo": "コンボ", "members": "メンバー", - "moreMembers": "+{count} 件" + "moreMembers": "+{count} 件", + "minMaxOutput": "最小最大出力", + "minMaxOutputPlaceholder": "例: 4096", + "bulkTestProgress": "一括テストの進捗", + "testingProgressModels": "{total} 件中 {completed} 件のモデルをテスト中…", + "testingProgressCombos": "{total} 件中 {completed} 件のコンボをテスト中…", + "testsCancelledModels": "{total} 件中 {completed} 件のモデルをテスト後にキャンセルされました", + "testsCancelledCombos": "{total} 件中 {completed} 件のコンボをテスト後にキャンセルされました", + "bulkConfirmTitle": "一括テストを開始しますか?", + "bulkConfirmModels": "これにより、プロバイダーに {count} 件のモデルテストが送信され、クォータを消費する可能性があります。続行しますか?", + "bulkConfirmCombos": "これにより、{count} 件のコンボテストが実行され、プロバイダーのクォータを消費する可能性があります。続行しますか?", + "bulkConfirmStart": "テストを開始", + "errorDetail": "エラー詳細: {detail}", + "httpError": "HTTP {status} でリクエストが失敗しました", + "testFailedNoDetail": "エラーメッセージなしでテストが失敗しました", + "additionalCapabilities": "追加機能: {list}", + "comboRefMember": "コンボ → {name}" }, "combos": { "title": "コンボ", diff --git a/src/i18n/messages/ka.json b/src/i18n/messages/ka.json index 7303a0e8d65b..69e7633cc0df 100644 --- a/src/i18n/messages/ka.json +++ b/src/i18n/messages/ka.json @@ -3317,7 +3317,23 @@ "next": "შემდეგი", "combo": "კომბინაცია", "members": "წევრები", - "moreMembers": "კიდევ +{count}" + "moreMembers": "კიდევ +{count}", + "minMaxOutput": "მინიმალური მაქსიმალური გამოტანა", + "minMaxOutputPlaceholder": "მაგ. 4096", + "bulkTestProgress": "მასობრივი ტესტირების პროგრესი", + "testingProgressModels": "მიმდინარეობს {total}-დან {completed} მოდელის ტესტირება…", + "testingProgressCombos": "მიმდინარეობს {total}-დან {completed} კომბინაციის ტესტირება…", + "testsCancelledModels": "ტესტები გაუქმდა {total}-დან {completed} მოდელის შემდეგ", + "testsCancelledCombos": "ტესტები გაუქმდა {total}-დან {completed} კომბინაციის შემდეგ", + "bulkConfirmTitle": "დაიწყოს მასობრივი ტესტირება?", + "bulkConfirmModels": "ეს გააგზავნის {count} მოდელის ტესტს თქვენს პროვაიდერებთან და შესაძლოა გამოიყენოს კვოტა. გსურთ გაგრძელება?", + "bulkConfirmCombos": "ეს გაუშვებს {count} კომბინაციის ტესტს და შესაძლოა გამოიყენოს პროვაიდერის კვოტა. გსურთ გაგრძელება?", + "bulkConfirmStart": "ტესტების დაწყება", + "errorDetail": "შეცდომის დეტალები: {detail}", + "httpError": "მოთხოვნა ვერ შესრულდა HTTP {status} სტატუსით", + "testFailedNoDetail": "ტესტი ჩაიშალა შეცდომის შეტყობინების გარეშე", + "additionalCapabilities": "დამატებითი შესაძლებლობები: {list}", + "comboRefMember": "კომბინაცია → {name}" }, "combos": { "title": "კომბინაციები", diff --git a/src/i18n/messages/km.json b/src/i18n/messages/km.json index fdb77e4287b8..f84061f14505 100644 --- a/src/i18n/messages/km.json +++ b/src/i18n/messages/km.json @@ -3317,7 +3317,23 @@ "next": "បន្ទាប់", "combo": "បន្សំ", "members": "សមាជិក", - "moreMembers": "+{count} ទៀត" + "moreMembers": "+{count} ទៀត", + "minMaxOutput": "ទិន្នផលអតិបរមាអប្បបរមា", + "minMaxOutputPlaceholder": "ឧ. 4096", + "bulkTestProgress": "វឌ្ឍនភាពនៃការធ្វើតេស្តជាបាច់", + "testingProgressModels": "កំពុងធ្វើតេស្ត {completed} នៃ {total} ម៉ូឌែល…", + "testingProgressCombos": "កំពុងធ្វើតេស្ត {completed} នៃ {total} បន្សំ…", + "testsCancelledModels": "ការធ្វើតេស្តត្រូវបានបោះបង់បន្ទាប់ពី {completed} នៃ {total} ម៉ូឌែល", + "testsCancelledCombos": "ការធ្វើតេស្តត្រូវបានបោះបង់បន្ទាប់ពី {completed} នៃ {total} បន្សំ", + "bulkConfirmTitle": "ចាប់ផ្តើមការធ្វើតេស្តជាបាច់?", + "bulkConfirmModels": "ដំណើរការនេះនឹងផ្ញើការធ្វើតេស្តម៉ូឌែលចំនួន {count} ទៅកាន់ providers របស់អ្នក ហើយអាចនឹងប្រើប្រាស់កូតា។ បន្តដែរឬទេ?", + "bulkConfirmCombos": "ដំណើរការនេះនឹងដំណើរការការធ្វើតេស្តបន្សំចំនួន {count} ហើយអាចនឹងប្រើប្រាស់កូតារបស់ provider។ បន្តដែរឬទេ?", + "bulkConfirmStart": "ចាប់ផ្តើមការធ្វើតេស្ត", + "errorDetail": "ព័ត៌មានលម្អិតអំពីកំហុស៖ {detail}", + "httpError": "សំណើបានបរាជ័យជាមួយ HTTP {status}", + "testFailedNoDetail": "ការធ្វើតេស្តបានបរាជ័យដោយគ្មានសារកំហុស", + "additionalCapabilities": "សមត្ថភាពបន្ថែម៖ {list}", + "comboRefMember": "បន្សំ → {name}" }, "combos": { "title": "បន្សំ", diff --git a/src/i18n/messages/kn.json b/src/i18n/messages/kn.json index ee1d2018d643..dafd3baedd62 100644 --- a/src/i18n/messages/kn.json +++ b/src/i18n/messages/kn.json @@ -3317,7 +3317,23 @@ "next": "ಮುಂದಿನದು", "combo": "ಕಾಂಬೋ", "members": "ಸದಸ್ಯರು", - "moreMembers": "+{count} ಇನ್ನಷ್ಟು" + "moreMembers": "+{count} ಇನ್ನಷ್ಟು", + "minMaxOutput": "ಕನಿಷ್ಠ ಗರಿಷ್ಠ ಔಟ್‌ಪುಟ್", + "minMaxOutputPlaceholder": "ಉದಾ: 4096", + "bulkTestProgress": "ಬಲ್ಕ್ ಪರೀಕ್ಷೆಯ ಪ್ರಗತಿ", + "testingProgressModels": "{total} ಮಾದರಿಗಳಲ್ಲಿ {completed} ಪರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ…", + "testingProgressCombos": "{total} ಕಾಂಬೊಗಳಲ್ಲಿ {completed} ಪರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ…", + "testsCancelledModels": "{total} ಮಾದರಿಗಳಲ್ಲಿ {completed} ನಂತರ ಪರೀಕ್ಷೆಗಳನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ", + "testsCancelledCombos": "{total} ಕಾಂಬೊಗಳಲ್ಲಿ {completed} ನಂತರ ಪರೀಕ್ಷೆಗಳನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ", + "bulkConfirmTitle": "ಬಲ್ಕ್ ಪರೀಕ್ಷೆಯನ್ನು ಪ್ರಾರಂಭಿಸುವುದೇ?", + "bulkConfirmModels": "ಇದು ನಿಮ್ಮ ಪ್ರೊವೈಡರ್‌ಗಳಿಗೆ {count} ಮಾದರಿ ಪರೀಕ್ಷೆಗಳನ್ನು ಕಳುಹಿಸುತ್ತದೆ ಮತ್ತು ಕೋಟಾವನ್ನು ಬಳಸಬಹುದು. ಮುಂದುವರಿಸುವುದೇ?", + "bulkConfirmCombos": "ಇದು {count} ಕಾಂಬೊ ಪರೀಕ್ಷೆಗಳನ್ನು ಚಲಾಯಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರೊವೈಡರ್ ಕೋಟಾವನ್ನು ಬಳಸಬಹುದು. ಮುಂದುವರಿಸುವುದೇ?", + "bulkConfirmStart": "ಪರೀಕ್ಷೆಗಳನ್ನು ಪ್ರಾರಂಭಿಸಿ", + "errorDetail": "ದೋಷದ ವಿವರಗಳು: {detail}", + "httpError": "ವಿನಂತಿಯು HTTP {status} ನೊಂದಿಗೆ ವಿಫಲವಾಗಿದೆ", + "testFailedNoDetail": "ಯಾವುದೇ ದೋಷ ಸಂದೇಶವಿಲ್ಲದೆ ಪರೀಕ್ಷೆ ವಿಫಲವಾಗಿದೆ", + "additionalCapabilities": "ಹೆಚ್ಚುವರಿ ಸಾಮರ್ಥ್ಯಗಳು: {list}", + "comboRefMember": "ಕಾಂಬೊ → {name}" }, "combos": { "title": "ಸಂಯೋಜನೆಗಳು", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index a4e1c951a0dd..de86d1701059 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -3317,7 +3317,23 @@ "next": "다음", "combo": "콤보", "members": "멤버", - "moreMembers": "+{count}개 더 보기" + "moreMembers": "+{count}개 더 보기", + "minMaxOutput": "최소 최대 출력", + "minMaxOutputPlaceholder": "예: 4096", + "bulkTestProgress": "일괄 테스트 진행 상황", + "testingProgressModels": "{total}개 중 {completed}개 모델 테스트 중…", + "testingProgressCombos": "{total}개 중 {completed}개 조합 테스트 중…", + "testsCancelledModels": "{total}개 중 {completed}개 모델 테스트 후 취소됨", + "testsCancelledCombos": "{total}개 중 {completed}개 조합 테스트 후 취소됨", + "bulkConfirmTitle": "일괄 테스트를 시작하시겠습니까?", + "bulkConfirmModels": "공급자에게 {count}개의 모델 테스트를 전송하며 쿼터가 소모될 수 있습니다. 계속하시겠습니까?", + "bulkConfirmCombos": "{count}개의 조합 테스트를 실행하며 공급자 쿼터가 소모될 수 있습니다. 계속하시겠습니까?", + "bulkConfirmStart": "테스트 시작", + "errorDetail": "오류 세부 정보: {detail}", + "httpError": "HTTP {status} 오류로 요청 실패", + "testFailedNoDetail": "오류 메시지 없이 테스트 실패", + "additionalCapabilities": "추가 기능: {list}", + "comboRefMember": "조합 → {name}" }, "combos": { "title": "콤보", diff --git a/src/i18n/messages/lt.json b/src/i18n/messages/lt.json index fc2f8668a215..eaddf05ccd83 100644 --- a/src/i18n/messages/lt.json +++ b/src/i18n/messages/lt.json @@ -3317,7 +3317,23 @@ "next": "Kitas", "combo": "Kombinacija", "members": "Nariai", - "moreMembers": "+dar {count}" + "moreMembers": "+dar {count}", + "minMaxOutput": "Minimali maksimali išvestis", + "minMaxOutputPlaceholder": "pvz., 4096", + "bulkTestProgress": "Masinio testavimo eiga", + "testingProgressModels": "Testuojama {completed} iš {total} modelių…", + "testingProgressCombos": "Testuojama {completed} iš {total} derinių…", + "testsCancelledModels": "Testai atšaukti patikrinus {completed} iš {total} modelių", + "testsCancelledCombos": "Testai atšaukti patikrinus {completed} iš {total} derinių", + "bulkConfirmTitle": "Pradėti masinį testavimą?", + "bulkConfirmModels": "Tai išsiųs {count} modelių testus jūsų teikėjams ir gali sunaudoti kvotą. Tęsti?", + "bulkConfirmCombos": "Tai paleis {count} derinių testus ir gali sunaudoti teikėjo kvotą. Tęsti?", + "bulkConfirmStart": "Pradėti testus", + "errorDetail": "Klaidos informacija: {detail}", + "httpError": "Užklausa nepavyko su HTTP {status}", + "testFailedNoDetail": "Testas nepavyko be klaidos pranešimo", + "additionalCapabilities": "Papildomos galimybės: {list}", + "comboRefMember": "Derinys → {name}" }, "combos": { "title": "Kombinacijos", diff --git a/src/i18n/messages/lv.json b/src/i18n/messages/lv.json index 678c77f63bea..933a35aee9cb 100644 --- a/src/i18n/messages/lv.json +++ b/src/i18n/messages/lv.json @@ -3317,7 +3317,23 @@ "next": "Nākamā", "combo": "Kombinācija", "members": "Dalībnieki", - "moreMembers": "+vēl {count}" + "moreMembers": "+vēl {count}", + "minMaxOutput": "Minimālā maksimālā izvade", + "minMaxOutputPlaceholder": "piem., 4096", + "bulkTestProgress": "Masveida testa progress", + "testingProgressModels": "Testē {completed} no {total} modeļiem…", + "testingProgressCombos": "Testē {completed} no {total} kombinācijām…", + "testsCancelledModels": "Testi atcelti pēc {completed} no {total} modeļiem", + "testsCancelledCombos": "Testi atcelti pēc {completed} no {total} kombinācijām", + "bulkConfirmTitle": "Sākt masveida testu?", + "bulkConfirmModels": "Tas nosūtīs {count} modeļu testus jūsu pakalpojumu sniedzējiem un var izmantot kvotu. Vai turpināt?", + "bulkConfirmCombos": "Tas palaidīs {count} kombināciju testus un var izmantot pakalpojumu sniedzēja kvotu. Vai turpināt?", + "bulkConfirmStart": "Sākt testus", + "errorDetail": "Kļūdas informācija: {detail}", + "httpError": "Pieprasījums neizdevās ar HTTP {status}", + "testFailedNoDetail": "Tests neizdevās bez kļūdas ziņojuma", + "additionalCapabilities": "Papildu iespējas: {list}", + "comboRefMember": "Kombinācija → {name}" }, "combos": { "title": "Kombinācijas", diff --git a/src/i18n/messages/ml.json b/src/i18n/messages/ml.json index b6cb335739d5..58655495176c 100644 --- a/src/i18n/messages/ml.json +++ b/src/i18n/messages/ml.json @@ -3317,7 +3317,23 @@ "next": "അടുത്തത്", "combo": "കോമ്പോ", "members": "അംഗങ്ങൾ", - "moreMembers": "+{count} കൂടി" + "moreMembers": "+{count} കൂടി", + "minMaxOutput": "മിനിമം പരമാവധി ഔട്ട്പുട്ട്", + "minMaxOutputPlaceholder": "ഉദാ. 4096", + "bulkTestProgress": "ബൾക്ക് ടെസ്റ്റ് പുരോഗതി", + "testingProgressModels": "{total} മോഡലുകളിൽ {completed} എണ്ണം പരിശോധിക്കുന്നു…", + "testingProgressCombos": "{total} കോമ്പോകളിൽ {completed} എണ്ണം പരിശോധിക്കുന്നു…", + "testsCancelledModels": "{total} മോഡലുകളിൽ {completed} എണ്ണത്തിന് ശേഷം ടെസ്റ്റുകൾ റദ്ദാക്കി", + "testsCancelledCombos": "{total} കോമ്പോകളിൽ {completed} എണ്ണത്തിന് ശേഷം ടെസ്റ്റുകൾ റദ്ദാക്കി", + "bulkConfirmTitle": "ബൾക്ക് ടെസ്റ്റ് ആരംഭിക്കണോ?", + "bulkConfirmModels": "ഇത് നിങ്ങളുടെ പ്രൊവൈഡർമാർക്ക് {count} മോഡൽ ടെസ്റ്റുകൾ അയയ്ക്കുകയും ക്വാട്ട ഉപയോഗിക്കുകയും ചെയ്തേക്കാം. തുടരണോ?", + "bulkConfirmCombos": "ഇത് {count} കോമ്പോ ടെസ്റ്റുകൾ റൺ ചെയ്യുകയും പ്രൊവൈഡർ ക്വാട്ട ഉപയോഗിക്കുകയും ചെയ്തേക്കാം. തുടരണോ?", + "bulkConfirmStart": "ടെസ്റ്റുകൾ ആരംഭിക്കുക", + "errorDetail": "പിശക് വിവരങ്ങൾ: {detail}", + "httpError": "HTTP {status} സഹിതം അഭ്യർത്ഥന പരാജയപ്പെട്ടു", + "testFailedNoDetail": "പിശക് സന്ദേശമൊന്നുമില്ലാതെ ടെസ്റ്റ് പരാജയപ്പെട്ടു", + "additionalCapabilities": "അധിക ശേഷികൾ: {list}", + "comboRefMember": "കോമ്പോ → {name}" }, "combos": { "title": "കോംബോകൾ", diff --git a/src/i18n/messages/mr.json b/src/i18n/messages/mr.json index 7e5e88bebbb1..07a8627e65d1 100644 --- a/src/i18n/messages/mr.json +++ b/src/i18n/messages/mr.json @@ -3317,7 +3317,23 @@ "next": "पुढील", "combo": "कॉम्बो", "members": "सदस्य", - "moreMembers": "+{count} आणखी" + "moreMembers": "+{count} आणखी", + "minMaxOutput": "किमान कमाल आउटपुट", + "minMaxOutputPlaceholder": "उदा. 4096", + "bulkTestProgress": "बल्क चाचणी प्रगती", + "testingProgressModels": "{total} पैकी {completed} मॉडेल्सची चाचणी सुरू आहे…", + "testingProgressCombos": "{total} पैकी {completed} कॉम्बोची चाचणी सुरू आहे…", + "testsCancelledModels": "{total} पैकी {completed} मॉडेल्सनंतर चाचण्या रद्द केल्या", + "testsCancelledCombos": "{total} पैकी {completed} कॉम्बोनंतर चाचण्या रद्द केल्या", + "bulkConfirmTitle": "बल्क चाचणी सुरू करायची?", + "bulkConfirmModels": "हे तुमच्या प्रोव्हायडर्सना {count} मॉडेल चाचण्या पाठवते आणि कोटा वापरू शकते. सुरू ठेवायचे?", + "bulkConfirmCombos": "हे {count} कॉम्बो चाचण्या चालवते आणि प्रोव्हायडर कोटा वापरू शकते. सुरू ठेवायचे?", + "bulkConfirmStart": "चाचण्या सुरू करा", + "errorDetail": "त्रुटी तपशील: {detail}", + "httpError": "HTTP {status} सह विनंती अयशस्वी झाली", + "testFailedNoDetail": "त्रुटी संदेशाशिवाय चाचणी अयशस्वी झाली", + "additionalCapabilities": "अतिरिक्त क्षमता: {list}", + "comboRefMember": "कॉम्बो → {name}" }, "combos": { "title": "कॉम्बोज", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index 7d687c5be277..138f50152e92 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -3317,7 +3317,23 @@ "next": "Seterusnya", "combo": "Kombo", "members": "Ahli", - "moreMembers": "+{count} lagi" + "moreMembers": "+{count} lagi", + "minMaxOutput": "Min output maksimum", + "minMaxOutputPlaceholder": "cth. 4096", + "bulkTestProgress": "Kemajuan ujian pukal", + "testingProgressModels": "Menguji {completed} daripada {total} model…", + "testingProgressCombos": "Menguji {completed} daripada {total} kombo…", + "testsCancelledModels": "Ujian dibatalkan selepas {completed} daripada {total} model", + "testsCancelledCombos": "Ujian dibatalkan selepas {completed} daripada {total} kombo", + "bulkConfirmTitle": "Mulakan ujian pukal?", + "bulkConfirmModels": "Ini menghantar {count} ujian model kepada penyedia anda dan mungkin menggunakan kuota. Teruskan?", + "bulkConfirmCombos": "Ini menjalankan {count} ujian kombo dan mungkin menggunakan kuota penyedia. Teruskan?", + "bulkConfirmStart": "Mulakan ujian", + "errorDetail": "Butiran ralat: {detail}", + "httpError": "Permintaan gagal dengan HTTP {status}", + "testFailedNoDetail": "Ujian gagal tanpa mesej ralat", + "additionalCapabilities": "Keupayaan tambahan: {list}", + "comboRefMember": "Kombo → {name}" }, "combos": { "title": "Kombo", diff --git a/src/i18n/messages/mt.json b/src/i18n/messages/mt.json index 6181a0a865a6..673945690998 100644 --- a/src/i18n/messages/mt.json +++ b/src/i18n/messages/mt.json @@ -3317,7 +3317,23 @@ "next": "Li jmiss", "combo": "Combo", "members": "Membri", - "moreMembers": "+{count} oħra" + "moreMembers": "+{count} oħra", + "minMaxOutput": "Minimu tal-output massimu", + "minMaxOutputPlaceholder": "eż. 4096", + "bulkTestProgress": "Progress tat-testijiet bl-ingrossa", + "testingProgressModels": "Qed jiġu ttestjati {completed} minn {total} mudelli…", + "testingProgressCombos": "Qed jiġu ttestjati {completed} minn {total} combos…", + "testsCancelledModels": "Testijiet ikkanċellati wara {completed} minn {total} mudelli", + "testsCancelledCombos": "Testijiet ikkanċellati wara {completed} minn {total} combos", + "bulkConfirmTitle": "Ibda t-test bl-ingrossa?", + "bulkConfirmModels": "Dan jibgħat {count} testijiet tal-mudell lill-fornituri tiegħek u jista' juża mill-kwota. Trid tkompli?", + "bulkConfirmCombos": "Dan iħaddem {count} testijiet ta' combo u jista' juża l-kwota tal-fornitur. Trid tkompli?", + "bulkConfirmStart": "Ibda t-testijiet", + "errorDetail": "Dettalji tal-iżball: {detail}", + "httpError": "It-talba falliet b'HTTP {status}", + "testFailedNoDetail": "It-test falla mingħajr messaġġ ta' żball", + "additionalCapabilities": "Kapaċitajiet addizzjonali: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Kombinazzjonijiet", diff --git a/src/i18n/messages/my.json b/src/i18n/messages/my.json index ea2e46ea56d9..273bd39c91fb 100644 --- a/src/i18n/messages/my.json +++ b/src/i18n/messages/my.json @@ -3317,7 +3317,23 @@ "next": "နောက်တစ်ခု", "combo": "တွဲစပ်မှု", "members": "အဖွဲ့ဝင်များ", - "moreMembers": "နောက်ထပ် +{count} ခု" + "moreMembers": "နောက်ထပ် +{count} ခု", + "minMaxOutput": "အနည်းဆုံး အများဆုံး output", + "minMaxOutputPlaceholder": "ဥပမာ - 4096", + "bulkTestProgress": "အစုလိုက် စမ်းသပ်မှု အခြေအနေ", + "testingProgressModels": "မော်ဒယ် {total} ခုအနက် {completed} ခုကို စမ်းသပ်နေသည်…", + "testingProgressCombos": "combo {total} ခုအနက် {completed} ခုကို စမ်းသပ်နေသည်…", + "testsCancelledModels": "မော်ဒယ် {total} ခုအနက် {completed} ခု စမ်းသပ်ပြီးနောက် ပယ်ဖျက်လိုက်သည်", + "testsCancelledCombos": "combo {total} ခုအနက် {completed} ခု စမ်းသပ်ပြီးနောက် ပယ်ဖျက်လိုက်သည်", + "bulkConfirmTitle": "အစုလိုက် စမ်းသပ်မှုကို စတင်မလား။", + "bulkConfirmModels": "၎င်းသည် သင်၏ provider များထံ မော်ဒယ်စမ်းသပ်မှု {count} ခုကို ပေးပို့မည်ဖြစ်ပြီး quota ကုန်ကျနိုင်ပါသည်။ ဆက်လုပ်မလား။", + "bulkConfirmCombos": "၎င်းသည် combo စမ်းသပ်မှု {count} ခုကို လုပ်ဆောင်မည်ဖြစ်ပြီး provider quota ကုန်ကျနိုင်ပါသည်။ ဆက်လုပ်မလား။", + "bulkConfirmStart": "စမ်းသပ်မှုများ စတင်ရန်", + "errorDetail": "အမှား အသေးစိတ်- {detail}", + "httpError": "တောင်းဆိုမှုသည် HTTP {status} ဖြင့် မအောင်မြင်ပါ", + "testFailedNoDetail": "အမှားသတင်းစကား မပါဘဲ စမ်းသပ်မှု မအောင်မြင်ပါ", + "additionalCapabilities": "ထပ်ဆောင်း လုပ်ဆောင်နိုင်စွမ်းများ- {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "ပေါင်းစပ်မော်ဒယ်များ", diff --git a/src/i18n/messages/ne.json b/src/i18n/messages/ne.json index bf229253e0d7..891d74e0288b 100644 --- a/src/i18n/messages/ne.json +++ b/src/i18n/messages/ne.json @@ -3317,7 +3317,23 @@ "next": "अर्को", "combo": "कम्बो", "members": "सदस्यहरू", - "moreMembers": "+{count} थप" + "moreMembers": "+{count} थप", + "minMaxOutput": "न्यूनतम अधिकतम आउटपुट", + "minMaxOutputPlaceholder": "उदाहरण: 4096", + "bulkTestProgress": "बल्क परीक्षण प्रगति", + "testingProgressModels": "{total} मध्ये {completed} मोडलहरू परीक्षण गरिँदैछ…", + "testingProgressCombos": "{total} मध्ये {completed} कम्बोहरू परीक्षण गरिँदैछ…", + "testsCancelledModels": "{total} मध्ये {completed} मोडलहरू पछि परीक्षण रद्द गरियो", + "testsCancelledCombos": "{total} मध्ये {completed} कम्बोहरू पछि परीक्षण रद्द गरियो", + "bulkConfirmTitle": "बल्क परीक्षण सुरु गर्ने?", + "bulkConfirmModels": "यसले तपाईंको प्रदायकहरूलाई {count} मोडल परीक्षणहरू पठाउँछ र कोटा प्रयोग गर्न सक्छ। जारी राख्नुहुन्छ?", + "bulkConfirmCombos": "यसले {count} कम्बो परीक्षणहरू चलाउँछ र प्रदायक कोटा प्रयोग गर्न सक्छ। जारी राख्नुहुन्छ?", + "bulkConfirmStart": "परीक्षणहरू सुरु गर्नुहोस्", + "errorDetail": "त्रुटि विवरण: {detail}", + "httpError": "HTTP {status} सँग अनुरोध असफल भयो", + "testFailedNoDetail": "कुनै त्रुटि सन्देश बिना परीक्षण असफल भयो", + "additionalCapabilities": "थप क्षमताहरू: {list}", + "comboRefMember": "कम्बो → {name}" }, "combos": { "title": "कम्बोहरू", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index f3f08cc9dd6e..b0177495c0d0 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -3317,7 +3317,23 @@ "next": "Volgende", "combo": "Combo", "members": "Leden", - "moreMembers": "+{count} meer" + "moreMembers": "+{count} meer", + "minMaxOutput": "Minimale max. uitvoer", + "minMaxOutputPlaceholder": "bijv. 4096", + "bulkTestProgress": "Voortgang bulktest", + "testingProgressModels": "{completed} van {total} modellen testen…", + "testingProgressCombos": "{completed} van {total} combo's testen…", + "testsCancelledModels": "Tests geannuleerd na {completed} van {total} modellen", + "testsCancelledCombos": "Tests geannuleerd na {completed} van {total} combo's", + "bulkConfirmTitle": "Bulktest starten?", + "bulkConfirmModels": "Dit verzendt {count} modeltests naar uw providers en kan quotum verbruiken. Doorgaan?", + "bulkConfirmCombos": "Dit voert {count} combotests uit en kan providerquotum verbruiken. Doorgaan?", + "bulkConfirmStart": "Tests starten", + "errorDetail": "Foutdetails: {detail}", + "httpError": "Verzoek mislukt met HTTP {status}", + "testFailedNoDetail": "Test mislukt zonder foutmelding", + "additionalCapabilities": "Aanvullende mogelijkheden: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combo's", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index 5424810d16ff..11f7d6c743ac 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -3317,7 +3317,23 @@ "next": "Neste", "combo": "Kombinasjon", "members": "Medlemmer", - "moreMembers": "+{count} flere" + "moreMembers": "+{count} flere", + "minMaxOutput": "Min. maks-utdata", + "minMaxOutputPlaceholder": "f.eks. 4096", + "bulkTestProgress": "Fremdrift for massetesting", + "testingProgressModels": "Tester {completed} av {total} modeller…", + "testingProgressCombos": "Tester {completed} av {total} kombinasjoner…", + "testsCancelledModels": "Tester avbrutt etter {completed} av {total} modeller", + "testsCancelledCombos": "Tester avbrutt etter {completed} av {total} kombinasjoner", + "bulkConfirmTitle": "Start massetest?", + "bulkConfirmModels": "Dette sender {count} modelltester til leverandørene dine og kan bruke kvote. Fortsette?", + "bulkConfirmCombos": "Dette kjører {count} kombinasjonstester og kan bruke leverandørkvote. Fortsette?", + "bulkConfirmStart": "Start tester", + "errorDetail": "Feildetaljer: {detail}", + "httpError": "Forespørselen mislyktes med HTTP {status}", + "testFailedNoDetail": "Testen mislyktes uten en feilmelding", + "additionalCapabilities": "Ytterligere funksjoner: {list}", + "comboRefMember": "Kombinasjon → {name}" }, "combos": { "title": "Kombinasjoner", diff --git a/src/i18n/messages/or.json b/src/i18n/messages/or.json index 00cb9111d366..e0fbc6c7d9a6 100644 --- a/src/i18n/messages/or.json +++ b/src/i18n/messages/or.json @@ -3317,7 +3317,23 @@ "next": "ପରବର୍ତ୍ତୀ", "combo": "କମ୍ବୋ", "members": "ସଦସ୍ୟ", - "moreMembers": "+{count} ଅଧିକ" + "moreMembers": "+{count} ଅଧିକ", + "minMaxOutput": "ସର୍ବନିମ୍ନ ସର୍ବାଧିକ ଆଉଟପୁଟ୍", + "minMaxOutputPlaceholder": "ଯଥା: 4096", + "bulkTestProgress": "ବଲ୍କ ପରୀକ୍ଷଣ ପ୍ରଗତି", + "testingProgressModels": "{total} ରୁ {completed} ଟି ମଡେଲ୍ ପରୀକ୍ଷା କରାଯାଉଛି…", + "testingProgressCombos": "{total} ରୁ {completed} ଟି କମ୍ବୋ ପରୀକ୍ଷା କରାଯାଉଛି…", + "testsCancelledModels": "{total} ରୁ {completed} ଟି ମଡେଲ୍ ପରେ ପରୀକ୍ଷଣ ବାତିଲ କରାଗଲା", + "testsCancelledCombos": "{total} ରୁ {completed} ଟି କମ୍ବୋ ପରେ ପରୀକ୍ଷଣ ବାତିଲ କରାଗଲା", + "bulkConfirmTitle": "ବଲ୍କ ପରୀକ୍ଷଣ ଆରମ୍ଭ କରିବେ କି?", + "bulkConfirmModels": "ଏହା ଆପଣଙ୍କ ପ୍ରଦାନକାରୀଙ୍କ ନିକଟକୁ {count} ଟି ମଡେଲ୍ ପରୀକ୍ଷଣ ପଠାଇଥାଏ ଏବଂ କୋଟା ବ୍ୟବହାର କରିପାରେ। ଆଗକୁ ବଢ଼ିବେ କି?", + "bulkConfirmCombos": "ଏହା {count} ଟି କମ୍ବୋ ପରୀକ୍ଷଣ ଚଲାଇଥାଏ ଏବଂ ପ୍ରଦାନକାରୀ କୋଟା ବ୍ୟବହାର କରିପାରେ। ଆଗକୁ ବଢ଼ିବେ କି?", + "bulkConfirmStart": "ପରୀକ୍ଷଣ ଆରମ୍ଭ କରନ୍ତୁ", + "errorDetail": "ତ୍ରୁଟି ବିବରଣୀ: {detail}", + "httpError": "HTTP {status} ସହିତ ଅନୁରୋଧ ବିଫଳ ହେଲା", + "testFailedNoDetail": "କୌଣସି ତ୍ରୁଟି ବାର୍ତ୍ତା ବିନା ପରୀକ୍ଷଣ ବିଫଳ ହେଲା", + "additionalCapabilities": "ଅତିରିକ୍ତ କ୍ଷମତା: {list}", + "comboRefMember": "କମ୍ବୋ → {name}" }, "combos": { "title": "କମ୍ବୋଗୁଡ଼ିକ", diff --git a/src/i18n/messages/pa.json b/src/i18n/messages/pa.json index 98cdc6a30038..ce2751a46307 100644 --- a/src/i18n/messages/pa.json +++ b/src/i18n/messages/pa.json @@ -3317,7 +3317,23 @@ "next": "ਅਗਲਾ", "combo": "ਕੰਬੋ", "members": "ਮੈਂਬਰ", - "moreMembers": "+{count} ਹੋਰ" + "moreMembers": "+{count} ਹੋਰ", + "minMaxOutput": "ਘੱਟੋ-ਘੱਟ ਵੱਧ ਤੋਂ ਵੱਧ ਆਉਟਪੁੱਟ", + "minMaxOutputPlaceholder": "ਜਿਵੇਂ ਕਿ 4096", + "bulkTestProgress": "ਬਲਕ ਟੈਸਟ ਦੀ ਪ੍ਰਗਤੀ", + "testingProgressModels": "{total} ਵਿੱਚੋਂ {completed} ਮਾਡਲਾਂ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…", + "testingProgressCombos": "{total} ਵਿੱਚੋਂ {completed} ਕੰਬੋਜ਼ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ…", + "testsCancelledModels": "{total} ਵਿੱਚੋਂ {completed} ਮਾਡਲਾਂ ਤੋਂ ਬਾਅਦ ਟੈਸਟ ਰੱਦ ਕੀਤੇ ਗਏ", + "testsCancelledCombos": "{total} ਵਿੱਚੋਂ {completed} ਕੰਬੋਜ਼ ਤੋਂ ਬਾਅਦ ਟੈਸਟ ਰੱਦ ਕੀਤੇ ਗਏ", + "bulkConfirmTitle": "ਕੀ ਬਲਕ ਟੈਸਟ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?", + "bulkConfirmModels": "ਇਹ ਤੁਹਾਡੇ ਪ੍ਰੋਵਾਈਡਰਾਂ ਨੂੰ {count} ਮਾਡਲ ਟੈਸਟ ਭੇਜਦਾ ਹੈ ਅਤੇ ਕੋਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦਾ ਹੈ। ਕੀ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?", + "bulkConfirmCombos": "ਇਹ {count} ਕੰਬੋ ਟੈਸਟ ਚਲਾਉਂਦਾ ਹੈ ਅਤੇ ਪ੍ਰੋਵਾਈਡਰ ਦੇ ਕੋਟੇ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦਾ ਹੈ। ਕੀ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?", + "bulkConfirmStart": "ਟੈਸਟ ਸ਼ੁਰੂ ਕਰੋ", + "errorDetail": "ਗਲਤੀ ਦੇ ਵੇਰਵੇ: {detail}", + "httpError": "HTTP {status} ਨਾਲ ਬੇਨਤੀ ਅਸਫ਼ਲ ਰਹੀ", + "testFailedNoDetail": "ਬਿਨਾਂ ਕਿਸੇ ਗਲਤੀ ਸੁਨੇਹੇ ਦੇ ਟੈਸਟ ਅਸਫ਼ਲ ਰਿਹਾ", + "additionalCapabilities": "ਵਾਧੂ ਸਮਰੱਥਾਵਾਂ: {list}", + "comboRefMember": "ਕੰਬੋ → {name}" }, "combos": { "title": "ਕੌਂਬੋ", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index b165b0d31051..3d50a1c2693a 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -3317,7 +3317,23 @@ "next": "Susunod", "combo": "Combo", "members": "Mga Miyembro", - "moreMembers": "+{count} pa" + "moreMembers": "+{count} pa", + "minMaxOutput": "Min max na output", + "minMaxOutputPlaceholder": "hal. 4096", + "bulkTestProgress": "Progreso ng maramihang pagsusuri", + "testingProgressModels": "Sinusuri ang {completed} sa {total} na mga modelo…", + "testingProgressCombos": "Sinusuri ang {completed} sa {total} na mga combo…", + "testsCancelledModels": "Kinansela ang mga pagsusuri pagkatapos ng {completed} sa {total} na mga modelo", + "testsCancelledCombos": "Kinansela ang mga pagsusuri pagkatapos ng {completed} sa {total} na mga combo", + "bulkConfirmTitle": "Simulan ang maramihang pagsusuri?", + "bulkConfirmModels": "Magpapadala ito ng {count} na pagsusuri ng modelo sa iyong mga provider at maaaring gumamit ng quota. Magpatuloy?", + "bulkConfirmCombos": "Magpapatakbo ito ng {count} na pagsusuri ng combo at maaaring gumamit ng quota ng provider. Magpatuloy?", + "bulkConfirmStart": "Simulan ang mga pagsusuri", + "errorDetail": "Mga detalye ng error: {detail}", + "httpError": "Nabigo ang kahilingan na may HTTP {status}", + "testFailedNoDetail": "Nabigo ang pagsusuri nang walang mensahe ng error", + "additionalCapabilities": "Mga karagdagang kakayahan: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Mga combo", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index 84101ecfbd1e..cbf165b72172 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -3317,7 +3317,23 @@ "next": "Następna", "combo": "Kombinacja", "members": "Członkowie", - "moreMembers": "+{count} więcej" + "moreMembers": "+{count} więcej", + "minMaxOutput": "Minimalna maks. wielkość wyjścia", + "minMaxOutputPlaceholder": "np. 4096", + "bulkTestProgress": "Postęp testu masowego", + "testingProgressModels": "Testowanie {completed} z {total} modeli…", + "testingProgressCombos": "Testowanie {completed} z {total} kombinacji…", + "testsCancelledModels": "Testy anulowane po {completed} z {total} modeli", + "testsCancelledCombos": "Testy anulowane po {completed} z {total} kombinacji", + "bulkConfirmTitle": "Rozpocząć test masowy?", + "bulkConfirmModels": "Spowoduje to wysłanie {count} testów modeli do Twoich dostawców i może zużyć limit. Kontynuować?", + "bulkConfirmCombos": "Spowoduje to uruchomienie {count} testów kombinacji i może zużyć limit dostawcy. Kontynuować?", + "bulkConfirmStart": "Rozpocznij testy", + "errorDetail": "Szczegóły błędu: {detail}", + "httpError": "Żądanie nie powiodło się z kodem HTTP {status}", + "testFailedNoDetail": "Test zakończył się niepowodzeniem bez komunikatu o błędzie", + "additionalCapabilities": "Dodatkowe możliwości: {list}", + "comboRefMember": "Kombinacja → {name}" }, "combos": { "title": "Kombinacje", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index d7ce54288d8d..b167e12070e7 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -3317,7 +3317,23 @@ "next": "Próximo", "combo": "Combo", "members": "Membros", - "moreMembers": "+{count} mais" + "moreMembers": "+{count} mais", + "minMaxOutput": "Mínimo de saída máxima", + "minMaxOutputPlaceholder": "ex.: 4096", + "bulkTestProgress": "Progresso do teste em massa", + "testingProgressModels": "Testando {completed} de {total} modelos…", + "testingProgressCombos": "Testando {completed} de {total} combos…", + "testsCancelledModels": "Testes cancelados após {completed} de {total} modelos", + "testsCancelledCombos": "Testes cancelados após {completed} de {total} combos", + "bulkConfirmTitle": "Iniciar teste em massa?", + "bulkConfirmModels": "Isso enviará {count} testes de modelo para seus provedores e poderá consumir cota. Continuar?", + "bulkConfirmCombos": "Isso executará {count} testes de combo e poderá consumir cota do provedor. Continuar?", + "bulkConfirmStart": "Iniciar testes", + "errorDetail": "Detalhes do erro: {detail}", + "httpError": "A requisição falhou com HTTP {status}", + "testFailedNoDetail": "O teste falhou sem uma mensagem de erro", + "additionalCapabilities": "Capacidades adicionais: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combinações", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index b63808884430..c4727756906b 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -3317,7 +3317,23 @@ "next": "Seguinte", "combo": "Combo", "members": "Membros", - "moreMembers": "+{count} mais" + "moreMembers": "+{count} mais", + "minMaxOutput": "Mínimo de output máximo", + "minMaxOutputPlaceholder": "ex.: 4096", + "bulkTestProgress": "Progresso do teste em massa", + "testingProgressModels": "A testar {completed} de {total} modelos…", + "testingProgressCombos": "A testar {completed} de {total} combos…", + "testsCancelledModels": "Testes cancelados após {completed} de {total} modelos", + "testsCancelledCombos": "Testes cancelados após {completed} de {total} combos", + "bulkConfirmTitle": "Iniciar teste em massa?", + "bulkConfirmModels": "Isto envia {count} testes de modelo para os seus fornecedores e pode consumir quota. Continuar?", + "bulkConfirmCombos": "Isto executa {count} testes de combo e pode consumir quota do fornecedor. Continuar?", + "bulkConfirmStart": "Iniciar testes", + "errorDetail": "Detalhes do erro: {detail}", + "httpError": "O pedido falhou com HTTP {status}", + "testFailedNoDetail": "O teste falhou sem mensagem de erro", + "additionalCapabilities": "Capacidades adicionais: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combinações", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index aebeb3bf8a5c..3fef6aa6918f 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -3317,7 +3317,23 @@ "next": "Următor", "combo": "Combinație", "members": "Membri", - "moreMembers": "+{count} în plus" + "moreMembers": "+{count} în plus", + "minMaxOutput": "Minim max output", + "minMaxOutputPlaceholder": "de ex. 4096", + "bulkTestProgress": "Progres testare în masă", + "testingProgressModels": "Se testează {completed} din {total} modele…", + "testingProgressCombos": "Se testează {completed} din {total} combinații…", + "testsCancelledModels": "Teste anulate după {completed} din {total} modele", + "testsCancelledCombos": "Teste anulate după {completed} din {total} combinații", + "bulkConfirmTitle": "Porniți testarea în masă?", + "bulkConfirmModels": "Această acțiune trimite {count} teste de model către furnizorii dvs. și poate consuma din cotă. Continuați?", + "bulkConfirmCombos": "Această acțiune rulează {count} teste de combinație și poate consuma din cota furnizorului. Continuați?", + "bulkConfirmStart": "Porniți testele", + "errorDetail": "Detalii eroare: {detail}", + "httpError": "Cererea a eșuat cu HTTP {status}", + "testFailedNoDetail": "Testul a eșuat fără un mesaj de eroare", + "additionalCapabilities": "Capabilități suplimentare: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combo-uri", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index b4abbefc0039..04b9ccb3c271 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -3317,7 +3317,23 @@ "next": "Следующая", "combo": "Комбо", "members": "Участники", - "moreMembers": "+{count} еще" + "moreMembers": "+{count} еще", + "minMaxOutput": "Мин. максимальный вывод", + "minMaxOutputPlaceholder": "напр., 4096", + "bulkTestProgress": "Ход массового тестирования", + "testingProgressModels": "Тестирование моделей: {completed} из {total}…", + "testingProgressCombos": "Тестирование комбинаций: {completed} из {total}…", + "testsCancelledModels": "Тесты отменены после {completed} из {total} моделей", + "testsCancelledCombos": "Тесты отменены после {completed} из {total} комбинаций", + "bulkConfirmTitle": "Запустить массовое тестирование?", + "bulkConfirmModels": "Будет отправлено {count} тестов моделей вашим провайдерам, что может израсходовать квоту. Продолжить?", + "bulkConfirmCombos": "Будет запущено {count} тестов комбинаций, что может израсходовать квоту провайдера. Продолжить?", + "bulkConfirmStart": "Запустить тесты", + "errorDetail": "Сведения об ошибке: {detail}", + "httpError": "Запрос завершился ошибкой HTTP {status}", + "testFailedNoDetail": "Тест завершился сбоем без сообщения об ошибке", + "additionalCapabilities": "Дополнительные возможности: {list}", + "comboRefMember": "Комбинация → {name}" }, "combos": { "title": "Комбо", diff --git a/src/i18n/messages/si.json b/src/i18n/messages/si.json index bfa87f451203..05e925fedb86 100644 --- a/src/i18n/messages/si.json +++ b/src/i18n/messages/si.json @@ -3317,7 +3317,23 @@ "next": "ඊළඟ", "combo": "සංයෝජනය", "members": "සාමාජිකයින්", - "moreMembers": "තවත් +{count} ක්" + "moreMembers": "තවත් +{count} ක්", + "minMaxOutput": "අවම උපරිම ප්‍රතිදානය", + "minMaxOutputPlaceholder": "උදා. 4096", + "bulkTestProgress": "තොග පරීක්ෂණ ප්‍රගතිය", + "testingProgressModels": "මාදිලි {total} න් {completed} ක් පරීක්ෂා කරමින් පවතී…", + "testingProgressCombos": "සංයෝජන {total} න් {completed} ක් පරීක්ෂා කරමින් පවතී…", + "testsCancelledModels": "මාදිලි {total} න් {completed} කට පසු පරීක්ෂණ අවලංගු කරන ලදී", + "testsCancelledCombos": "සංයෝජන {total} න් {completed} කට පසු පරීක්ෂණ අවලංගු කරන ලදී", + "bulkConfirmTitle": "තොග පරීක්ෂණය ආරම්භ කරන්නද?", + "bulkConfirmModels": "මෙය ඔබගේ සපයන්නන් වෙත මාදිලි පරීක්ෂණ {count} ක් යවන අතර කෝටාව භාවිත විය හැක. ඉදිරියට යන්නද?", + "bulkConfirmCombos": "මෙය සංයෝජන පරීක්ෂණ {count} ක් ධාවනය කරන අතර සපයන්නාගේ කෝටාව භාවිත විය හැක. ඉදිරියට යන්නද?", + "bulkConfirmStart": "පරීක්ෂණ ආරම්භ කරන්න", + "errorDetail": "දෝෂ විස්තර: {detail}", + "httpError": "ඉල්ලීම HTTP {status} සමඟ අසාර්ථක විය", + "testFailedNoDetail": "දෝෂ පණිවිඩයක් නොමැතිව පරීක්ෂණය අසාර්ථක විය", + "additionalCapabilities": "අමතර හැකියාවන්: {list}", + "comboRefMember": "සංයෝජනය → {name}" }, "combos": { "title": "සංයෝජන", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index a0dc242ff27a..9ef5f4dc7d9b 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -3317,7 +3317,23 @@ "next": "Nasledujúca", "combo": "Kombinácia", "members": "Členovia", - "moreMembers": "+{count} ďalších" + "moreMembers": "+{count} ďalších", + "minMaxOutput": "Min. max. výstup", + "minMaxOutputPlaceholder": "napr. 4096", + "bulkTestProgress": "Priebeh hromadného testovania", + "testingProgressModels": "Testuje sa {completed} z {total} modelov…", + "testingProgressCombos": "Testuje sa {completed} z {total} kombinácií…", + "testsCancelledModels": "Testy boli zrušené po {completed} z {total} modelov", + "testsCancelledCombos": "Testy boli zrušené po {completed} z {total} kombinácií", + "bulkConfirmTitle": "Spustiť hromadný test?", + "bulkConfirmModels": "Týmto sa odošle {count} testov modelov vašim poskytovateľom a môže dôjsť k vyčerpaniu kvóty. Pokračovať?", + "bulkConfirmCombos": "Týmto sa spustí {count} testov kombinácií a môže dôjsť k vyčerpaniu kvóty poskytovateľa. Pokračovať?", + "bulkConfirmStart": "Spustiť testy", + "errorDetail": "Podrobnosti chyby: {detail}", + "httpError": "Požiadavka zlyhala s kódom HTTP {status}", + "testFailedNoDetail": "Test zlyhal bez chybovej správy", + "additionalCapabilities": "Ďalšie schopnosti: {list}", + "comboRefMember": "Kombinácia → {name}" }, "combos": { "title": "kombá", diff --git a/src/i18n/messages/sl.json b/src/i18n/messages/sl.json index 3551b80c52b4..fcfe4f276dd3 100644 --- a/src/i18n/messages/sl.json +++ b/src/i18n/messages/sl.json @@ -3317,7 +3317,23 @@ "next": "Naslednja", "combo": "Kombinacija", "members": "Člani", - "moreMembers": "+{count} več" + "moreMembers": "+{count} več", + "minMaxOutput": "Minimalni maksimalni izhod", + "minMaxOutputPlaceholder": "npr. 4096", + "bulkTestProgress": "Napredek množičnega testiranja", + "testingProgressModels": "Testiranje {completed} od {total} modelov…", + "testingProgressCombos": "Testiranje {completed} od {total} kombinacij…", + "testsCancelledModels": "Testi preklicani po {completed} od {total} modelov", + "testsCancelledCombos": "Testi preklicani po {completed} od {total} kombinacijah", + "bulkConfirmTitle": "Začni množično testiranje?", + "bulkConfirmModels": "To bo vašim ponudnikom poslalo {count} testov modelov in lahko porabi kvoto. Želite nadaljevati?", + "bulkConfirmCombos": "To bo izvedlo {count} testov kombinacij in lahko porabi kvoto ponudnika. Želite nadaljevati?", + "bulkConfirmStart": "Začni teste", + "errorDetail": "Podrobnosti napake: {detail}", + "httpError": "Zahteva ni uspela s kodo HTTP {status}", + "testFailedNoDetail": "Test ni uspel brez sporočila o napaki", + "additionalCapabilities": "Dodatne zmožnosti: {list}", + "comboRefMember": "Kombinacija → {name}" }, "combos": { "title": "Kombinacije", diff --git a/src/i18n/messages/sr.json b/src/i18n/messages/sr.json index f3e59a889891..2649139286ba 100644 --- a/src/i18n/messages/sr.json +++ b/src/i18n/messages/sr.json @@ -3317,7 +3317,23 @@ "next": "Следећа", "combo": "Комбинација", "members": "Чланови", - "moreMembers": "+{count} још" + "moreMembers": "+{count} још", + "minMaxOutput": "Минимални максимални излаз", + "minMaxOutputPlaceholder": "нпр. 4096", + "bulkTestProgress": "Напредак групног тестирања", + "testingProgressModels": "Тестирање {completed} од {total} модела…", + "testingProgressCombos": "Тестирање {completed} од {total} комбинација…", + "testsCancelledModels": "Тестови су отказани након {completed} од {total} модела", + "testsCancelledCombos": "Тестови су отказани након {completed} од {total} комбинација", + "bulkConfirmTitle": "Покренути групни тест?", + "bulkConfirmModels": "Ово шаље {count} тестова модела вашим провајдерима и може потрошити квоту. Наставити?", + "bulkConfirmCombos": "Ово покреће {count} тестова комбинација и може потрошити квоту провајдера. Наставити?", + "bulkConfirmStart": "Покрени тестове", + "errorDetail": "Детаљи грешке: {detail}", + "httpError": "Захтев није успео уз HTTP {status}", + "testFailedNoDetail": "Тест није успео без поруке о грешци", + "additionalCapabilities": "Додатне могућности: {list}", + "comboRefMember": "Комбинација → {name}" }, "combos": { "title": "Комбинације", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 7ef7ed317f62..20eccc3a685e 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -3317,7 +3317,23 @@ "next": "Nästa", "combo": "Kombination", "members": "Medlemmar", - "moreMembers": "+{count} fler" + "moreMembers": "+{count} fler", + "minMaxOutput": "Minsta max-utdata", + "minMaxOutputPlaceholder": "t.ex. 4096", + "bulkTestProgress": "Förlopp för masstest", + "testingProgressModels": "Testar {completed} av {total} modeller…", + "testingProgressCombos": "Testar {completed} av {total} kombinationer…", + "testsCancelledModels": "Testerna avbröts efter {completed} av {total} modeller", + "testsCancelledCombos": "Testerna avbröts efter {completed} av {total} kombinationer", + "bulkConfirmTitle": "Starta masstest?", + "bulkConfirmModels": "Detta skickar {count} modelltester till dina leverantörer och kan förbruka kvot. Fortsätta?", + "bulkConfirmCombos": "Detta kör {count} kombinationstester och kan förbruka leverantörskvot. Fortsätta?", + "bulkConfirmStart": "Starta tester", + "errorDetail": "Felinformation: {detail}", + "httpError": "Förfrågan misslyckades med HTTP {status}", + "testFailedNoDetail": "Testet misslyckades utan något felmeddelande", + "additionalCapabilities": "Ytterligare förmågor: {list}", + "comboRefMember": "Kombination → {name}" }, "combos": { "title": "Kombinationer", diff --git a/src/i18n/messages/sw.json b/src/i18n/messages/sw.json index 774b43eddea4..2d64b4093fe7 100644 --- a/src/i18n/messages/sw.json +++ b/src/i18n/messages/sw.json @@ -3317,7 +3317,23 @@ "next": "Inayofuata", "combo": "Mchanganyiko", "members": "Wanachama", - "moreMembers": "+{count} zaidi" + "moreMembers": "+{count} zaidi", + "minMaxOutput": "Kima cha chini cha pato la juu", + "minMaxOutputPlaceholder": "k.m. 4096", + "bulkTestProgress": "Maendeleo ya jaribio la jumla", + "testingProgressModels": "Inajaribu modeli {completed} kati ya {total}…", + "testingProgressCombos": "Inajaribu michanganyiko {completed} kati ya {total}…", + "testsCancelledModels": "Majaribio yameghairiwa baada ya modeli {completed} kati ya {total}", + "testsCancelledCombos": "Majaribio yameghairiwa baada ya michanganyiko {completed} kati ya {total}", + "bulkConfirmTitle": "Anzisha jaribio la jumla?", + "bulkConfirmModels": "Hii inatuma majaribio {count} ya modeli kwa watoa huduma wako na inaweza kutumia mgao. Ungependa kuendelea?", + "bulkConfirmCombos": "Hii inaendesha majaribio {count} ya michanganyiko na inaweza kutumia mgao wa mtoa huduma. Ungependa kuendelea?", + "bulkConfirmStart": "Anzisha majaribio", + "errorDetail": "Maelezo ya hitilafu: {detail}", + "httpError": "Ombi limeshindwa likiwa na HTTP {status}", + "testFailedNoDetail": "Jaribio limeshindwa bila ujumbe wa hitilafu", + "additionalCapabilities": "Uwezo wa ziada: {list}", + "comboRefMember": "Mchanganyiko → {name}" }, "combos": { "title": "Mikusanyiko", diff --git a/src/i18n/messages/ta.json b/src/i18n/messages/ta.json index e98e0db33eb0..f851d4248ff7 100644 --- a/src/i18n/messages/ta.json +++ b/src/i18n/messages/ta.json @@ -3317,7 +3317,23 @@ "next": "அடுத்தது", "combo": "சேர்க்கை", "members": "உறுப்பினர்கள்", - "moreMembers": "+{count} மேலும்" + "moreMembers": "+{count} மேலும்", + "minMaxOutput": "குறைந்தபட்ச அதிகபட்ச வெளியீடு", + "minMaxOutputPlaceholder": "எ.கா. 4096", + "bulkTestProgress": "மொத்த சோதனை முன்னேற்றம்", + "testingProgressModels": "{total} மாடல்களில் {completed} சோதிக்கப்படுகிறது…", + "testingProgressCombos": "{total} காம்போக்களில் {completed} சோதிக்கப்படுகிறது…", + "testsCancelledModels": "{total} மாடல்களில் {completed} முடிந்ததும் சோதனைகள் ரத்துசெய்யப்பட்டன", + "testsCancelledCombos": "{total} காம்போக்களில் {completed} முடிந்ததும் சோதனைகள் ரத்துசெய்யப்பட்டன", + "bulkConfirmTitle": "மொத்த சோதனையைத் தொடங்கவா?", + "bulkConfirmModels": "இது உங்கள் வழங்குநர்களுக்கு {count} மாடல் சோதனைகளை அனுப்பி, ஒதுக்கீட்டைப் பயன்படுத்தக்கூடும். தொடரவா?", + "bulkConfirmCombos": "இது {count} காம்போ சோதனைகளை இயக்கும் மற்றும் வழங்குநர் ஒதுக்கீட்டைப் பயன்படுத்தக்கூடும். தொடரவா?", + "bulkConfirmStart": "சோதனைகளைத் தொடங்கு", + "errorDetail": "பிழை விவரங்கள்: {detail}", + "httpError": "HTTP {status} உடன் கோரிக்கை தோல்வியடைந்தது", + "testFailedNoDetail": "பிழைச் செய்தி ஏதுமின்றி சோதனை தோல்வியடைந்தது", + "additionalCapabilities": "கூடுதல் திறன்கள்: {list}", + "comboRefMember": "காம்போ → {name}" }, "combos": { "title": "காம்போக்கள்", diff --git a/src/i18n/messages/te.json b/src/i18n/messages/te.json index dd35786ec800..5dd10e463018 100644 --- a/src/i18n/messages/te.json +++ b/src/i18n/messages/te.json @@ -3317,7 +3317,23 @@ "next": "తదుపరి", "combo": "కాంబో", "members": "సభ్యులు", - "moreMembers": "+{count} మరిన్ని" + "moreMembers": "+{count} మరిన్ని", + "minMaxOutput": "కనిష్ట గరిష్ట అవుట్‌పుట్", + "minMaxOutputPlaceholder": "ఉదా. 4096", + "bulkTestProgress": "బల్క్ పరీక్ష పురోగతి", + "testingProgressModels": "{total} మోడళ్లలో {completed} పరీక్షించబడుతున్నాయి…", + "testingProgressCombos": "{total} కాంబోలలో {completed} పరీక్షించబడుతున్నాయి…", + "testsCancelledModels": "{total} మోడళ్లలో {completed} తర్వాత పరీక్షలు రద్దు చేయబడ్డాయి", + "testsCancelledCombos": "{total} కాంబోలలో {completed} తర్వాత పరీక్షలు రద్దు చేయబడ్డాయి", + "bulkConfirmTitle": "బల్క్ పరీక్షను ప్రారంభించాలా?", + "bulkConfirmModels": "ఇది మీ ప్రొవైడర్‌లకు {count} మోడల్ పరీక్షలను పంపుతుంది మరియు కోటాను ఉపయోగించవచ్చు. కొనసాగించాలా?", + "bulkConfirmCombos": "ఇది {count} కాంబో పరీక్షలను రన్ చేస్తుంది మరియు ప్రొవైడర్ కోటాను ఉపయోగించవచ్చు. కొనసాగించాలా?", + "bulkConfirmStart": "పరీక్షలను ప్రారంభించండి", + "errorDetail": "లోపం వివరాలు: {detail}", + "httpError": "HTTP {status} తో అభ్యర్థన విఫలమైంది", + "testFailedNoDetail": "లోపం సందేశం లేకుండా పరీక్ష విఫలమైంది", + "additionalCapabilities": "అదనపు సామర్థ్యాలు: {list}", + "comboRefMember": "కాంబో → {name}" }, "combos": { "title": "కాంబోలు", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index e3f193c45727..bdd0ef45d447 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -3317,7 +3317,23 @@ "next": "ถัดไป", "combo": "คอมโบ", "members": "สมาชิก", - "moreMembers": "+{count} เพิ่มเติม" + "moreMembers": "+{count} เพิ่มเติม", + "minMaxOutput": "Max output ขั้นต่ำ", + "minMaxOutputPlaceholder": "เช่น 4096", + "bulkTestProgress": "ความคืบหน้าการทดสอบแบบกลุ่ม", + "testingProgressModels": "กำลังทดสอบ {completed} จาก {total} โมเดล…", + "testingProgressCombos": "กำลังทดสอบ {completed} จาก {total} คอมโบ…", + "testsCancelledModels": "ยกเลิกการทดสอบหลังจาก {completed} จาก {total} โมเดล", + "testsCancelledCombos": "ยกเลิกการทดสอบหลังจาก {completed} จาก {total} คอมโบ", + "bulkConfirmTitle": "เริ่มการทดสอบแบบกลุ่มหรือไม่?", + "bulkConfirmModels": "การดำเนินการนี้จะส่งการทดสอบโมเดล {count} รายการไปยังผู้ให้บริการของคุณและอาจใช้โควตา ดำเนินการต่อหรือไม่?", + "bulkConfirmCombos": "การดำเนินการนี้จะทำการทดสอบคอมโบ {count} รายการและอาจใช้โควตาของผู้ให้บริการ ดำเนินการต่อหรือไม่?", + "bulkConfirmStart": "เริ่มการทดสอบ", + "errorDetail": "รายละเอียดข้อผิดพลาด: {detail}", + "httpError": "คำขอไม่สำเร็จด้วย HTTP {status}", + "testFailedNoDetail": "การทดสอบล้มเหลวโดยไม่มีข้อความแสดงข้อผิดพลาด", + "additionalCapabilities": "ความสามารถเพิ่มเติม: {list}", + "comboRefMember": "คอมโบ → {name}" }, "combos": { "title": "คอมโบ", diff --git a/src/i18n/messages/tr.json b/src/i18n/messages/tr.json index 62b2405e6d0c..a32a1e3f8f87 100644 --- a/src/i18n/messages/tr.json +++ b/src/i18n/messages/tr.json @@ -3317,7 +3317,23 @@ "next": "Sonraki", "combo": "Kombo", "members": "Üyeler", - "moreMembers": "+{count} daha" + "moreMembers": "+{count} daha", + "minMaxOutput": "Minimum maksimum çıktı", + "minMaxOutputPlaceholder": "ör. 4096", + "bulkTestProgress": "Toplu test ilerlemesi", + "testingProgressModels": "{total} modelden {completed} tanesi test ediliyor…", + "testingProgressCombos": "{total} kombinasyondan {completed} tanesi test ediliyor…", + "testsCancelledModels": "{total} modelden {completed} tanesinin ardından testler iptal edildi", + "testsCancelledCombos": "{total} kombinasyondan {completed} tanesinin ardından testler iptal edildi", + "bulkConfirmTitle": "Toplu test başlatılsın mı?", + "bulkConfirmModels": "Bu işlem sağlayıcılarınıza {count} model testi gönderir ve kota tüketebilir. Devam edilsin mi?", + "bulkConfirmCombos": "Bu işlem {count} kombinasyon testi çalıştırır ve sağlayıcı kotasını tüketebilir. Devam edilsin mi?", + "bulkConfirmStart": "Testleri başlat", + "errorDetail": "Hata ayrıntıları: {detail}", + "httpError": "İstek HTTP {status} ile başarısız oldu", + "testFailedNoDetail": "Test bir hata mesajı olmadan başarısız oldu", + "additionalCapabilities": "Ek yetenekler: {list}", + "comboRefMember": "Kombinasyon → {name}" }, "combos": { "title": "Kombolar", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index ad5ee558db0a..bbf5e584d9f6 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -3317,7 +3317,23 @@ "next": "Наступна", "combo": "Комбо", "members": "Учасники", - "moreMembers": "+{count} ще" + "moreMembers": "+{count} ще", + "minMaxOutput": "Мінімальний макс. вивід", + "minMaxOutputPlaceholder": "наприклад, 4096", + "bulkTestProgress": "Прогрес масового тестування", + "testingProgressModels": "Тестування {completed} із {total} моделей…", + "testingProgressCombos": "Тестування {completed} із {total} комбінацій…", + "testsCancelledModels": "Тести скасовано після {completed} із {total} моделей", + "testsCancelledCombos": "Тести скасовано після {completed} із {total} комбінацій", + "bulkConfirmTitle": "Запустити масове тестування?", + "bulkConfirmModels": "Буде надіслано {count} тестів моделей до ваших провайдерів, що може використати квоту. Продовжити?", + "bulkConfirmCombos": "Буде запущено {count} тестів комбінацій, що може використати квоту провайдера. Продовжити?", + "bulkConfirmStart": "Запустити тести", + "errorDetail": "Деталі помилки: {detail}", + "httpError": "Запит завершився помилкою HTTP {status}", + "testFailedNoDetail": "Тест завершився помилкою без повідомлення про помилку", + "additionalCapabilities": "Додаткові можливості: {list}", + "comboRefMember": "Комбінація → {name}" }, "combos": { "title": "Комбо", diff --git a/src/i18n/messages/ur.json b/src/i18n/messages/ur.json index bee446958e72..39ad19aa6d2e 100644 --- a/src/i18n/messages/ur.json +++ b/src/i18n/messages/ur.json @@ -3317,7 +3317,23 @@ "next": "اگلا", "combo": "کمبو", "members": "ارکان", - "moreMembers": "+{count} مزید" + "moreMembers": "+{count} مزید", + "minMaxOutput": "کم سے کم زیادہ سے زیادہ آؤٹ پٹ", + "minMaxOutputPlaceholder": "مثلاً 4096", + "bulkTestProgress": "بلک ٹیسٹ کی پیش رفت", + "testingProgressModels": "{total} میں سے {completed} ماڈلز کی جانچ کی جا رہی ہے…", + "testingProgressCombos": "{total} میں سے {completed} کمبوز کی جانچ کی جا رہی ہے…", + "testsCancelledModels": "{total} میں سے {completed} ماڈلز کے بعد ٹیسٹ منسوخ کر دیے گئے", + "testsCancelledCombos": "{total} میں سے {completed} کمبوز کے بعد ٹیسٹ منسوخ کر دیے گئے", + "bulkConfirmTitle": "بلک ٹیسٹ شروع کریں؟", + "bulkConfirmModels": "یہ آپ کے فراہم کنندگان کو {count} ماڈل ٹیسٹ بھیجتا ہے اور کوٹہ استعمال کر سکتا ہے۔ کیا جاری رکھنا چاہتے ہیں؟", + "bulkConfirmCombos": "یہ {count} کمبو ٹیسٹ چلاتا ہے اور فراہم کنندہ کا کوٹہ استعمال کر سکتا ہے۔ کیا جاری رکھنا چاہتے ہیں؟", + "bulkConfirmStart": "ٹیسٹ شروع کریں", + "errorDetail": "خرابی کی تفصیلات: {detail}", + "httpError": "درخواست HTTP {status} کے ساتھ ناکام ہو گئی", + "testFailedNoDetail": "ٹیسٹ بغیر کسی خرابی کے پیغام کے ناکام ہو گیا", + "additionalCapabilities": "اضافی صلاحیتیں: {list}", + "comboRefMember": "کمبو → {name}" }, "combos": { "title": "کمبوز", diff --git a/src/i18n/messages/uz.json b/src/i18n/messages/uz.json index d6dd7283a78e..3e8062783242 100644 --- a/src/i18n/messages/uz.json +++ b/src/i18n/messages/uz.json @@ -3317,7 +3317,23 @@ "next": "Keyingi", "combo": "Kombo", "members": "Aʼzolar", - "moreMembers": "Yana +{count} ta" + "moreMembers": "Yana +{count} ta", + "minMaxOutput": "Minimal maksimal chiqish", + "minMaxOutputPlaceholder": "masalan, 4096", + "bulkTestProgress": "Ommaviy test jarayoni", + "testingProgressModels": "{total} ta modeldan {completed} tasi sinovdan oʻtkazilmoqda…", + "testingProgressCombos": "{total} ta kombinatsiyadan {completed} tasi sinovdan oʻtkazilmoqda…", + "testsCancelledModels": "{total} ta modeldan {completed} tasidan soʻng testlar bekor qilindi", + "testsCancelledCombos": "{total} ta kombinatsiyadan {completed} tasidan soʻng testlar bekor qilindi", + "bulkConfirmTitle": "Ommaviy test boshlansinmi?", + "bulkConfirmModels": "Bu provayderlaringizga {count} ta model sinovini yuboradi va kvotani sarflashi mumkin. Davom etilsinmi?", + "bulkConfirmCombos": "Bu {count} ta kombinatsiya sinovini bajaradi va provayder kvotasini sarflashi mumkin. Davom etilsinmi?", + "bulkConfirmStart": "Testlarni boshlash", + "errorDetail": "Xatolik tafsilotlari: {detail}", + "httpError": "Soʻrov HTTP {status} bilan muvaffaqiyatsiz tugadi", + "testFailedNoDetail": "Test xatolik xabarisiz muvaffaqiyatsiz tugadi", + "additionalCapabilities": "Qoʻshimcha imkoniyatlar: {list}", + "comboRefMember": "Kombinatsiya → {name}" }, "combos": { "title": "Kombinatsiyalar", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index c026644d5526..23480fd7e73b 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -3318,7 +3318,23 @@ "next": "Tiếp", "combo": "Combo", "members": "Thành viên", - "moreMembers": "+{count} nữa" + "moreMembers": "+{count} nữa", + "minMaxOutput": "Đầu ra tối đa tối thiểu", + "minMaxOutputPlaceholder": "vd: 4096", + "bulkTestProgress": "Tiến độ kiểm thử hàng loạt", + "testingProgressModels": "Đang kiểm thử {completed}/{total} mô hình…", + "testingProgressCombos": "Đang kiểm thử {completed}/{total} combo…", + "testsCancelledModels": "Đã hủy kiểm thử sau {completed}/{total} mô hình", + "testsCancelledCombos": "Đã hủy kiểm thử sau {completed}/{total} combo", + "bulkConfirmTitle": "Bắt đầu kiểm thử hàng loạt?", + "bulkConfirmModels": "Thao tác này sẽ gửi {count} lượt kiểm thử mô hình tới các nhà cung cấp của bạn và có thể tiêu tốn hạn ngạch. Tiếp tục?", + "bulkConfirmCombos": "Thao tác này sẽ chạy {count} lượt kiểm thử combo và có thể tiêu tốn hạn ngạch nhà cung cấp. Tiếp tục?", + "bulkConfirmStart": "Bắt đầu kiểm thử", + "errorDetail": "Chi tiết lỗi: {detail}", + "httpError": "Yêu cầu thất bại với mã HTTP {status}", + "testFailedNoDetail": "Kiểm thử thất bại mà không có thông báo lỗi", + "additionalCapabilities": "Khả năng bổ sung: {list}", + "comboRefMember": "Combo → {name}" }, "combos": { "title": "Combo", diff --git a/src/i18n/messages/yo.json b/src/i18n/messages/yo.json index fdbce7170af9..1489f736a392 100644 --- a/src/i18n/messages/yo.json +++ b/src/i18n/messages/yo.json @@ -3317,7 +3317,23 @@ "next": "Tókàn", "combo": "Àpapọ̀", "members": "Àwọn ọmọ ẹgbẹ́", - "moreMembers": "+{count} síi" + "moreMembers": "+{count} síi", + "minMaxOutput": "Àbájáde tó kéré/tó pọ̀ jù", + "minMaxOutputPlaceholder": "f.a. 4096", + "bulkTestProgress": "Ìlọsíwájú àdánwò àpapọ̀", + "testingProgressModels": "Ń dán {completed} nínú {total} àwọn àwòṣe wò…", + "testingProgressCombos": "Ń dán {completed} nínú {total} àwọn àkópọ̀ wò…", + "testsCancelledModels": "A fagilé àwọn àdánwò lẹ́yìn {completed} nínú {total} àwọn àwòṣe", + "testsCancelledCombos": "A fagilé àwọn àdánwò lẹ́yìn {completed} nínú {total} àwọn àkópọ̀", + "bulkConfirmTitle": "Bẹ̀rẹ̀ àdánwò àpapọ̀?", + "bulkConfirmModels": "Èyí yóò fi àwọn àdánwò àwòṣe {count} ránṣẹ́ sí àwọn olùpèsè rẹ tí ó sì lè lo quota. Ṣé kí a tẹ̀síwájú?", + "bulkConfirmCombos": "Èyí yóò ṣe àwọn àdánwò àkópọ̀ {count} tí ó sì lè lo quota olùpèsè. Ṣé kí a tẹ̀síwájú?", + "bulkConfirmStart": "Bẹ̀rẹ̀ àwọn àdánwò", + "errorDetail": "Àwọn kúlẹ̀kúlẹ̀ àṣìṣe: {detail}", + "httpError": "Ìbéèrè kùnà pẹ̀lú HTTP {status}", + "testFailedNoDetail": "Àdánwò kùnà láìsí ìránṣẹ́ àṣìṣe", + "additionalCapabilities": "Àwọn agbára àfikún: {list}", + "comboRefMember": "Àkópọ̀ → {name}" }, "combos": { "title": "Àwọn àkójọpọ̀", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 932d50f24ebc..ccb3264e0aaf 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -3317,7 +3317,23 @@ "next": "下一页", "combo": "组合", "members": "成员", - "moreMembers": "+{count} 更多" + "moreMembers": "+{count} 更多", + "minMaxOutput": "最小最大输出", + "minMaxOutputPlaceholder": "例如 4096", + "bulkTestProgress": "批量测试进度", + "testingProgressModels": "正在测试模型({completed}/{total})…", + "testingProgressCombos": "正在测试组合({completed}/{total})…", + "testsCancelledModels": "测试已取消(已测试 {completed}/{total} 个模型)", + "testsCancelledCombos": "测试已取消(已测试 {completed}/{total} 个组合)", + "bulkConfirmTitle": "开始批量测试?", + "bulkConfirmModels": "这将向您的提供商发送 {count} 个模型测试,并可能消耗配额。是否继续?", + "bulkConfirmCombos": "这将运行 {count} 个组合测试,并可能消耗提供商配额。是否继续?", + "bulkConfirmStart": "开始测试", + "errorDetail": "错误详情:{detail}", + "httpError": "请求失败,HTTP {status}", + "testFailedNoDetail": "测试失败且未提供错误信息", + "additionalCapabilities": "额外能力:{list}", + "comboRefMember": "组合 → {name}" }, "combos": { "title": "组合", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index aa480655ed54..c13117640618 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -3317,7 +3317,23 @@ "next": "下一頁", "combo": "組合", "members": "成員", - "moreMembers": "+{count} 更多" + "moreMembers": "+{count} 更多", + "minMaxOutput": "最小最大輸出", + "minMaxOutputPlaceholder": "例如 4096", + "bulkTestProgress": "批次測試進度", + "testingProgressModels": "正在測試 {completed} / {total} 個模型…", + "testingProgressCombos": "正在測試 {completed} / {total} 個組合…", + "testsCancelledModels": "已在測試 {completed} / {total} 個模型後取消", + "testsCancelledCombos": "已在測試 {completed} / {total} 個組合後取消", + "bulkConfirmTitle": "開始批次測試?", + "bulkConfirmModels": "這將向您的提供者發送 {count} 個模型測試,可能會消耗配額。是否繼續?", + "bulkConfirmCombos": "這將執行 {count} 個組合測試,可能會消耗提供者配額。是否繼續?", + "bulkConfirmStart": "開始測試", + "errorDetail": "錯誤詳細資訊:{detail}", + "httpError": "請求失敗,HTTP {status}", + "testFailedNoDetail": "測試失敗且無錯誤訊息", + "additionalCapabilities": "其他功能:{list}", + "comboRefMember": "組合 → {name}" }, "combos": { "title": "組合", From c4e121a778d1f7a3fec1785eb37e86efd1cb50fe Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 16:49:51 +0300 Subject: [PATCH 06/16] docs(changelog): add the models and combos catalog fragment #14887 --- changelog.d/features/14887-models-combos-catalog.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/features/14887-models-combos-catalog.md diff --git a/changelog.d/features/14887-models-combos-catalog.md b/changelog.d/features/14887-models-combos-catalog.md new file mode 100644 index 000000000000..9bc76ad8ecf4 --- /dev/null +++ b/changelog.d/features/14887-models-combos-catalog.md @@ -0,0 +1 @@ +- **feat(dashboard):** models and combos catalog with filters and browser-side health tests ([#14887](https://github.com/diegosouzapw/OmniRoute/pull/14887)). From f415a76eb1946e8bbd70c7fb838b64d9212304a7 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 17:30:46 +0300 Subject: [PATCH 07/16] fix(dashboard): address catalog re-review findings --- .../dashboard/models/CatalogTabs.tsx | 2 +- .../dashboard/models/ComboCatalogTable.tsx | 6 +- .../dashboard/models/ModelCatalogFilters.tsx | 2 +- .../dashboard/models/ModelCatalogTable.tsx | 23 ++-- .../dashboard/models/catalogBulkUtils.ts | 24 ++++ .../dashboard/models/catalogTestResponses.ts | 10 +- .../dashboard/models/catalogTestStorage.ts | 6 +- .../dashboard/models/catalogUrlState.ts | 5 +- .../dashboard/models/comboCatalogUtils.ts | 6 + src/app/(dashboard)/dashboard/models/page.tsx | 115 ++++++++++++------ .../dashboard/models/useCatalogTestRunner.ts | 94 +++++++------- .../unit/dashboard/catalogBulkUtils.test.tsx | 27 ++++ .../dashboard/catalogTestResponses.test.tsx | 27 ++++ .../dashboard/catalogTestStorage.test.tsx | 11 ++ tests/unit/dashboard/catalogUrlState.test.tsx | 10 ++ .../unit/dashboard/comboCatalogUtils.test.tsx | 20 +++ .../dashboard/modelsCombosCatalog.test.tsx | 33 +++++ 17 files changed, 322 insertions(+), 99 deletions(-) diff --git a/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx b/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx index 0a142f55b286..98b4e9ab9331 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogTabs.tsx @@ -65,7 +65,7 @@ export default function CatalogTabs({ role="tab" id={catalogTabId(tab)} aria-selected={selected} - aria-controls={catalogPanelId(tab)} + aria-controls={selected ? catalogPanelId(tab) : undefined} tabIndex={selected ? 0 : -1} onClick={() => onSelect(tab)} onKeyDown={(event) => handleKeyDown(event, index)} diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx index 5f4fb0c188d3..3e49c641f63b 100644 --- a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx @@ -67,7 +67,7 @@ export default function ComboCatalogTable({ onToggleSelect, onToggleSelectAll, testResults, - activeTestingKey, + activeTestingKeys, onTestCombo, onPrevious, onNext, @@ -85,7 +85,7 @@ export default function ComboCatalogTable({ onToggleSelect: (id: string) => void; onToggleSelectAll: () => void; testResults: Record; - activeTestingKey: string | null; + activeTestingKeys: ReadonlySet; onTestCombo: (comboName: string) => void; onPrevious: () => void; onNext: () => void; @@ -169,7 +169,7 @@ export default function ComboCatalogTable({ {rows.map((combo) => { const isSelected = selectedIds.has(combo.id); const testKey = getComboTestKey(combo.name); - const isTesting = activeTestingKey === testKey; + const isTesting = activeTestingKeys.has(testKey); const result = testResults[testKey]; return ( diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx index c01e8c839f7f..1c27105b302d 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx @@ -59,7 +59,7 @@ export default function ModelCatalogFiltersComponent({ -
+
Promise +): Promise { + const providerGroups = new Map(); + for (const batch of batches) { + const group = providerGroups.get(batch.providerId) ?? []; + group.push(batch); + providerGroups.set(batch.providerId, group); + } + await runWithConcurrency( + [...providerGroups.values()], + BULK_CONCURRENCY, + signal, + async (group) => { + for (const batch of group) { + if (signal.aborted) return; + await worker(batch); + } + } + ); +} + /** Run `worker` over `items` with at most `limit` in flight; stop scheduling once `signal` aborts. */ export async function runWithConcurrency( items: T[], diff --git a/src/app/(dashboard)/dashboard/models/catalogTestResponses.ts b/src/app/(dashboard)/dashboard/models/catalogTestResponses.ts index b94863b7735c..a3f250f2c06a 100644 --- a/src/app/(dashboard)/dashboard/models/catalogTestResponses.ts +++ b/src/app/(dashboard)/dashboard/models/catalogTestResponses.ts @@ -147,10 +147,10 @@ export function mapBatchResponse( if (!isRecord(entry)) return []; const latencyMs = asNumber(entry.latencyMs); const statusCode = asNumber(entry.statusCode); - const status = normalizeTestStatus( - typeof entry.status === "string" ? entry.status : "error", - latencyMs - ); + const isTimeout = entry.isTimeout === true || entry.status === "slow"; + const status = isTimeout + ? "error" + : normalizeTestStatus(typeof entry.status === "string" ? entry.status : "error", latencyMs); const error = status === "error" ? extractErrorText(entry.error) : undefined; return [ { @@ -163,7 +163,7 @@ export function mapBatchResponse( ? failureClass(error, statusCode, { rateLimited: entry.rateLimited === true, isQuota: entry.isQuota === true, - isTimeout: entry.isTimeout === true, + isTimeout, }) : undefined, statusCode, diff --git a/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts b/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts index e0ed9aa6a7b5..8b0ab6020bbd 100644 --- a/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts +++ b/src/app/(dashboard)/dashboard/models/catalogTestStorage.ts @@ -96,7 +96,11 @@ export function loadCatalogTestResults(): Record { typeof value === "object" && !Array.isArray(value) && "status" in value && - typeof (value as { status: unknown }).status === "string" + typeof (value as { status: unknown }).status === "string" && + "testedAt" in value && + typeof value.testedAt === "number" && + Number.isFinite(value.testedAt) && + Math.abs(value.testedAt) <= 8.64e15 ) { sanitized[key] = value as CatalogTestResult; } diff --git a/src/app/(dashboard)/dashboard/models/catalogUrlState.ts b/src/app/(dashboard)/dashboard/models/catalogUrlState.ts index 29b567f13561..5d8ef56a2865 100644 --- a/src/app/(dashboard)/dashboard/models/catalogUrlState.ts +++ b/src/app/(dashboard)/dashboard/models/catalogUrlState.ts @@ -48,15 +48,16 @@ export function parseCatalogTab(params: URLSearchParams): CatalogTab { } export function parseModelFilters(params: URLSearchParams): CatalogFilters { + const onModelsTab = parseCatalogTab(params) === "models"; return { - query: params.get("query") || "", + query: onModelsTab ? params.get("query") || "" : "", providerId: params.get("provider") || "all", type: params.get("type") || "all", subtype: params.get("subtype") || "all", capability: params.get("capability") || "all", pricing: pickAllowed(params.get("pricing"), PRICING_VALUES), providerHealth: pickAllowed(params.get("health"), HEALTH_VALUES), - testResult: pickAllowed(params.get("testResult"), TEST_RESULT_VALUES), + testResult: pickAllowed(onModelsTab ? params.get("testResult") : null, TEST_RESULT_VALUES), minContextLength: parseNonNegativeInt(params.get("minContext")), minMaxOutputTokens: parseNonNegativeInt(params.get("minOutput")), }; diff --git a/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts b/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts index fb104a70a7cd..a130865eb968 100644 --- a/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts +++ b/src/app/(dashboard)/dashboard/models/comboCatalogUtils.ts @@ -71,6 +71,12 @@ export function flattenCombos(rawCombos: unknown): ComboCatalogRow[] { kind: "combo-ref", ...(typeof m.label === "string" ? { label: m.label } : {}), }); + } else if ( + m.kind === "provider-wildcard" && + typeof m.providerId === "string" && + typeof m.modelPattern === "string" + ) { + modelsList.push({ model: `${m.providerId}/${m.modelPattern}` }); } else if (typeof m.model === "string") { modelsList.push({ model: m.model, diff --git a/src/app/(dashboard)/dashboard/models/page.tsx b/src/app/(dashboard)/dashboard/models/page.tsx index 6769e0ca58b5..508583f5055d 100644 --- a/src/app/(dashboard)/dashboard/models/page.tsx +++ b/src/app/(dashboard)/dashboard/models/page.tsx @@ -96,14 +96,14 @@ export default function ModelCatalogPage() { Record >({}); - const [modelFilters, setModelFilters] = useState(DEFAULT_MODEL_FILTERS); - const [comboFilters, setComboFilters] = useState(DEFAULT_COMBO_FILTERS); + const [rawModelFilters, setModelFilters] = useState(DEFAULT_MODEL_FILTERS); + const [rawComboFilters, setComboFilters] = useState(DEFAULT_COMBO_FILTERS); // Test Runner Hook const { testResults, running, - activeItemKey, + activeItemKeys, progress, testSingleModel, testSingleCombo, @@ -139,37 +139,6 @@ export default function ModelCatalogPage() { [] ); - const switchTab = (tab: CatalogTab) => { - setActiveTab(tab); - syncUrlParams(tab, modelFilters, comboFilters); - }; - - const updateModelFilters = (patch: Partial) => { - const updated = { ...modelFilters, ...patch }; - setModelFilters(updated); - setRequestedModelPage(0); - syncUrlParams("models", updated, comboFilters); - }; - - const clearModelFilters = () => { - setModelFilters(DEFAULT_MODEL_FILTERS); - setRequestedModelPage(0); - syncUrlParams("models", DEFAULT_MODEL_FILTERS, comboFilters); - }; - - const updateComboFilters = (patch: Partial) => { - const updated = { ...comboFilters, ...patch }; - setComboFilters(updated); - setRequestedComboPage(0); - syncUrlParams("combos", modelFilters, updated); - }; - - const clearComboFilters = () => { - setComboFilters(DEFAULT_COMBO_FILTERS); - setRequestedComboPage(0); - syncUrlParams("combos", modelFilters, DEFAULT_COMBO_FILTERS); - }; - // Data Loading const loadData = useCallback(async () => { requestController.current?.abort(); @@ -285,6 +254,80 @@ export default function ModelCatalogPage() { [combos] ); + const modelFilters = useMemo( + () => ({ + ...rawModelFilters, + providerId: + modelsLoading || providerOptions.some(([id]) => id === rawModelFilters.providerId) + ? rawModelFilters.providerId + : "all", + type: + modelsLoading || typeOptions.includes(rawModelFilters.type) ? rawModelFilters.type : "all", + subtype: + modelsLoading || subtypeOptions.includes(rawModelFilters.subtype || "all") + ? rawModelFilters.subtype + : "all", + capability: + modelsLoading || capabilityOptions.includes(rawModelFilters.capability || "all") + ? rawModelFilters.capability + : "all", + }), + [ + rawModelFilters, + modelsLoading, + providerOptions, + typeOptions, + subtypeOptions, + capabilityOptions, + ] + ); + const comboFilters = useMemo( + () => ({ + ...rawComboFilters, + strategy: + combosLoading || strategyOptions.includes(rawComboFilters.strategy) + ? rawComboFilters.strategy + : "all", + }), + [rawComboFilters, combosLoading, strategyOptions] + ); + + useEffect(() => { + if (modelsLoading || combosLoading) return; + syncUrlParams(activeTab, modelFilters, comboFilters); + }, [activeTab, modelFilters, comboFilters, modelsLoading, combosLoading, syncUrlParams]); + + const switchTab = (tab: CatalogTab) => { + setActiveTab(tab); + syncUrlParams(tab, modelFilters, comboFilters); + }; + + const updateModelFilters = (patch: Partial) => { + const updated = { ...modelFilters, ...patch }; + setModelFilters(updated); + setRequestedModelPage(0); + syncUrlParams("models", updated, comboFilters); + }; + + const clearModelFilters = () => { + setModelFilters(DEFAULT_MODEL_FILTERS); + setRequestedModelPage(0); + syncUrlParams("models", DEFAULT_MODEL_FILTERS, comboFilters); + }; + + const updateComboFilters = (patch: Partial) => { + const updated = { ...comboFilters, ...patch }; + setComboFilters(updated); + setRequestedComboPage(0); + syncUrlParams("combos", modelFilters, updated); + }; + + const clearComboFilters = () => { + setComboFilters(DEFAULT_COMBO_FILTERS); + setRequestedComboPage(0); + syncUrlParams("combos", modelFilters, DEFAULT_COMBO_FILTERS); + }; + // Filtered & Sorted Models const visibleModels = useMemo(() => { const filtered = filterCatalogModels(models, modelFilters, { @@ -535,7 +578,7 @@ export default function ModelCatalogPage() { onToggleSelect={toggleSelectModel} onToggleSelectAll={toggleSelectAllModelsOnPage} testResults={testResults} - activeTestingKey={activeItemKey} + activeTestingKeys={activeItemKeys} onTestModel={testSingleModel} providerHealthMap={providerHealthMap} bulkRunning={running} @@ -633,7 +676,7 @@ export default function ModelCatalogPage() { onToggleSelect={toggleSelectCombo} onToggleSelectAll={toggleSelectAllCombosOnPage} testResults={testResults} - activeTestingKey={activeItemKey} + activeTestingKeys={activeItemKeys} onTestCombo={testSingleCombo} onPrevious={() => setRequestedComboPage((c) => Math.max(0, c - 1))} onNext={() => diff --git a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts index df99c0dad4a4..f6cbce85571b 100644 --- a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts +++ b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts @@ -7,6 +7,7 @@ import { dedupeComboTargets, dedupeModelTargets, runWithConcurrency, + runModelBatches, type ComboTestTarget, type ModelTestTarget, } from "./catalogBulkUtils"; @@ -44,7 +45,8 @@ const JSON_HEADERS = { "Content-Type": "application/json" }; export function useCatalogTestRunner() { const [testResults, setTestResults] = useState>({}); const [running, setRunning] = useState(false); - const [activeItemKey, setActiveItemKey] = useState(null); + const [activeItemKeys, setActiveItemKeys] = useState>(new Set()); + const activeSignalsRef = useRef(new Map()); const [progress, setProgress] = useState(IDLE_PROGRESS); const mountedRef = useRef(false); @@ -78,9 +80,17 @@ export function useCatalogTestRunner() { setTestResults({ ...saveBatchTestResults(results) }); }, []); + const claimActiveKey = useCallback((key: string, signal: AbortSignal) => { + if (activeSignalsRef.current.has(key)) return false; + activeSignalsRef.current.set(key, signal); + setActiveItemKeys(new Set(activeSignalsRef.current.keys())); + return true; + }, []); + const releaseActiveKey = useCallback((key: string, signal: AbortSignal) => { - if (!mountedRef.current || signal.aborted) return; - setActiveItemKey((current) => (current === key ? null : current)); + if (activeSignalsRef.current.get(key) !== signal) return; + activeSignalsRef.current.delete(key); + if (mountedRef.current) setActiveItemKeys(new Set(activeSignalsRef.current.keys())); }, []); const withSingleController = useCallback(async (work: (signal: AbortSignal) => Promise) => { @@ -96,7 +106,7 @@ export function useCatalogTestRunner() { const runComboTest = useCallback( async (comboName: string, signal: AbortSignal) => { const key = getComboTestKey(comboName); - setActiveItemKey(key); + if (!claimActiveKey(key, signal)) return; try { const res = await fetch("/api/combos/test", { method: "POST", @@ -115,14 +125,14 @@ export function useCatalogTestRunner() { releaseActiveKey(key, signal); } }, - [persist, releaseActiveKey] + [claimActiveKey, persist, releaseActiveKey] ); const testSingleModel = useCallback( (providerId: string, modelId: string) => withSingleController(async (signal) => { const key = getModelTestKey(providerId, modelId); - setActiveItemKey(key); + if (!claimActiveKey(key, signal)) return; try { const res = await fetch("/api/models/test", { method: "POST", @@ -141,7 +151,7 @@ export function useCatalogTestRunner() { releaseActiveKey(key, signal); } }), - [persist, releaseActiveKey, withSingleController] + [claimActiveKey, persist, releaseActiveKey, withSingleController] ); const testSingleCombo = useCallback( @@ -180,41 +190,36 @@ export function useCatalogTestRunner() { const controller = startRun("models", unique.length); const { signal } = controller; try { - await runWithConcurrency( - buildModelBatches(unique), - BULK_CONCURRENCY, - signal, - async (batch) => { - try { - const res = await fetch("/api/models/test-all", { - method: "POST", - headers: JSON_HEADERS, - body: JSON.stringify({ - providerId: batch.providerId, - modelIds: batch.modelIds, - respectRateLimit: true, - }), - signal, - }); - const body = await readJsonBody(res); - persist(mapBatchResponse(batch, res, body, Date.now()), signal); - } catch (failure) { - const testedAt = Date.now(); - persist( - batch.modelIds.map((modelId) => - mapRequestFailure( - { targetType: "model", providerId: batch.providerId, modelId }, - failure, - testedAt - ) - ), - signal - ); - } finally { - advanceRun(controller, batch.modelIds.length); - } + await runModelBatches(buildModelBatches(unique), signal, async (batch) => { + try { + const res = await fetch("/api/models/test-all", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ + providerId: batch.providerId, + modelIds: batch.modelIds, + respectRateLimit: true, + }), + signal, + }); + const body = await readJsonBody(res); + persist(mapBatchResponse(batch, res, body, Date.now()), signal); + } catch (failure) { + const testedAt = Date.now(); + persist( + batch.modelIds.map((modelId) => + mapRequestFailure( + { targetType: "model", providerId: batch.providerId, modelId }, + failure, + testedAt + ) + ), + signal + ); + } finally { + advanceRun(controller, batch.modelIds.length); } - ); + }); } finally { finishRun(controller); } @@ -249,7 +254,10 @@ export function useCatalogTestRunner() { runControllerRef.current = null; controller.abort(); setRunning(false); - setActiveItemKey(null); + for (const [key, signal] of activeSignalsRef.current) { + if (signal === controller.signal) activeSignalsRef.current.delete(key); + } + setActiveItemKeys(new Set(activeSignalsRef.current.keys())); setProgress((current) => ({ ...current, cancelled: true })); }, []); @@ -261,7 +269,7 @@ export function useCatalogTestRunner() { return { testResults, running, - activeItemKey, + activeItemKeys, progress, testSingleModel, testSingleCombo, diff --git a/tests/unit/dashboard/catalogBulkUtils.test.tsx b/tests/unit/dashboard/catalogBulkUtils.test.tsx index 07c01a40a44b..0b966b73f7c6 100644 --- a/tests/unit/dashboard/catalogBulkUtils.test.tsx +++ b/tests/unit/dashboard/catalogBulkUtils.test.tsx @@ -4,6 +4,7 @@ import { dedupeComboTargets, dedupeModelTargets, runWithConcurrency, + runModelBatches, } from "@/app/(dashboard)/dashboard/models/catalogBulkUtils"; function deferred() { @@ -81,6 +82,32 @@ describe("buildModelBatches", () => { }); }); +describe("runModelBatches", () => { + it("serializes each provider while another provider fills the second slot", async () => { + const gates = [deferred(), deferred(), deferred()]; + const batches = [ + { providerId: "alpha", modelIds: ["0"] }, + { providerId: "alpha", modelIds: ["1"] }, + { providerId: "beta", modelIds: ["2"] }, + ]; + const started: string[] = []; + const run = runModelBatches(batches, new AbortController().signal, async (batch) => { + started.push(`${batch.providerId}:${batch.modelIds[0]}`); + await gates[Number(batch.modelIds[0])].promise; + }); + await settle(); + expect(started).toEqual(["alpha:0", "beta:2"]); + gates[2].resolve(); + await settle(); + expect(started).toEqual(["alpha:0", "beta:2"]); + gates[0].resolve(); + await settle(); + expect(started).toEqual(["alpha:0", "beta:2", "alpha:1"]); + gates[1].resolve(); + await run; + }); +}); + describe("runWithConcurrency", () => { it("never runs more than the limit at once and processes every item", async () => { const gates = [deferred(), deferred(), deferred(), deferred()]; diff --git a/tests/unit/dashboard/catalogTestResponses.test.tsx b/tests/unit/dashboard/catalogTestResponses.test.tsx index d8e16e589008..108c2c4b3231 100644 --- a/tests/unit/dashboard/catalogTestResponses.test.tsx +++ b/tests/unit/dashboard/catalogTestResponses.test.tsx @@ -12,6 +12,33 @@ const TESTED_AT = 1_000; describe("mapBatchResponse", () => { const batch = { providerId: "alpha", modelIds: ["a", "b", "c"] }; + it.each([{ status: "slow" }, { status: "error", isTimeout: true }])( + "classifies a batch timeout as an error: %j", + (timeout) => { + const error = "No model output within 30s"; + const [bulk] = mapBatchResponse( + { providerId: "alpha", modelIds: ["chat"] }, + OK, + { results: { chat: { ...timeout, latencyMs: 30_000, error } } }, + TESTED_AT + ); + const single = mapSingleModelResponse( + "alpha", + "chat", + { ok: false, status: 504 }, + { status: "error", latencyMs: 30_000, error }, + TESTED_AT + ); + expect(bulk).toMatchObject({ + status: single.status, + errorClass: single.errorClass, + error, + }); + expect(bulk.status).toBe("error"); + expect(bulk.errorClass).toBe("timeout"); + } + ); + it("stores only the models the server reported when it stopped early", () => { const results = mapBatchResponse( batch, diff --git a/tests/unit/dashboard/catalogTestStorage.test.tsx b/tests/unit/dashboard/catalogTestStorage.test.tsx index d22640b58a0c..46a35670b6f2 100644 --- a/tests/unit/dashboard/catalogTestStorage.test.tsx +++ b/tests/unit/dashboard/catalogTestStorage.test.tsx @@ -70,6 +70,17 @@ describe("catalogTestStorage", () => { expect(loaded[comboResult.id]).toEqual(comboResult); }); + it("drops stored timestamps outside the JavaScript date range", () => { + localStorage.setItem( + CATALOG_TEST_RESULTS_KEY, + JSON.stringify({ + invalid: { status: "ok", testedAt: 8.64e15 + 1 }, + valid: { status: "ok", testedAt: 1000 }, + }) + ); + expect(loadCatalogTestResults()).toEqual({ valid: { status: "ok", testedAt: 1000 } }); + }); + it("clears test results from localStorage", () => { const modelResult: CatalogTestResult = { id: getModelTestKey("alpha", "chat-1"), diff --git a/tests/unit/dashboard/catalogUrlState.test.tsx b/tests/unit/dashboard/catalogUrlState.test.tsx index 404f3caabb04..be9349527f8a 100644 --- a/tests/unit/dashboard/catalogUrlState.test.tsx +++ b/tests/unit/dashboard/catalogUrlState.test.tsx @@ -49,6 +49,16 @@ describe("parseModelFilters", () => { expect(parseModelFilters(new URLSearchParams(""))).toEqual(DEFAULT_MODEL_FILTERS); }); + it("does not leak combo search or test-result filters into models after reload", () => { + const params = buildCatalogSearchParams("combos", DEFAULT_MODEL_FILTERS, { + ...DEFAULT_COMBO_FILTERS, + query: "fast", + testResult: "error", + }); + expect(parseModelFilters(params)).toEqual(DEFAULT_MODEL_FILTERS); + expect(parseComboFilters(params)).toMatchObject({ query: "fast", testResult: "error" }); + }); + it("reads every model filter param", () => { expect( parseModelFilters( diff --git a/tests/unit/dashboard/comboCatalogUtils.test.tsx b/tests/unit/dashboard/comboCatalogUtils.test.tsx index 0ab30c53a31c..e068c0479c2a 100644 --- a/tests/unit/dashboard/comboCatalogUtils.test.tsx +++ b/tests/unit/dashboard/comboCatalogUtils.test.tsx @@ -81,6 +81,26 @@ describe("flattenCombos", () => { expect(result[1].memberCount).toBe(2); }); + it("counts provider-wildcard steps in the member-range filter", () => { + const rows = flattenCombos([ + { + name: "wildcard", + models: [{ kind: "provider-wildcard", providerId: "alpha", modelPattern: "chat-*" }], + }, + ]); + expect(rows[0].memberCount).toBe(1); + expect(rows[0].models[0].model).toBe("alpha/chat-*"); + expect( + filterCatalogCombos(rows, { + query: "", + strategy: "all", + status: "all", + testResult: "all", + minMembers: 1, + }) + ).toEqual(rows); + }); + it("counts combo-ref steps as members for nested combos", () => { const rawCombos = [ { diff --git a/tests/unit/dashboard/modelsCombosCatalog.test.tsx b/tests/unit/dashboard/modelsCombosCatalog.test.tsx index 629a93051d79..32b76ba21bdc 100644 --- a/tests/unit/dashboard/modelsCombosCatalog.test.tsx +++ b/tests/unit/dashboard/modelsCombosCatalog.test.tsx @@ -437,6 +437,39 @@ describe("Models and Combos Catalog Page UI", () => { expect(bodyRows()).toHaveLength(2); }); + it("ignores unknown provider filters once catalog options load", async () => { + installFetch(); + window.history.replaceState(null, "", "/dashboard/models?provider=unknown"); + await renderPage(); + expect(bodyRows().length).toBeGreaterThan(0); + expect(window.location.search).not.toContain("provider=unknown"); + }); + + it("keeps both row tests disabled until their own requests finish", async () => { + const responses = [deferred(), deferred()]; + let index = 0; + installFetch({ modelTest: () => responses[index++].promise }); + await renderPage(); + const buttons = Array.from( + container.querySelectorAll("button[data-testid^='test-model-']") + ); + await click(buttons[0]); + await click(buttons[1]); + expect(buttons[0].disabled).toBe(true); + expect(buttons[1].disabled).toBe(true); + await act(async () => { + responses[0].resolve(jsonResponse({ status: "ok", latencyMs: 90 })); + await flush(); + }); + expect(buttons[0].disabled).toBe(false); + expect(buttons[1].disabled).toBe(true); + await act(async () => { + responses[1].resolve(jsonResponse({ status: "ok", latencyMs: 90 })); + await flush(); + }); + expect(buttons[1].disabled).toBe(false); + }); + it("executes a single model test and displays the status badge and latency", async () => { const fetchMock = installFetch(); await renderPage(); From 34739f6a2d7d4e57b8b4eaf9d7718d32c831f92a Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 19:07:47 +0300 Subject: [PATCH 08/16] fix(dashboard): make catalog URL sync safe and keep filters during reloads - Write the URL from one effect only, skip the write when pathname and search are unchanged, and ignore a refused history.replaceState call (browsers rate-limit it), so a throttled update never takes the page down. - Check free-form URL filters against loaded options only while options exist (models/combos loaded), so a Refresh no longer flashes an empty table and a failed load no longer drops valid filters from the URL. - Match the capability URL param case-insensitively, like the filter. - Drop the redundant lg/xl grid-cols-3 classes on the model filter grid. --- .../dashboard/models/ModelCatalogFilters.tsx | 2 +- .../dashboard/models/catalogUrlState.ts | 47 +++++++ src/app/(dashboard)/dashboard/models/page.tsx | 97 +++++++-------- tests/unit/dashboard/catalogUrlState.test.tsx | 70 +++++++++++ .../dashboard/modelsCombosCatalog.test.tsx | 116 ++++++++++++++++++ 5 files changed, 281 insertions(+), 51 deletions(-) diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx index 1c27105b302d..42bc1a685ddb 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx @@ -59,7 +59,7 @@ export default function ModelCatalogFiltersComponent({ -
+
+ ); +} + +export function FilterSelect({ + label, + value, + onChange, + children, +}: { + label: string; + value: string; + onChange: (value: string) => void; + children: ReactNode; +}) { + return ( + + ); +} + +/** One option per value, labelled with the humanized value. */ +export function HumanizedOptions({ values }: { values: string[] }) { + return ( + <> + {values.map((value) => ( + + ))} + + ); +} + +/** The health-test result choices shared by the model and combo filters. */ +export function TestResultOptions() { + const t = useTranslations("modelCatalog"); + + return ( + <> + + + + + + + ); +} + +/** A numeric filter: empty or invalid input clears it (see `parseNonNegativeInt`). */ +export function FilterNumberInput({ + label, + min, + step, + placeholder, + value, + onChange, +}: { + label: string; + min: number; + step?: number; + placeholder: string; + value: number | undefined; + onChange: (value: number | undefined) => void; +}) { + return ( + + ); +} diff --git a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx index 3ed699b6942b..db05dd94bae1 100644 --- a/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx +++ b/src/app/(dashboard)/dashboard/models/CatalogTestBadge.tsx @@ -37,34 +37,30 @@ function testAge(testedAt: number, now = Date.now()): TestAge { return { unit: "date" }; } -export default function CatalogTestBadge({ - result, - loading = false, -}: { - result?: CatalogTestResult; - loading?: boolean; -}) { +function TestingIndicator() { const t = useTranslations("modelCatalog"); + return ( +
+
+ ); +} - if (loading) { - return ( -
-
- ); - } +function UntestedMark() { + const t = useTranslations("modelCatalog"); + return ( + + — + + ); +} - if (!result) { - return ( - - — - - ); - } +function TestResultSummary({ result }: { result: CatalogTestResult }) { + const t = useTranslations("modelCatalog"); const variant = result.status === "ok" ? "success" : result.status === "slow" ? "warning" : "error"; @@ -130,3 +126,21 @@ export default function CatalogTestBadge({
); } + +export default function CatalogTestBadge({ + result, + loading = false, +}: { + result?: CatalogTestResult; + loading?: boolean; +}) { + if (loading) { + return ; + } + + if (!result) { + return ; + } + + return ; +} diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx index bc81072b9906..fb324cbe29f8 100644 --- a/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogFilters.tsx @@ -1,17 +1,15 @@ "use client"; import { useTranslations } from "next-intl"; -import { Button, Input } from "@/shared/components"; -import { parseNonNegativeInt } from "./catalogUrlState"; +import { + FilterNumberInput, + FilterSearchRow, + FilterSelect, + HumanizedOptions, + TestResultOptions, +} from "./CatalogFilterFields"; import type { ComboCatalogFilters } from "./comboCatalogUtils"; -function humanize(value: string): string { - return value - .replace(/([a-z])([A-Z])/g, "$1 $2") - .replaceAll(/[_-]+/g, " ") - .replace(/^\w/, (first) => first.toUpperCase()); -} - export default function ComboCatalogFiltersComponent({ filters, onChange, @@ -31,104 +29,60 @@ export default function ComboCatalogFiltersComponent({ return (
-
- onChange({ query: event.target.value })} - className="min-w-0 flex-1" - /> - -
- - {totalCount} {totalCount === 1 ? t("comboCountSingle") : t("comboCountPlural")} - - {hasActiveFilters && ( - - )} -
-
+ onChange({ query })} + totalCount={totalCount} + countLabel={totalCount === 1 ? t("comboCountSingle") : t("comboCountPlural")} + hasActiveFilters={hasActiveFilters} + onClear={onClear} + />
- + onChange({ strategy })} + > + + + - + onChange({ status })} + > + + + + - + onChange({ testResult })} + > + + - + onChange({ minMembers })} + /> - + onChange({ maxMembers })} + />
); diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx index 42bc1a685ddb..b86202e91975 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogFilters.tsx @@ -1,15 +1,136 @@ "use client"; import { useTranslations } from "next-intl"; -import { Button, Input } from "@/shared/components"; -import { parseNonNegativeInt } from "./catalogUrlState"; +import { + FilterNumberInput, + FilterSearchRow, + FilterSelect, + HumanizedOptions, + TestResultOptions, +} from "./CatalogFilterFields"; import type { CatalogFilters } from "./modelCatalogUtils"; -function humanize(value: string): string { - return value - .replace(/([a-z])([A-Z])/g, "$1 $2") - .replaceAll(/[_-]+/g, " ") - .replace(/^\w/, (first) => first.toUpperCase()); +type FilterChange = (patch: Partial) => void; + +/** Selects whose choices come from the loaded catalog (provider, type, subtype, capability). */ +function ModelCatalogOptionFilters({ + filters, + onChange, + providerOptions, + typeOptions, + subtypeOptions, + capabilityOptions, +}: { + filters: CatalogFilters; + onChange: FilterChange; + providerOptions: Array<[string, string]>; + typeOptions: string[]; + subtypeOptions: string[]; + capabilityOptions: string[]; +}) { + const t = useTranslations("modelCatalog"); + + return ( + <> + onChange({ providerId })} + > + + {providerOptions.map(([id, name]) => ( + + ))} + + + onChange({ type })}> + + + + + onChange({ subtype })} + > + + + + + onChange({ capability })} + > + + + + + ); +} + +/** Filters with fixed choices (pricing, provider health, test result) and numeric minimums. */ +function ModelCatalogFixedFilters({ + filters, + onChange, +}: { + filters: CatalogFilters; + onChange: FilterChange; +}) { + const t = useTranslations("modelCatalog"); + + return ( + <> + onChange({ pricing })} + > + + + + + + onChange({ providerHealth })} + > + + + + + + + onChange({ testResult })} + > + + + + onChange({ minContextLength })} + /> + + onChange({ minMaxOutputTokens })} + /> + + ); } export default function ModelCatalogFiltersComponent({ @@ -37,168 +158,27 @@ export default function ModelCatalogFiltersComponent({ return (
-
- onChange({ query: event.target.value })} - className="min-w-0 flex-1" - /> - -
- - {totalCount} {totalCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} - - {hasActiveFilters && ( - - )} -
-
+ onChange({ query })} + totalCount={totalCount} + countLabel={totalCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} + hasActiveFilters={hasActiveFilters} + onClear={onClear} + />
- - - - - - - - - - - - - - - - - + +
); From 1217d823cf4c15b11f2c5d44f94618f46e4dcae1 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 20:04:09 +0300 Subject: [PATCH 12/16] refactor(dashboard): split catalog tables into smaller helpers for the complexity gate Behaviour-preserving split with the same props, DOM, classes and i18n keys: - CatalogTableParts: plain and actions headings, selection checkbox cells and the paging footer that both tables rendered inline. - ModelCatalogTable renders its header and rows through ModelCatalogTableHead and ModelCatalogTableRow, with the provider, type, capabilities and flags cells as small components. Its props block keeps its place; only the labels shape gets a name. - ComboCatalogTable does the same with ComboCatalogTableHead, ComboCatalogTableRow and ComboMembersCell; its props move to the ComboCatalogTableProps interface with the same members. --- .../dashboard/models/CatalogTableParts.tsx | 119 ++++ .../dashboard/models/ComboCatalogTable.tsx | 386 ++++++------ .../dashboard/models/ModelCatalogTable.tsx | 552 ++++++++++-------- 3 files changed, 637 insertions(+), 420 deletions(-) create mode 100644 src/app/(dashboard)/dashboard/models/CatalogTableParts.tsx diff --git a/src/app/(dashboard)/dashboard/models/CatalogTableParts.tsx b/src/app/(dashboard)/dashboard/models/CatalogTableParts.tsx new file mode 100644 index 000000000000..9e49b55bd01b --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/CatalogTableParts.tsx @@ -0,0 +1,119 @@ +"use client"; + +import type { ReactNode } from "react"; +import { useTranslations } from "next-intl"; +import { Button } from "@/shared/components"; + +// Cells and footer shared by the model and combo catalog tables; the markup matches what each +// table rendered inline, so both keep the same DOM, labels and classes. + +const CHECKBOX_CLASS = + "rounded border-black/20 text-primary focus:ring-primary dark:border-white/20"; + +/** A column heading without sorting. */ +export function PlainHeading({ children }: { children: ReactNode }) { + return ( +
+ ); +} + +/** The right-aligned heading above the per-row test buttons. */ +export function ActionsHeading() { + const t = useTranslations("modelCatalog"); + return ( + + ); +} + +/** Page-wide selection checkbox; `indeterminate` marks a partly selected page. */ +export function SelectAllHeaderCell({ + checked, + indeterminate, + onToggle, + label, +}: { + checked: boolean; + indeterminate: boolean; + onToggle: () => void; + label: string; +}) { + return ( + + ); +} + +export function SelectRowCell({ + checked, + onToggle, + label, +}: { + checked: boolean; + onToggle: () => void; + label: string; +}) { + return ( + + ); +} + +/** Result summary (the children) plus previous/next paging under a catalog table. */ +export function CatalogTableFooter({ + page, + pageCount, + onPrevious, + onNext, + children, +}: { + page: number; + pageCount: number; + onPrevious: () => void; + onNext: () => void; + children: ReactNode; +}) { + const t = useTranslations("modelCatalog"); + return ( +
+

+ {children} +

+
+ {t("page", { page, pageCount })} + + +
+
+ ); +} diff --git a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx index 3e49c641f63b..fc7846d339c4 100644 --- a/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ComboCatalogTable.tsx @@ -3,6 +3,13 @@ import { useTranslations } from "next-intl"; import { Badge, Button } from "@/shared/components"; import CatalogTestBadge from "./CatalogTestBadge"; +import { + ActionsHeading, + CatalogTableFooter, + PlainHeading, + SelectAllHeaderCell, + SelectRowCell, +} from "./CatalogTableParts"; import type { CatalogTestResult } from "./catalogTestStorage"; import { getComboTestKey } from "./catalogTestStorage"; import type { ComboCatalogRow, ComboSortDirection, ComboSortField } from "./comboCatalogUtils"; @@ -54,25 +61,172 @@ function SortableHeading({ ); } -export default function ComboCatalogTable({ - rows, +function ComboCatalogTableHead({ sortField, sortDirection, onSort, - page, - pageCount, - startIndex, - totalCount, - selectedIds, - onToggleSelect, + allOnPageSelected, + someOnPageSelected, onToggleSelectAll, +}: { + sortField: ComboSortField; + sortDirection: ComboSortDirection; + onSort: (field: ComboSortField) => void; + allOnPageSelected: boolean; + someOnPageSelected: boolean; + onToggleSelectAll: () => void; +}) { + const t = useTranslations("modelCatalog"); + return ( + + + + + + + + {t("healthTest")} + + + + ); +} + +/** Member count plus up to three member chips; nested combos show their translated label. */ +function ComboMembersCell({ combo }: { combo: ComboCatalogRow }) { + const t = useTranslations("modelCatalog"); + return ( + + ); +} + +function ComboCatalogTableRow({ + combo, + isSelected, testResults, activeTestingKeys, + onToggleSelect, onTestCombo, - onPrevious, - onNext, - bulkRunning = false, + bulkRunning, }: { + combo: ComboCatalogRow; + isSelected: boolean; + testResults: Record; + activeTestingKeys: ReadonlySet; + onToggleSelect: (id: string) => void; + onTestCombo: (comboName: string) => void; + bulkRunning: boolean; +}) { + const t = useTranslations("modelCatalog"); + const testKey = getComboTestKey(combo.name); + const isTesting = activeTestingKeys.has(testKey); + const result = testResults[testKey]; + + return ( + + onToggleSelect(combo.id)} + label={t("selectCombo", { name: combo.name })} + /> + + + + + + + + ); +} + +interface ComboCatalogTableProps { rows: ComboCatalogRow[]; sortField: ComboSortField; sortDirection: ComboSortDirection; @@ -91,7 +245,27 @@ export default function ComboCatalogTable({ onNext: () => void; /** A bulk run owns the runner; per-row tests wait until it ends. */ bulkRunning?: boolean; -}) { +} + +export default function ComboCatalogTable({ + rows, + sortField, + sortDirection, + onSort, + page, + pageCount, + startIndex, + totalCount, + selectedIds, + onToggleSelect, + onToggleSelectAll, + testResults, + activeTestingKeys, + onTestCombo, + onPrevious, + onNext, + bulkRunning = false, +}: ComboCatalogTableProps) { const t = useTranslations("modelCatalog"); const allOnPageSelected = rows.length > 0 && rows.every((row) => selectedIds.has(row.id)); const someOnPageSelected = rows.some((row) => selectedIds.has(row.id)) && !allOnPageSelected; @@ -109,172 +283,38 @@ export default function ComboCatalogTable({ >
Model catalog across all providers{t("tableCaption")}
- Health Test + {t("healthTest")} - Actions + {t("actions")}
+ {children} + + {t("actions")} + + { + if (el) el.indeterminate = indeterminate; + }} + onChange={onToggle} + aria-label={label} + className={CHECKBOX_CLASS} + /> + + +
+ + {combo.memberCount}{" "} + {combo.memberCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} + + {combo.models.length > 0 && ( +
+ {combo.models.slice(0, 3).map((m, idx) => ( + + {m.label || + (m.kind === "combo-ref" + ? t("comboRefMember", { name: m.model }) + : m.model.split("/").pop())} + + ))} + {combo.models.length > 3 && ( + + {t("moreMembers", { count: combo.models.length - 3 })} + + )} +
+ )} +
+
{combo.displayName}
+ {combo.displayName !== combo.name && ( + {combo.name} + )} + {combo.description && ( +

{combo.description}

+ )} +
+ + {humanize(combo.strategy)} + + + + {combo.status === "active" ? t("active") : t("paused")} + + + + + +
- - - - - - - - - - - + - {rows.map((combo) => { - const isSelected = selectedIds.has(combo.id); - const testKey = getComboTestKey(combo.name); - const isTesting = activeTestingKeys.has(testKey); - const result = testResults[testKey]; - - return ( - - - - - - - - - - ); - })} + {rows.map((combo) => ( + + ))}
{t("combosTableCaption")}
- { - if (el) el.indeterminate = someOnPageSelected; - }} - onChange={onToggleSelectAll} - aria-label={t("selectAllCombos")} - className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" - /> - - {t("healthTest")} - - {t("actions")} -
- onToggleSelect(combo.id)} - aria-label={t("selectCombo", { name: combo.name })} - className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" - /> - -
{combo.displayName}
- {combo.displayName !== combo.name && ( - {combo.name} - )} - {combo.description && ( -

- {combo.description} -

- )} -
- - {humanize(combo.strategy)} - - - - {combo.memberCount}{" "} - {combo.memberCount === 1 ? t("modelCountSingle") : t("modelCountPlural")} - - {combo.models.length > 0 && ( -
- {combo.models.slice(0, 3).map((m, idx) => ( - - {m.label || - (m.kind === "combo-ref" - ? t("comboRefMember", { name: m.model }) - : m.model.split("/").pop())} - - ))} - {combo.models.length > 3 && ( - - {t("moreMembers", { count: combo.models.length - 3 })} - - )} -
- )} -
- - {combo.status === "active" ? t("active") : t("paused")} - - - - - -
-
-

- {t("showingCombos", { - first: formatCount(firstResult), - last: formatCount(lastResult), - total: formatCount(totalCount), - })} -

-
- {t("page", { page, pageCount })} - - -
-
+ + {t("showingCombos", { + first: formatCount(firstResult), + last: formatCount(lastResult), + total: formatCount(totalCount), + })} + ); } diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx index 9407feda5e1e..b0e08a05e965 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx @@ -3,6 +3,13 @@ import { useTranslations } from "next-intl"; import { Badge, Button } from "@/shared/components"; import CatalogTestBadge from "./CatalogTestBadge"; +import { + ActionsHeading, + CatalogTableFooter, + PlainHeading, + SelectAllHeaderCell, + SelectRowCell, +} from "./CatalogTableParts"; import type { CatalogTestResult } from "./catalogTestStorage"; import { getModelTestKey } from "./catalogTestStorage"; import type { CatalogModelRow, CatalogSortDirection, CatalogSortField } from "./modelCatalogUtils"; @@ -77,6 +84,270 @@ function SortableHeading({ ); } +type ModelCatalogLabels = { + provider: string; + model: string; + type: string; + capabilities: string; + context: string; + output: string; + flags: string; + custom: string; + free: string; +}; + +type ProviderHealth = "healthy" | "degraded" | "down"; + +function ModelCatalogTableHead({ + labels, + sortField, + sortDirection, + onSort, + allOnPageSelected, + someOnPageSelected, + onToggleSelectAll, + showActions, +}: { + labels: ModelCatalogLabels; + sortField: CatalogSortField; + sortDirection: CatalogSortDirection; + onSort: (field: CatalogSortField) => void; + allOnPageSelected: boolean; + someOnPageSelected: boolean; + onToggleSelectAll?: () => void; + showActions: boolean; +}) { + const t = useTranslations("modelCatalog"); + return ( + + + {onToggleSelectAll && ( + + )} + + + + {labels.capabilities || t("capabilities")} + + + {labels.flags || t("flags")} + {t("healthTest")} + {showActions && } + + + ); +} + +function ModelProviderCell({ + model, + providerHealth, +}: { + model: CatalogModelRow; + providerHealth?: ProviderHealth; +}) { + const t = useTranslations("modelCatalog"); + return ( + +
+ {model.provider} + {providerHealth && providerHealth !== "healthy" && ( + + {providerHealth === "degraded" ? t("degraded") : t("down")} + + )} +
+ {model.providerId} + + ); +} + +function ModelTypeCell({ model }: { model: CatalogModelRow }) { + return ( + + {humanize(model.type)} + {model.subtype && ( + {humanize(model.subtype)} + )} + + ); +} + +/** The first three capability badges, then a "+N" badge whose label lists the rest. */ +function ModelCapabilitiesCell({ capabilities }: { capabilities: string[] }) { + const t = useTranslations("modelCatalog"); + const additionalCapabilities = capabilities.slice(3); + return ( + + {capabilities.length > 0 ? ( +
+ {capabilities.slice(0, 3).map((capability) => ( + + {capability} + + ))} + {additionalCapabilities.length > 0 && ( + + + +{additionalCapabilities.length} + + + )} +
+ ) : ( + + — + + )} + + ); +} + +function ModelFlagsCell({ model, labels }: { model: CatalogModelRow; labels: ModelCatalogLabels }) { + const t = useTranslations("modelCatalog"); + return ( + +
+ {model.custom === true && ( + + {labels.custom || t("custom")} + + )} + {model.free === true && ( + + {labels.free || t("free")} + + )} + {model.custom !== true && model.free !== true && ( + + — + + )} +
+ + ); +} + +function ModelCatalogTableRow({ + model, + labels, + selectedIds, + testResults, + activeTestingKeys, + providerHealthMap, + onToggleSelect, + onTestModel, + bulkRunning, +}: { + model: CatalogModelRow; + labels: ModelCatalogLabels; + selectedIds: Set; + testResults: Record; + activeTestingKeys: ReadonlySet; + providerHealthMap: Record; + onToggleSelect?: (id: string) => void; + onTestModel?: (providerId: string, modelId: string) => void; + bulkRunning: boolean; +}) { + const t = useTranslations("modelCatalog"); + const common = useTranslations("common"); + const rowId = `${model.providerId}:${model.id}`; + const isSelected = selectedIds.has(rowId); + const testKey = getModelTestKey(model.providerId, model.id); + const isTesting = activeTestingKeys.has(testKey); + const result = testResults[testKey]; + + const capabilities = capabilityLabels(model, { + input: common("input"), + output: common("output"), + }); + return ( + + {onToggleSelect && ( + onToggleSelect(rowId)} + label={t("selectModel", { name: model.name })} + /> + )} + + + {model.name} + {model.id} + + + + + {formatOptionalCount(model.context_length)} + + + {formatOptionalCount(model.max_output_tokens)} + + + + + + {onTestModel && ( + + + + )} + + ); +} + export default function ModelCatalogTable({ rows, sortField, @@ -112,17 +383,7 @@ export default function ModelCatalogTable({ error: boolean; onPrevious: () => void; onNext: () => void; - labels: { - provider: string; - model: string; - type: string; - capabilities: string; - context: string; - output: string; - flags: string; - custom: string; - free: string; - }; + labels: ModelCatalogLabels; selectedIds?: Set; onToggleSelect?: (id: string) => void; onToggleSelectAll?: () => void; @@ -134,7 +395,6 @@ export default function ModelCatalogTable({ bulkRunning?: boolean; }) { const t = useTranslations("modelCatalog"); - const common = useTranslations("common"); const firstResult = startIndex + 1; const lastResult = startIndex + rows.length; @@ -147,246 +407,44 @@ export default function ModelCatalogTable({
- - - {onToggleSelectAll && ( - - )} - - - - - - - - - {onTestModel && ( - - )} - - + - {rows.map((model) => { - const rowId = `${model.providerId}:${model.id}`; - const isSelected = selectedIds.has(rowId); - const testKey = getModelTestKey(model.providerId, model.id); - const isTesting = activeTestingKeys.has(testKey); - const result = testResults[testKey]; - const providerHealth = providerHealthMap[model.providerId]; - - const capabilities = capabilityLabels(model, { - input: common("input"), - output: common("output"), - }); - const additionalCapabilities = capabilities.slice(3); - return ( - - {onToggleSelect && ( - - )} - - - - - - - - - {onTestModel && ( - - )} - - ); - })} + {rows.map((model) => ( + + ))}
{t("tableCaption")}
- { - if (el) el.indeterminate = someOnPageSelected; - }} - onChange={onToggleSelectAll} - aria-label={t("selectAllModels")} - className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" - /> - - {labels.capabilities || t("capabilities")} - - {labels.flags || t("flags")} - - {t("healthTest")} - - {t("actions")} -
- onToggleSelect(rowId)} - aria-label={t("selectModel", { name: model.name })} - className="rounded border-black/20 text-primary focus:ring-primary dark:border-white/20" - /> - -
- {model.provider} - {providerHealth && providerHealth !== "healthy" && ( - - {providerHealth === "degraded" ? t("degraded") : t("down")} - - )} -
- - {model.providerId} - -
- - {model.name} - - - {model.id} - - - {humanize(model.type)} - {model.subtype && ( - - {humanize(model.subtype)} - - )} - - {capabilities.length > 0 ? ( -
- {capabilities.slice(0, 3).map((capability) => ( - - {capability} - - ))} - {additionalCapabilities.length > 0 && ( - - - +{additionalCapabilities.length} - - - )} -
- ) : ( - - — - - )} -
- {formatOptionalCount(model.context_length)} - - {formatOptionalCount(model.max_output_tokens)} - -
- {model.custom === true && ( - - {labels.custom || t("custom")} - - )} - {model.free === true && ( - - {labels.free || t("free")} - - )} - {model.custom !== true && model.free !== true && ( - - — - - )} -
-
- - - -
-
-

- {t("showingModels", { - first: formatCount(firstResult), - last: formatCount(lastResult), - total: formatCount(totalCount), - })} - {loading && {t("refreshing")}} - {error && {t("refreshFailed")}} -

-
- {t("page", { page, pageCount })} - - -
-
+ + {t("showingModels", { + first: formatCount(firstResult), + last: formatCount(lastResult), + total: formatCount(totalCount), + })} + {loading && {t("refreshing")}} + {error && {t("refreshFailed")}} + ); } From e64c4fba6e7f125312dc7d7c6976472b78fe2cb2 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 21:22:34 +0300 Subject: [PATCH 13/16] refactor(dashboard): isolate catalog health-test requests --- .../dashboard/models/catalogTestRequests.ts | 83 +++++++++++++++++++ .../dashboard/models/useCatalogTestRunner.ts | 67 ++------------- 2 files changed, 90 insertions(+), 60 deletions(-) create mode 100644 src/app/(dashboard)/dashboard/models/catalogTestRequests.ts diff --git a/src/app/(dashboard)/dashboard/models/catalogTestRequests.ts b/src/app/(dashboard)/dashboard/models/catalogTestRequests.ts new file mode 100644 index 000000000000..06e5242b20a8 --- /dev/null +++ b/src/app/(dashboard)/dashboard/models/catalogTestRequests.ts @@ -0,0 +1,83 @@ +import type { ModelTestBatch } from "./catalogBulkUtils"; +import { + mapBatchResponse, + mapComboResponse, + mapRequestFailure, + mapSingleModelResponse, + readJsonBody, + type BatchModelTestResponse, + type ComboTestResponse, + type SingleModelTestResponse, +} from "./catalogTestResponses"; +import type { CatalogTestResult } from "./catalogTestStorage"; + +// One health-test request each. A request that fails (network error, abort, unreadable body) +// resolves to error results rather than rejecting, so callers always get something to store. + +const JSON_HEADERS = { "Content-Type": "application/json" }; + +export async function requestComboTest( + comboName: string, + signal: AbortSignal +): Promise { + try { + const res = await fetch("/api/combos/test", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ comboName }), + signal, + }); + const body = await readJsonBody(res); + return mapComboResponse(comboName, res, body, Date.now()); + } catch (failure) { + return mapRequestFailure({ targetType: "combo", comboName }, failure, Date.now()); + } +} + +export async function requestSingleModelTest( + providerId: string, + modelId: string, + signal: AbortSignal +): Promise { + try { + const res = await fetch("/api/models/test", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ providerId, modelId }), + signal, + }); + const body = await readJsonBody(res); + return mapSingleModelResponse(providerId, modelId, res, body, Date.now()); + } catch (failure) { + return mapRequestFailure({ targetType: "model", providerId, modelId }, failure, Date.now()); + } +} + +export async function requestModelBatchTest( + batch: ModelTestBatch, + signal: AbortSignal +): Promise { + try { + const res = await fetch("/api/models/test-all", { + method: "POST", + headers: JSON_HEADERS, + body: JSON.stringify({ + providerId: batch.providerId, + modelIds: batch.modelIds, + respectRateLimit: true, + }), + signal, + }); + const body = await readJsonBody(res); + return mapBatchResponse(batch, res, body, Date.now()); + } catch (failure) { + const testedAt = Date.now(); + return batch.modelIds.map((modelId) => + mapRequestFailure( + { targetType: "model", providerId: batch.providerId, modelId }, + failure, + testedAt + ) + ); + } +} diff --git a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts index f6cbce85571b..d88344c5eeee 100644 --- a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts +++ b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts @@ -12,15 +12,10 @@ import { type ModelTestTarget, } from "./catalogBulkUtils"; import { - mapBatchResponse, - mapComboResponse, - mapRequestFailure, - mapSingleModelResponse, - readJsonBody, - type BatchModelTestResponse, - type ComboTestResponse, - type SingleModelTestResponse, -} from "./catalogTestResponses"; + requestComboTest, + requestSingleModelTest, + requestModelBatchTest, +} from "./catalogTestRequests"; import { clearCatalogTestResults, getComboTestKey, @@ -40,7 +35,6 @@ export interface ProgressState { } const IDLE_PROGRESS: ProgressState = { kind: "models", completed: 0, total: 0, cancelled: false }; -const JSON_HEADERS = { "Content-Type": "application/json" }; export function useCatalogTestRunner() { const [testResults, setTestResults] = useState>({}); @@ -108,19 +102,7 @@ export function useCatalogTestRunner() { const key = getComboTestKey(comboName); if (!claimActiveKey(key, signal)) return; try { - const res = await fetch("/api/combos/test", { - method: "POST", - headers: JSON_HEADERS, - body: JSON.stringify({ comboName }), - signal, - }); - const body = await readJsonBody(res); - persist([mapComboResponse(comboName, res, body, Date.now())], signal); - } catch (failure) { - persist( - [mapRequestFailure({ targetType: "combo", comboName }, failure, Date.now())], - signal - ); + persist([await requestComboTest(comboName, signal)], signal); } finally { releaseActiveKey(key, signal); } @@ -134,19 +116,7 @@ export function useCatalogTestRunner() { const key = getModelTestKey(providerId, modelId); if (!claimActiveKey(key, signal)) return; try { - const res = await fetch("/api/models/test", { - method: "POST", - headers: JSON_HEADERS, - body: JSON.stringify({ providerId, modelId }), - signal, - }); - const body = await readJsonBody(res); - persist([mapSingleModelResponse(providerId, modelId, res, body, Date.now())], signal); - } catch (failure) { - persist( - [mapRequestFailure({ targetType: "model", providerId, modelId }, failure, Date.now())], - signal - ); + persist([await requestSingleModelTest(providerId, modelId, signal)], signal); } finally { releaseActiveKey(key, signal); } @@ -192,30 +162,7 @@ export function useCatalogTestRunner() { try { await runModelBatches(buildModelBatches(unique), signal, async (batch) => { try { - const res = await fetch("/api/models/test-all", { - method: "POST", - headers: JSON_HEADERS, - body: JSON.stringify({ - providerId: batch.providerId, - modelIds: batch.modelIds, - respectRateLimit: true, - }), - signal, - }); - const body = await readJsonBody(res); - persist(mapBatchResponse(batch, res, body, Date.now()), signal); - } catch (failure) { - const testedAt = Date.now(); - persist( - batch.modelIds.map((modelId) => - mapRequestFailure( - { targetType: "model", providerId: batch.providerId, modelId }, - failure, - testedAt - ) - ), - signal - ); + persist(await requestModelBatchTest(batch, signal), signal); } finally { advanceRun(controller, batch.modelIds.length); } From 38fd55373d79b5739d556fe5dce32e42b366d6d8 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 21:39:51 +0300 Subject: [PATCH 14/16] refactor(dashboard): split catalog test runner lifecycle hooks --- .../dashboard/models/useCatalogTestRunner.ts | 127 ++++++++++++------ 1 file changed, 89 insertions(+), 38 deletions(-) diff --git a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts index d88344c5eeee..681f0ae44670 100644 --- a/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts +++ b/src/app/(dashboard)/dashboard/models/useCatalogTestRunner.ts @@ -36,7 +36,7 @@ export interface ProgressState { const IDLE_PROGRESS: ProgressState = { kind: "models", completed: 0, total: 0, cancelled: false }; -export function useCatalogTestRunner() { +function useCatalogRunnerState() { const [testResults, setTestResults] = useState>({}); const [running, setRunning] = useState(false); const [activeItemKeys, setActiveItemKeys] = useState>(new Set()); @@ -97,6 +97,86 @@ export function useCatalogTestRunner() { } }, []); + return { + testResults, + setTestResults, + running, + setRunning, + activeItemKeys, + setActiveItemKeys, + activeSignalsRef, + progress, + setProgress, + mountedRef, + runControllerRef, + singleControllersRef, + persist, + claimActiveKey, + releaseActiveKey, + withSingleController, + }; +} + +function useCatalogRunProgress(state: ReturnType) { + const { + runControllerRef, + setRunning, + setProgress, + mountedRef, + activeSignalsRef, + setActiveItemKeys, + } = state; + const startRun = useCallback( + (kind: BulkRunKind, total: number) => { + runControllerRef.current?.abort(); + const controller = new AbortController(); + runControllerRef.current = controller; + setRunning(true); + setProgress({ kind, completed: 0, total, cancelled: false }); + return controller; + }, + [runControllerRef, setProgress, setRunning] + ); + + /** Only the run that still owns the runner may move the progress bar or end the run. */ + const advanceRun = useCallback( + (controller: AbortController, count: number) => { + if (!mountedRef.current || runControllerRef.current !== controller) return; + setProgress((current) => ({ + ...current, + completed: Math.min(current.completed + count, current.total), + })); + }, + [mountedRef, runControllerRef, setProgress] + ); + + const finishRun = useCallback( + (controller: AbortController) => { + if (runControllerRef.current !== controller) return; + runControllerRef.current = null; + if (mountedRef.current) setRunning(false); + }, + [mountedRef, runControllerRef, setRunning] + ); + + const cancelTest = useCallback(() => { + const controller = runControllerRef.current; + if (!controller) return; + runControllerRef.current = null; + controller.abort(); + setRunning(false); + for (const [key, signal] of activeSignalsRef.current) { + if (signal === controller.signal) activeSignalsRef.current.delete(key); + } + setActiveItemKeys(new Set(activeSignalsRef.current.keys())); + setProgress((current) => ({ ...current, cancelled: true })); + }, [activeSignalsRef, runControllerRef, setActiveItemKeys, setProgress, setRunning]); + + return { startRun, advanceRun, finishRun, cancelTest }; +} + +function useCatalogRowTests(state: ReturnType) { + const { claimActiveKey, releaseActiveKey, persist, withSingleController } = state; const runComboTest = useCallback( async (comboName: string, signal: AbortSignal) => { const key = getComboTestKey(comboName); @@ -129,30 +209,14 @@ export function useCatalogTestRunner() { [runComboTest, withSingleController] ); - const startRun = useCallback((kind: BulkRunKind, total: number) => { - runControllerRef.current?.abort(); - const controller = new AbortController(); - runControllerRef.current = controller; - setRunning(true); - setProgress({ kind, completed: 0, total, cancelled: false }); - return controller; - }, []); - - /** Only the run that still owns the runner may move the progress bar or end the run. */ - const advanceRun = useCallback((controller: AbortController, count: number) => { - if (!mountedRef.current || runControllerRef.current !== controller) return; - setProgress((current) => ({ - ...current, - completed: Math.min(current.completed + count, current.total), - })); - }, []); - - const finishRun = useCallback((controller: AbortController) => { - if (runControllerRef.current !== controller) return; - runControllerRef.current = null; - if (mountedRef.current) setRunning(false); - }, []); + return { runComboTest, testSingleModel, testSingleCombo }; +} +export function useCatalogTestRunner() { + const state = useCatalogRunnerState(); + const { testResults, setTestResults, running, activeItemKeys, progress, persist } = state; + const { runComboTest, testSingleModel, testSingleCombo } = useCatalogRowTests(state); + const { startRun, advanceRun, finishRun, cancelTest } = useCatalogRunProgress(state); const testBulkModels = useCallback( async (targets: ModelTestTarget[]) => { const unique = dedupeModelTargets(targets); @@ -195,23 +259,10 @@ export function useCatalogTestRunner() { [advanceRun, finishRun, runComboTest, startRun] ); - const cancelTest = useCallback(() => { - const controller = runControllerRef.current; - if (!controller) return; - runControllerRef.current = null; - controller.abort(); - setRunning(false); - for (const [key, signal] of activeSignalsRef.current) { - if (signal === controller.signal) activeSignalsRef.current.delete(key); - } - setActiveItemKeys(new Set(activeSignalsRef.current.keys())); - setProgress((current) => ({ ...current, cancelled: true })); - }, []); - const clearResults = useCallback(() => { clearCatalogTestResults(); setTestResults({}); - }, []); + }, [setTestResults]); return { testResults, From 45ffd66321b7ef307851425a1ba9a6c9c7f08c75 Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Sat, 26 Sep 2026 22:04:53 +0300 Subject: [PATCH 15/16] refactor(dashboard): compose catalog page from bounded hooks and panels --- .../dashboard/models/ModelCatalogTable.tsx | 50 +- src/app/(dashboard)/dashboard/models/page.tsx | 937 ++++++++++++------ 2 files changed, 663 insertions(+), 324 deletions(-) diff --git a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx index b0e08a05e965..0950f54082eb 100644 --- a/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx +++ b/src/app/(dashboard)/dashboard/models/ModelCatalogTable.tsx @@ -348,29 +348,7 @@ function ModelCatalogTableRow({ ); } -export default function ModelCatalogTable({ - rows, - sortField, - sortDirection, - onSort, - page, - pageCount, - startIndex, - totalCount, - loading, - error, - onPrevious, - onNext, - labels, - selectedIds = new Set(), - onToggleSelect, - onToggleSelectAll, - testResults = {}, - activeTestingKeys = new Set(), - onTestModel, - providerHealthMap = {}, - bulkRunning = false, -}: { +interface ModelCatalogTableProps { rows: CatalogModelRow[]; sortField: CatalogSortField; sortDirection: CatalogSortDirection; @@ -393,7 +371,31 @@ export default function ModelCatalogTable({ providerHealthMap?: Record; /** A bulk run owns the runner; per-row tests wait until it ends. */ bulkRunning?: boolean; -}) { +} + +export default function ModelCatalogTable({ + rows, + sortField, + sortDirection, + onSort, + page, + pageCount, + startIndex, + totalCount, + loading, + error, + onPrevious, + onNext, + labels, + selectedIds = new Set(), + onToggleSelect, + onToggleSelectAll, + testResults = {}, + activeTestingKeys = new Set(), + onTestModel, + providerHealthMap = {}, + bulkRunning = false, +}: ModelCatalogTableProps) { const t = useTranslations("modelCatalog"); const firstResult = startIndex + 1; const lastResult = startIndex + rows.length; diff --git a/src/app/(dashboard)/dashboard/models/page.tsx b/src/app/(dashboard)/dashboard/models/page.tsx index 6df8289fb997..0b53538ace00 100644 --- a/src/app/(dashboard)/dashboard/models/page.tsx +++ b/src/app/(dashboard)/dashboard/models/page.tsx @@ -77,7 +77,7 @@ function setUrlParams(params: URLSearchParams) { } } -export default function ModelCatalogPage() { +function useCatalogPageState() { const t = useTranslations("modelCatalog"); // URL-driven state starts from the defaults the server renders; the mount effect below @@ -113,39 +113,92 @@ export default function ModelCatalogPage() { const [rawModelFilters, setModelFilters] = useState(DEFAULT_MODEL_FILTERS); const [rawComboFilters, setComboFilters] = useState(DEFAULT_COMBO_FILTERS); - // Test Runner Hook + const runner = useCatalogTestRunner(); + return { + ...runner, + activeTab, + setActiveTab, + urlApplied, + setUrlApplied, + pendingBulkRun, + setPendingBulkRun, + models, + setModels, + modelsLoading, + setModelsLoading, + modelsError, + setModelsError, + modelSortField, + setModelSortField, + modelSortDirection, + setModelSortDirection, + requestedModelPage, + setRequestedModelPage, + selectedModelIds, + setSelectedModelIds, + combos, + setCombos, + combosLoading, + setCombosLoading, + combosError, + setCombosError, + comboSortField, + setComboSortField, + comboSortDirection, + setComboSortDirection, + requestedComboPage, + setRequestedComboPage, + selectedComboIds, + setSelectedComboIds, + providerHealthMap, + setProviderHealthMap, + rawModelFilters, + setModelFilters, + rawComboFilters, + setComboFilters, + t, + }; +} +// Load provider health matrix +async function fetchCatalogHealth( + controller: AbortController, + setProviderHealthMap: React.Dispatch< + React.SetStateAction> + > +) { + try { + const response = await fetch("/api/providers/health-matrix", { signal: controller.signal }); + if (!response.ok) return; + const payload: unknown = await response.json(); + if (typeof payload === "object" && payload !== null && "providers" in payload) { + const list = ( + payload as { + providers: Array<{ provider: string; state: "healthy" | "degraded" | "down" }>; + } + ).providers; + const map: Record = {}; + for (const item of list || []) { + if (item.provider) map[item.provider] = item.state; + } + setProviderHealthMap(map); + } + } catch { + // Soft fail + } +} + +function useCatalogPageLoading(state: ReturnType) { const { - testResults, - running, - activeItemKeys, - progress, - testSingleModel, - testSingleCombo, - testBulkModels, - testBulkCombos, - cancelTest, - clearResults, - } = useCatalogTestRunner(); + setModels, + setModelsLoading, + setModelsError, + setCombos, + setCombosLoading, + setCombosError, + setProviderHealthMap, + } = state; const requestController = useRef(null); - - // Deep links and Back/Forward: read the query string after mount (DashboardLayout pattern). - useEffect(() => { - const applyUrlState = () => { - const params = new URLSearchParams(window.location.search); - setActiveTab(parseCatalogTab(params)); - setModelFilters(parseModelFilters(params)); - setComboFilters(parseComboFilters(params)); - setUrlApplied(true); - }; - const timer = window.setTimeout(applyUrlState, 0); - window.addEventListener("popstate", applyUrlState); - return () => { - window.clearTimeout(timer); - window.removeEventListener("popstate", applyUrlState); - }; - }, []); - // Data Loading const loadData = useCallback(async () => { requestController.current?.abort(); @@ -190,31 +243,18 @@ export default function ModelCatalogPage() { } }; - // Load provider health matrix - const fetchHealth = async () => { - try { - const response = await fetch("/api/providers/health-matrix", { signal: controller.signal }); - if (!response.ok) return; - const payload: unknown = await response.json(); - if (typeof payload === "object" && payload !== null && "providers" in payload) { - const list = ( - payload as { - providers: Array<{ provider: string; state: "healthy" | "degraded" | "down" }>; - } - ).providers; - const map: Record = {}; - for (const item of list || []) { - if (item.provider) map[item.provider] = item.state; - } - setProviderHealthMap(map); - } - } catch { - // Soft fail - } - }; - + const fetchHealth = () => fetchCatalogHealth(controller, setProviderHealthMap); await Promise.allSettled([fetchModels(), fetchCombos(), fetchHealth()]); - }, []); + }, [ + requestController, + setCombos, + setCombosError, + setCombosLoading, + setModels, + setModelsError, + setModelsLoading, + setProviderHealthMap, + ]); useEffect(() => { const timer = window.setTimeout(() => { @@ -224,7 +264,7 @@ export default function ModelCatalogPage() { window.clearTimeout(timer); requestController.current?.abort(); }; - }, [loadData]); + }, [loadData, requestController]); const refreshAll = useCallback(() => { setModelsLoading(true); @@ -232,8 +272,13 @@ export default function ModelCatalogPage() { setModelsError(false); setCombosError(false); void loadData(); - }, [loadData]); + }, [loadData, setCombosError, setCombosLoading, setModelsError, setModelsLoading]); + + return { loadData, refreshAll }; +} +function useCatalogPageOptions(state: ReturnType) { + const { models, combos, rawModelFilters, rawComboFilters } = state; // Derived filter options for models const providerOptions = useMemo( () => @@ -294,54 +339,34 @@ export default function ModelCatalogPage() { [rawComboFilters, comboOptionsKnown, strategyOptions] ); - // The only URL writer: one write per change of tab or (normalised) filters, never before the - // query string has been read, and skipped when the URL already matches. - useEffect(() => { - if (!urlApplied) return; - setUrlParams(buildCatalogSearchParams(activeTab, modelFilters, comboFilters)); - }, [urlApplied, activeTab, modelFilters, comboFilters]); - - const switchTab = (tab: CatalogTab) => { - setActiveTab(tab); - }; - - const updateModelFilters = (patch: Partial) => { - setModelFilters({ ...modelFilters, ...patch }); - setRequestedModelPage(0); - }; - - const clearModelFilters = () => { - setModelFilters(DEFAULT_MODEL_FILTERS); - setRequestedModelPage(0); - }; - - const updateComboFilters = (patch: Partial) => { - setComboFilters({ ...comboFilters, ...patch }); - setRequestedComboPage(0); + return { + providerOptions, + typeOptions, + subtypeOptions, + capabilityOptions, + strategyOptions, + modelOptionsKnown, + comboOptionsKnown, + modelFilters, + comboFilters, }; +} - const clearComboFilters = () => { - setComboFilters(DEFAULT_COMBO_FILTERS); - setRequestedComboPage(0); - }; - - // Filtered & Sorted Models - const visibleModels = useMemo(() => { - const filtered = filterCatalogModels(models, modelFilters, { - providerHealthMap, - testResults, - }); - return sortCatalogModels(filtered, modelSortField, modelSortDirection); - }, [models, modelFilters, providerHealthMap, testResults, modelSortField, modelSortDirection]); - const modelPage = getCatalogPage(visibleModels, requestedModelPage, PAGE_SIZE); - - // Filtered & Sorted Combos - const visibleCombos = useMemo(() => { - const filtered = filterCatalogCombos(combos, comboFilters, testResults); - return sortCatalogCombos(filtered, comboSortField, comboSortDirection); - }, [combos, comboFilters, testResults, comboSortField, comboSortDirection]); - const comboPage = getComboCatalogPage(visibleCombos, requestedComboPage, PAGE_SIZE); +function useCatalogPageSelection( + state: ReturnType & { + modelPage: ReturnType>; + comboPage: ReturnType>; + } +) { + const { + selectedModelIds, + setSelectedModelIds, + selectedComboIds, + setSelectedComboIds, + modelPage, + comboPage, + } = state; // Selection handlers for models const toggleSelectModel = (id: string) => { setSelectedModelIds((prev) => { @@ -390,6 +415,135 @@ export default function ModelCatalogPage() { }); }; + return { + toggleSelectModel, + toggleSelectAllModelsOnPage, + toggleSelectCombo, + toggleSelectAllCombosOnPage, + }; +} + +function useCatalogUrlRead(state: ReturnType) { + const { setActiveTab, setComboFilters, setModelFilters, setUrlApplied } = state; + // Deep links and Back/Forward: read the query string after mount (DashboardLayout pattern). + useEffect(() => { + const applyUrlState = () => { + const params = new URLSearchParams(window.location.search); + setActiveTab(parseCatalogTab(params)); + setModelFilters(parseModelFilters(params)); + setComboFilters(parseComboFilters(params)); + setUrlApplied(true); + }; + const timer = window.setTimeout(applyUrlState, 0); + window.addEventListener("popstate", applyUrlState); + return () => { + window.clearTimeout(timer); + window.removeEventListener("popstate", applyUrlState); + }; + }, [setActiveTab, setComboFilters, setModelFilters, setUrlApplied]); +} +function useCatalogPageActions( + state: ReturnType, + options: ReturnType +) { + const { + activeTab, + urlApplied, + setActiveTab, + setModelFilters, + setComboFilters, + setRequestedModelPage, + setRequestedComboPage, + models, + combos, + providerHealthMap, + testResults, + modelSortField, + modelSortDirection, + comboSortField, + comboSortDirection, + requestedModelPage, + requestedComboPage, + } = state; + const { modelFilters, comboFilters } = options; + // The only URL writer: one write per change of tab or (normalised) filters, never before the + // query string has been read, and skipped when the URL already matches. + useEffect(() => { + if (!urlApplied) return; + setUrlParams(buildCatalogSearchParams(activeTab, modelFilters, comboFilters)); + }, [urlApplied, activeTab, modelFilters, comboFilters]); + + const switchTab = (tab: CatalogTab) => { + setActiveTab(tab); + }; + + const updateModelFilters = (patch: Partial) => { + setModelFilters({ ...modelFilters, ...patch }); + setRequestedModelPage(0); + }; + + const clearModelFilters = () => { + setModelFilters(DEFAULT_MODEL_FILTERS); + setRequestedModelPage(0); + }; + + const updateComboFilters = (patch: Partial) => { + setComboFilters({ ...comboFilters, ...patch }); + setRequestedComboPage(0); + }; + + const clearComboFilters = () => { + setComboFilters(DEFAULT_COMBO_FILTERS); + setRequestedComboPage(0); + }; + + // Filtered & Sorted Models + const visibleModels = useMemo(() => { + const filtered = filterCatalogModels(models, modelFilters, { + providerHealthMap, + testResults, + }); + return sortCatalogModels(filtered, modelSortField, modelSortDirection); + }, [models, modelFilters, providerHealthMap, testResults, modelSortField, modelSortDirection]); + const modelPage = getCatalogPage(visibleModels, requestedModelPage, PAGE_SIZE); + + // Filtered & Sorted Combos + const visibleCombos = useMemo(() => { + const filtered = filterCatalogCombos(combos, comboFilters, testResults); + return sortCatalogCombos(filtered, comboSortField, comboSortDirection); + }, [combos, comboFilters, testResults, comboSortField, comboSortDirection]); + const comboPage = getComboCatalogPage(visibleCombos, requestedComboPage, PAGE_SIZE); + + const selection = useCatalogPageSelection({ ...state, modelPage, comboPage }); + return { + ...selection, + switchTab, + updateModelFilters, + clearModelFilters, + updateComboFilters, + clearComboFilters, + visibleModels, + visibleCombos, + modelPage, + comboPage, + }; +} +function useCatalogPageBulkActions( + state: ReturnType, + actions: ReturnType +) { + const { + testBulkModels, + testBulkCombos, + pendingBulkRun, + setPendingBulkRun, + activeTab, + models, + combos, + selectedModelIds, + selectedComboIds, + } = state; + const { visibleModels, visibleCombos } = actions; // Bulk test triggers: exact duplicates are dropped before counting, and large runs are // confirmed first because every test spends provider quota. const startBulkRun = (run: PendingBulkRun) => { @@ -434,12 +588,32 @@ export default function ModelCatalogPage() { } }; - const hasModelFiltersActive = hasActiveModelFilters(modelFilters); - const hasComboFiltersActive = hasActiveComboFilters(comboFilters); - const hasTestResults = Object.keys(testResults).length > 0; - + return { confirmPendingBulkRun, handleTestSelected, handleTestAllFiltered }; +} +function useCatalogPageContext() { + const state = useCatalogPageState(); + useCatalogUrlRead(state); + const loading = useCatalogPageLoading(state); + const options = useCatalogPageOptions(state); + const actions = useCatalogPageActions(state, options); + const bulk = useCatalogPageBulkActions(state, actions); + return { + ...state, + ...loading, + ...options, + ...actions, + ...bulk, + hasModelFiltersActive: hasActiveModelFilters(options.modelFilters), + hasComboFiltersActive: hasActiveComboFilters(options.comboFilters), + hasTestResults: Object.keys(state.testResults).length > 0, + }; +} +type CatalogPageContext = ReturnType; +function CatalogHeader({ context }: { context: CatalogPageContext }) { + const { t, refreshAll, switchTab, activeTab, models, modelsLoading, combos, combosLoading } = + context; return ( -
+ <>
@@ -466,7 +640,14 @@ export default function ModelCatalogPage() { }} />
+ + ); +} +function CatalogModelsPanel({ context }: { context: CatalogPageContext }) { + const { activeTab } = context; + return ( + <> {/* Models Tab Content */} {activeTab === "models" && (
- - - - - {modelsLoading && models.length === 0 ? ( -
- {t("loading")} -
- ) : modelsError && models.length === 0 ? ( -
-

{t("unableToLoad")}

-

{t("checkConnection")}

- -
- ) : visibleModels.length === 0 ? ( -
- -

- {models.length === 0 ? t("noModelsAvailable") : t("noModelsMatch")} -

- {models.length > 0 && ( - - )} -
- ) : ( - { - if (field === modelSortField) { - setModelSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); - } else { - setModelSortField(field); - setModelSortDirection("asc"); - } - setRequestedModelPage(0); - }} - page={modelPage.page + 1} - pageCount={modelPage.pageCount} - startIndex={modelPage.page * PAGE_SIZE} - totalCount={visibleModels.length} - loading={modelsLoading} - error={modelsError} - onPrevious={() => setRequestedModelPage((c) => Math.max(0, c - 1))} - onNext={() => - setRequestedModelPage((c) => Math.min(modelPage.pageCount - 1, c + 1)) - } - labels={{ - provider: t("provider"), - model: t("model"), - type: t("type"), - capabilities: t("capabilities"), - context: t("context"), - output: t("output"), - flags: t("flags"), - custom: t("custom"), - free: t("free"), - }} - selectedIds={selectedModelIds} - onToggleSelect={toggleSelectModel} - onToggleSelectAll={toggleSelectAllModelsOnPage} - testResults={testResults} - activeTestingKeys={activeItemKeys} - onTestModel={testSingleModel} - providerHealthMap={providerHealthMap} - bulkRunning={running} - /> - )} + + + + +
)} + + ); +} + +function CatalogModelsFilters({ context }: { context: CatalogPageContext }) { + const { + providerOptions, + typeOptions, + subtypeOptions, + capabilityOptions, + modelFilters, + updateModelFilters, + clearModelFilters, + visibleModels, + hasModelFiltersActive, + } = context; + return ( + <> + + + ); +} + +function CatalogModelsBulkActions({ context }: { context: CatalogPageContext }) { + const { + visibleModels, + handleTestSelected, + handleTestAllFiltered, + hasTestResults, + selectedModelIds, + running, + progress, + cancelTest, + clearResults, + } = context; + return ( + <> + + + ); +} + +function CatalogModelsContent({ context }: { context: CatalogPageContext }) { + const { t, refreshAll, clearModelFilters, visibleModels, models, modelsLoading, modelsError } = + context; + return ( + <> + {modelsLoading && models.length === 0 ? ( +
+ {t("loading")} +
+ ) : modelsError && models.length === 0 ? ( +
+

{t("unableToLoad")}

+

{t("checkConnection")}

+ +
+ ) : visibleModels.length === 0 ? ( +
+ +

+ {models.length === 0 ? t("noModelsAvailable") : t("noModelsMatch")} +

+ {models.length > 0 && ( + + )} +
+ ) : ( + + )} + + ); +} +function CatalogModelsResults({ context }: { context: CatalogPageContext }) { + const { + t, + visibleModels, + modelPage, + toggleSelectModel, + toggleSelectAllModelsOnPage, + modelsLoading, + modelsError, + modelSortField, + setModelSortField, + modelSortDirection, + setModelSortDirection, + setRequestedModelPage, + selectedModelIds, + providerHealthMap, + testResults, + running, + activeItemKeys, + testSingleModel, + } = context; + return ( + { + if (field === modelSortField) { + setModelSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); + } else { + setModelSortField(field); + setModelSortDirection("asc"); + } + setRequestedModelPage(0); + }} + page={modelPage.page + 1} + pageCount={modelPage.pageCount} + startIndex={modelPage.page * PAGE_SIZE} + totalCount={visibleModels.length} + loading={modelsLoading} + error={modelsError} + onPrevious={() => setRequestedModelPage((c) => Math.max(0, c - 1))} + onNext={() => setRequestedModelPage((c) => Math.min(modelPage.pageCount - 1, c + 1))} + labels={{ + provider: t("provider"), + model: t("model"), + type: t("type"), + capabilities: t("capabilities"), + context: t("context"), + output: t("output"), + flags: t("flags"), + custom: t("custom"), + free: t("free"), + }} + selectedIds={selectedModelIds} + onToggleSelect={toggleSelectModel} + onToggleSelectAll={toggleSelectAllModelsOnPage} + testResults={testResults} + activeTestingKeys={activeItemKeys} + onTestModel={testSingleModel} + providerHealthMap={providerHealthMap} + bulkRunning={running} + /> + ); +} + +function CatalogCombosPanel({ context }: { context: CatalogPageContext }) { + const { activeTab } = context; + return ( + <> {/* Combos Tab Content */} {activeTab === "combos" && (
- - - - - {combosLoading && combos.length === 0 ? ( -
- {t("loading")} -
- ) : combosError && combos.length === 0 ? ( -
-

{t("unableToLoadCombos")}

-

{t("checkConnection")}

- -
- ) : visibleCombos.length === 0 ? ( -
- -

- {combos.length === 0 ? t("noCombosAvailable") : t("noCombosMatch")} -

- {combos.length > 0 && ( - - )} -
- ) : ( - { - if (field === comboSortField) { - setComboSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); - } else { - setComboSortField(field); - setComboSortDirection("asc"); - } - setRequestedComboPage(0); - }} - page={comboPage.page + 1} - pageCount={comboPage.pageCount} - startIndex={comboPage.page * PAGE_SIZE} - totalCount={visibleCombos.length} - selectedIds={selectedComboIds} - onToggleSelect={toggleSelectCombo} - onToggleSelectAll={toggleSelectAllCombosOnPage} - testResults={testResults} - activeTestingKeys={activeItemKeys} - onTestCombo={testSingleCombo} - onPrevious={() => setRequestedComboPage((c) => Math.max(0, c - 1))} - onNext={() => - setRequestedComboPage((c) => Math.min(comboPage.pageCount - 1, c + 1)) - } - bulkRunning={running} - /> - )} + + + + +
)} + + ); +} + +function CatalogCombosFilters({ context }: { context: CatalogPageContext }) { + const { + strategyOptions, + comboFilters, + updateComboFilters, + clearComboFilters, + visibleCombos, + hasComboFiltersActive, + } = context; + return ( + <> + + + ); +} + +function CatalogCombosBulkActions({ context }: { context: CatalogPageContext }) { + const { + visibleCombos, + handleTestSelected, + handleTestAllFiltered, + hasTestResults, + selectedComboIds, + running, + progress, + cancelTest, + clearResults, + } = context; + return ( + <> + + + ); +} + +function CatalogCombosContent({ context }: { context: CatalogPageContext }) { + const { t, refreshAll, clearComboFilters, visibleCombos, combos, combosLoading, combosError } = + context; + return ( + <> + {combosLoading && combos.length === 0 ? ( +
+ {t("loading")} +
+ ) : combosError && combos.length === 0 ? ( +
+

{t("unableToLoadCombos")}

+

{t("checkConnection")}

+ +
+ ) : visibleCombos.length === 0 ? ( +
+ +

+ {combos.length === 0 ? t("noCombosAvailable") : t("noCombosMatch")} +

+ {combos.length > 0 && ( + + )} +
+ ) : ( + + )} + + ); +} + +function CatalogCombosResults({ context }: { context: CatalogPageContext }) { + const { + visibleCombos, + comboPage, + toggleSelectCombo, + toggleSelectAllCombosOnPage, + comboSortField, + setComboSortField, + comboSortDirection, + setComboSortDirection, + setRequestedComboPage, + selectedComboIds, + testResults, + running, + activeItemKeys, + testSingleCombo, + } = context; + return ( + { + if (field === comboSortField) { + setComboSortDirection((curr) => (curr === "asc" ? "desc" : "asc")); + } else { + setComboSortField(field); + setComboSortDirection("asc"); + } + setRequestedComboPage(0); + }} + page={comboPage.page + 1} + pageCount={comboPage.pageCount} + startIndex={comboPage.page * PAGE_SIZE} + totalCount={visibleCombos.length} + selectedIds={selectedComboIds} + onToggleSelect={toggleSelectCombo} + onToggleSelectAll={toggleSelectAllCombosOnPage} + testResults={testResults} + activeTestingKeys={activeItemKeys} + onTestCombo={testSingleCombo} + onPrevious={() => setRequestedComboPage((c) => Math.max(0, c - 1))} + onNext={() => setRequestedComboPage((c) => Math.min(comboPage.pageCount - 1, c + 1))} + bulkRunning={running} + /> + ); +} +function CatalogBulkConfirmation({ context }: { context: CatalogPageContext }) { + const { t, confirmPendingBulkRun, pendingBulkRun, setPendingBulkRun } = context; + return ( + <> setPendingBulkRun(null)} @@ -699,6 +1025,17 @@ export default function ModelCatalogPage() { confirmText={t("bulkConfirmStart")} variant="primary" /> + + ); +} +export default function ModelCatalogPage() { + const context = useCatalogPageContext(); + return ( +
+ + + +
); } From ff557c3b17ac3e6a8c0b614fff474a8ae4dd8ebd Mon Sep 17 00:00:00 2001 From: Fouad Salkini Date: Mon, 5 Oct 2026 23:27:25 +0300 Subject: [PATCH 16/16] fix(i18n): drop the duplicated sidebar catalog keys and use the canonical zh provider term MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The catalog page re-added sidebar.modelCatalog and sidebar.modelCatalogSubtitle while the base already had them later in the same object, so JSON.parse kept the base copy and the new 'Models & Combos' label never showed. Each locale now has one copy carrying the new label. zh-CN catalog strings use the glossary's canonical 提供者 instead of the retired 提供商. --- src/i18n/messages/am.json | 6 ++---- src/i18n/messages/ar.json | 6 ++---- src/i18n/messages/az.json | 6 ++---- src/i18n/messages/bg.json | 6 ++---- src/i18n/messages/bn.json | 6 ++---- src/i18n/messages/bs.json | 6 ++---- src/i18n/messages/cs.json | 6 ++---- src/i18n/messages/da.json | 6 ++---- src/i18n/messages/de.json | 6 ++---- src/i18n/messages/el.json | 6 ++---- src/i18n/messages/en.json | 6 ++---- src/i18n/messages/es.json | 6 ++---- src/i18n/messages/et.json | 6 ++---- src/i18n/messages/fa.json | 6 ++---- src/i18n/messages/fi.json | 6 ++---- src/i18n/messages/fr.json | 6 ++---- src/i18n/messages/ga.json | 6 ++---- src/i18n/messages/gu.json | 6 ++---- src/i18n/messages/ha.json | 6 ++---- src/i18n/messages/he.json | 6 ++---- src/i18n/messages/hi.json | 6 ++---- src/i18n/messages/hr.json | 6 ++---- src/i18n/messages/hu.json | 6 ++---- src/i18n/messages/hy.json | 6 ++---- src/i18n/messages/id.json | 6 ++---- src/i18n/messages/ig.json | 6 ++---- src/i18n/messages/it.json | 6 ++---- src/i18n/messages/ja.json | 6 ++---- src/i18n/messages/ka.json | 6 ++---- src/i18n/messages/km.json | 6 ++---- src/i18n/messages/kn.json | 6 ++---- src/i18n/messages/ko.json | 6 ++---- src/i18n/messages/lt.json | 6 ++---- src/i18n/messages/lv.json | 6 ++---- src/i18n/messages/ml.json | 6 ++---- src/i18n/messages/mr.json | 6 ++---- src/i18n/messages/ms.json | 6 ++---- src/i18n/messages/mt.json | 6 ++---- src/i18n/messages/my.json | 6 ++---- src/i18n/messages/ne.json | 6 ++---- src/i18n/messages/nl.json | 6 ++---- src/i18n/messages/no.json | 6 ++---- src/i18n/messages/or.json | 6 ++---- src/i18n/messages/pa.json | 6 ++---- src/i18n/messages/phi.json | 6 ++---- src/i18n/messages/pl.json | 6 ++---- src/i18n/messages/pt-BR.json | 6 ++---- src/i18n/messages/pt.json | 6 ++---- src/i18n/messages/ro.json | 6 ++---- src/i18n/messages/ru.json | 6 ++---- src/i18n/messages/si.json | 6 ++---- src/i18n/messages/sk.json | 6 ++---- src/i18n/messages/sl.json | 6 ++---- src/i18n/messages/sr.json | 6 ++---- src/i18n/messages/sv.json | 6 ++---- src/i18n/messages/sw.json | 6 ++---- src/i18n/messages/ta.json | 6 ++---- src/i18n/messages/te.json | 6 ++---- src/i18n/messages/th.json | 6 ++---- src/i18n/messages/tr.json | 6 ++---- src/i18n/messages/uk-UA.json | 6 ++---- src/i18n/messages/ur.json | 6 ++---- src/i18n/messages/uz.json | 6 ++---- src/i18n/messages/vi.json | 6 ++---- src/i18n/messages/yo.json | 6 ++---- src/i18n/messages/zh-CN.json | 22 ++++++++++------------ src/i18n/messages/zh-TW.json | 6 ++---- 67 files changed, 142 insertions(+), 276 deletions(-) diff --git a/src/i18n/messages/am.json b/src/i18n/messages/am.json index 4c44398243a1..97d85f3cda1b 100644 --- a/src/i18n/messages/am.json +++ b/src/i18n/messages/am.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AIን የሚያገናኙባቸው URLs", "apiManager": "API ቁልፎች", "apiManagerSubtitle": "የAPI ቁልፎችን እና መዳረሻን ያስተዳድሩ", - "modelCatalog": "ሞዴሎች እና ኮምቦዎች", - "modelCatalogSubtitle": "በአቅራቢዎች ዙሪያ ሞዴሎችን እና ኮምቦዎችን ያስሱ", "embeddedServices": "የተካተቱ አገልግሎቶች", "embeddedServicesSubtitle": "በአካባቢው የሚሰሩ አማራጭ አገልግሎቶች", "logs": "ምዝግቦች", @@ -1205,8 +1203,8 @@ "batchGroup": "ባች", "homeSubtitle": "የዳሽቦርድ አጠቃላይ እይታ", "providersSubtitle": "የAI አቅራቢዎችን ያስተዳድሩ", - "modelCatalog": "የሞዴል ካታሎግ", - "modelCatalogSubtitle": "በአቅራቢዎች መካከል ሞዴሎችን ያስሱ", + "modelCatalog": "ሞዴሎች እና ኮምቦዎች", + "modelCatalogSubtitle": "በአቅራቢዎች ዙሪያ ሞዴሎችን እና ኮምቦዎችን ያስሱ", "quotaTrackerSubtitle": "የአጠቃቀም ገደቦችን ይከታተሉ", "providerQuotaSubtitle": "የአቅራቢዎችን የአጠቃቀም ገደቦች ይከታተሉ", "runtimeSubtitle": "ቅጽበታዊ የመቋቋም ችሎታ እና ክፍለ ጊዜዎች", diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 424f01d80543..a202338369cb 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "عناوين URL لاتصال AI الخاص بك", "apiManager": "مدير API", "apiManagerSubtitle": "إدارة مفاتيح واجهة برمجة التطبيقات والوصول إليها", - "modelCatalog": "النماذج والتركيبات", - "modelCatalogSubtitle": "استعرض النماذج والتركيبات عبر المزودين", "embeddedServices": "الخدمات المدمجة", "embeddedServicesSubtitle": "إدارة خدمات الوكيل المحلية", "logs": "سجلات", @@ -1205,8 +1203,8 @@ "batchGroup": "الدُفعات", "homeSubtitle": "نظرة عامة على لوحة القيادة", "providersSubtitle": "إدارة موفري الذكاء الاصطناعي", - "modelCatalog": "كتالوج النماذج", - "modelCatalogSubtitle": "تصفح النماذج عبر المزودين", + "modelCatalog": "النماذج والتركيبات", + "modelCatalogSubtitle": "استعرض النماذج والتركيبات عبر المزودين", "quotaTrackerSubtitle": "تتبع حدود الاستخدام", "providerQuotaSubtitle": "تتبع حدود استخدام الموفر", "runtimeSubtitle": "المرونة والجلسات في الوقت الحقيقي", diff --git a/src/i18n/messages/az.json b/src/i18n/messages/az.json index 9b7704c58cde..26e4f3494288 100644 --- a/src/i18n/messages/az.json +++ b/src/i18n/messages/az.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AI bağlantı URL-ləriniz", "apiManager": "API açarları", "apiManagerSubtitle": "API açarlarını və girişi idarə edin", - "modelCatalog": "Modellər və Kombolar", - "modelCatalogSubtitle": "Provayderlər üzrə modelləri və komboları nəzərdən keçirin", "embeddedServices": "Daxili Xidmətlər", "embeddedServicesSubtitle": "Lokal proksi xidmətlərini idarə edin", "logs": "Jurnallar", @@ -1205,8 +1203,8 @@ "batchGroup": "Dəstə", "homeSubtitle": "İdarə panelinə ümumi baxış", "providersSubtitle": "Süni intellekt provayderlərini idarə edin", - "modelCatalog": "Model kataloqu", - "modelCatalogSubtitle": "Provayderlər üzrə modellərə baxın", + "modelCatalog": "Modellər və Kombolar", + "modelCatalogSubtitle": "Provayderlər üzrə modelləri və komboları nəzərdən keçirin", "quotaTrackerSubtitle": "İstifadə limitlərini izləyin", "providerQuotaSubtitle": "Provayderlərin istifadə limitlərini izləyin", "runtimeSubtitle": "Real vaxt rejimində dayanıqlılıq və sessiyalar", diff --git a/src/i18n/messages/bg.json b/src/i18n/messages/bg.json index f45e924d1296..a8e339186d9b 100644 --- a/src/i18n/messages/bg.json +++ b/src/i18n/messages/bg.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Вашите URL адреси за връзка с AI", "apiManager": "API мениджър", "apiManagerSubtitle": "Управление на API ключове и достъп", - "modelCatalog": "Модели и комбинации", - "modelCatalogSubtitle": "Преглед на модели и комбинации от различните доставчици", "embeddedServices": "Вградени услуги", "embeddedServicesSubtitle": "Управление на локални прокси услуги", "logs": "трупи", @@ -1205,8 +1203,8 @@ "batchGroup": "Пакетна обработка", "homeSubtitle": "Общ преглед на таблото", "providersSubtitle": "Управление на доставчиците на AI", - "modelCatalog": "Каталог с модели", - "modelCatalogSubtitle": "Разглеждайте модели от всички доставчици", + "modelCatalog": "Модели и комбинации", + "modelCatalogSubtitle": "Преглед на модели и комбинации от различните доставчици", "quotaTrackerSubtitle": "Проследяване на ограниченията за използване", "providerQuotaSubtitle": "Проследяване на ограниченията за използване при доставчика", "runtimeSubtitle": "Устойчивост в реално време и сесии", diff --git a/src/i18n/messages/bn.json b/src/i18n/messages/bn.json index 53719d2208c0..83ebd7ddce0d 100644 --- a/src/i18n/messages/bn.json +++ b/src/i18n/messages/bn.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "আপনার AI কানেকশন ইউআরএল", "apiManager": "API কী", "apiManagerSubtitle": "API কী এবং অ্যাক্সেস পরিচালনা করুন", - "modelCatalog": "মডেল এবং কম্বো", - "modelCatalogSubtitle": "বিভিন্ন প্রোভাইডারের মডেল এবং কম্বো ব্রাউজ করুন", "embeddedServices": "এমবেডেড সার্ভিস", "embeddedServicesSubtitle": "স্থানীয় প্রক্সি সার্ভিস পরিচালনা করুন", "logs": "লগ", @@ -1205,8 +1203,8 @@ "batchGroup": "ব্যাচ", "homeSubtitle": "ড্যাশবোর্ডের সারসংক্ষেপ", "providersSubtitle": "AI প্রোভাইডার পরিচালনা করুন", - "modelCatalog": "মডেল ক্যাটালগ", - "modelCatalogSubtitle": "প্রদানকারীদের মধ্যে মডেল ব্রাউজ করুন", + "modelCatalog": "মডেল এবং কম্বো", + "modelCatalogSubtitle": "বিভিন্ন প্রোভাইডারের মডেল এবং কম্বো ব্রাউজ করুন", "quotaTrackerSubtitle": "ব্যবহারের সীমা ট্র্যাক করুন", "providerQuotaSubtitle": "প্রোভাইডারের ব্যবহারের সীমা ট্র্যাক করুন", "runtimeSubtitle": "রিয়েল-টাইম সহনশীলতা ও সেশন", diff --git a/src/i18n/messages/bs.json b/src/i18n/messages/bs.json index 0467048e9c34..50eb196dd68c 100644 --- a/src/i18n/messages/bs.json +++ b/src/i18n/messages/bs.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Vaši AI connection URL-ovi", "apiManager": "API ključevi", "apiManagerSubtitle": "Upravljanje API ključevima i pristupom", - "modelCatalog": "Modeli i kombinacije", - "modelCatalogSubtitle": "Pregledajte modele i kombinacije kod različitih provajdera", "embeddedServices": "Ugrađene usluge", "embeddedServicesSubtitle": "Opcionalne lokalne usluge", "logs": "Logovi", @@ -1205,8 +1203,8 @@ "batchGroup": "Paketna obrada", "homeSubtitle": "Pregled dashboarda", "providersSubtitle": "Upravljanje AI provajderima", - "modelCatalog": "Katalog modela", - "modelCatalogSubtitle": "Pregledajte modele svih provajdera", + "modelCatalog": "Modeli i kombinacije", + "modelCatalogSubtitle": "Pregledajte modele i kombinacije kod različitih provajdera", "quotaTrackerSubtitle": "Praćenje limita korištenja", "providerQuotaSubtitle": "Praćenje limita korištenja provajdera", "runtimeSubtitle": "Real-time otpornost i sesije", diff --git a/src/i18n/messages/cs.json b/src/i18n/messages/cs.json index 409742db945b..59f5c6dbe273 100644 --- a/src/i18n/messages/cs.json +++ b/src/i18n/messages/cs.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Vaše adresy URL připojení AI", "apiManager": "Správce API", "apiManagerSubtitle": "Správa klíčů API a přístupu", - "modelCatalog": "Modely a kombinace", - "modelCatalogSubtitle": "Procházejte modely a kombinace napříč poskytovateli", "embeddedServices": "Vestavěné služby", "embeddedServicesSubtitle": "Správa místních proxy služeb", "logs": "Protokoly", @@ -1205,8 +1203,8 @@ "batchGroup": "Dávkové zpracování", "homeSubtitle": "Přehled řídicího panelu", "providersSubtitle": "Správa poskytovatelů AI", - "modelCatalog": "Katalog modelů", - "modelCatalogSubtitle": "Procházejte modely napříč poskytovateli", + "modelCatalog": "Modely a kombinace", + "modelCatalogSubtitle": "Procházejte modely a kombinace napříč poskytovateli", "quotaTrackerSubtitle": "Sledování limitů využití", "providerQuotaSubtitle": "Sledování limitů využití poskytovatelů", "runtimeSubtitle": "Odolnost a relace v reálném čase", diff --git a/src/i18n/messages/da.json b/src/i18n/messages/da.json index aab193cf3f38..a271cf04972a 100644 --- a/src/i18n/messages/da.json +++ b/src/i18n/messages/da.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Dine AI-forbindelses-URL'er", "apiManager": "API-nøgler", "apiManagerSubtitle": "Administrer API-nøgler og adgang", - "modelCatalog": "Modeller & kombinationer", - "modelCatalogSubtitle": "Gennemse modeller og kombinationer på tværs af udbydere", "embeddedServices": "Integrerede tjenester", "embeddedServicesSubtitle": "Administrer lokale proxytjenester", "logs": "Logfiler", @@ -1205,8 +1203,8 @@ "batchGroup": "Batch", "homeSubtitle": "Oversigt over dashboard", "providersSubtitle": "Administrer AI-udbydere", - "modelCatalog": "Modelkatalog", - "modelCatalogSubtitle": "Gennemse modeller på tværs af udbydere", + "modelCatalog": "Modeller & kombinationer", + "modelCatalogSubtitle": "Gennemse modeller og kombinationer på tværs af udbydere", "quotaTrackerSubtitle": "Spor forbrugsgrænser", "providerQuotaSubtitle": "Spor udbydernes forbrugsgrænser", "runtimeSubtitle": "Modstandsdygtighed og sessioner i realtid", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 85eb22c425e2..882874dc1e37 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Ihre AI-Verbindungs-URLs", "apiManager": "API-Manager", "apiManagerSubtitle": "Verwalten Sie API-Schlüssel und Zugriff", - "modelCatalog": "Modelle & Combos", - "modelCatalogSubtitle": "Modelle und Combos über Provider hinweg durchsuchen", "embeddedServices": "Eingebettete Dienste", "embeddedServicesSubtitle": "Lokale Proxy-Dienste verwalten", "logs": "Protokolle", @@ -1205,8 +1203,8 @@ "batchGroup": "Stapelverarbeitung", "homeSubtitle": "Dashboard-Übersicht", "providersSubtitle": "KI-Anbieter verwalten", - "modelCatalog": "Modellkatalog", - "modelCatalogSubtitle": "Modelle aller Anbieter durchsuchen", + "modelCatalog": "Modelle & Combos", + "modelCatalogSubtitle": "Modelle und Combos über Provider hinweg durchsuchen", "quotaTrackerSubtitle": "Nutzungslimits verfolgen", "providerQuotaSubtitle": "Nutzungslimits der Anbieter verfolgen", "runtimeSubtitle": "Ausfallsicherheit und Sitzungen in Echtzeit", diff --git a/src/i18n/messages/el.json b/src/i18n/messages/el.json index 7daa49c5099a..53aacff436ec 100644 --- a/src/i18n/messages/el.json +++ b/src/i18n/messages/el.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Οι διευθύνσεις URL σύνδεσής σας με AI", "apiManager": "Κλειδιά API", "apiManagerSubtitle": "Διαχείριση κλειδιών API και πρόσβασης", - "modelCatalog": "Μοντέλα & Συνδυασμοί", - "modelCatalogSubtitle": "Περιηγηθείτε σε μοντέλα και συνδυασμούς μεταξύ παρόχων", "embeddedServices": "Ενσωματωμένες υπηρεσίες", "embeddedServicesSubtitle": "Προαιρετικές τοπικές υπηρεσίες", "logs": "Αρχεία καταγραφής", @@ -1205,8 +1203,8 @@ "batchGroup": "Μαζική Επεξεργασία", "homeSubtitle": "Επισκόπηση πίνακα ελέγχου", "providersSubtitle": "Διαχείριση παρόχων AI", - "modelCatalog": "Κατάλογος μοντέλων", - "modelCatalogSubtitle": "Περιηγηθείτε σε μοντέλα όλων των παρόχων", + "modelCatalog": "Μοντέλα & Συνδυασμοί", + "modelCatalogSubtitle": "Περιηγηθείτε σε μοντέλα και συνδυασμούς μεταξύ παρόχων", "quotaTrackerSubtitle": "Παρακολούθηση ορίων χρήσης", "providerQuotaSubtitle": "Παρακολούθηση ορίων χρήσης παρόχου", "runtimeSubtitle": "Ανθεκτικότητα και συνεδρίες σε πραγματικό χρόνο", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index f38b1f5bb4d6..efae16a2a409 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Your AI connection URLs", "apiManager": "API Keys", "apiManagerSubtitle": "Manage API keys and access", - "modelCatalog": "Models & Combos", - "modelCatalogSubtitle": "Browse models and combos across providers", "embeddedServices": "Embedded Services", "embeddedServicesSubtitle": "Optional local services", "logs": "Logs", @@ -1205,8 +1203,8 @@ "batchGroup": "Batch", "homeSubtitle": "Dashboard overview", "providersSubtitle": "Manage AI providers", - "modelCatalog": "Model catalog", - "modelCatalogSubtitle": "Browse models across providers", + "modelCatalog": "Models & Combos", + "modelCatalogSubtitle": "Browse models and combos across providers", "quotaTrackerSubtitle": "Track usage limits", "providerQuotaSubtitle": "Track provider usage limits", "runtimeSubtitle": "Realtime resilience & sessions", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index a642d26627b9..f7b8e25c05b4 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Las URL de su conexión de IA", "apiManager": "Gestor de API", "apiManagerSubtitle": "Administrar claves API y acceso", - "modelCatalog": "Modelos y combos", - "modelCatalogSubtitle": "Explora modelos y combos entre proveedores", "embeddedServices": "Servicios Integrados", "embeddedServicesSubtitle": "Gestionar servicios proxy locales", "logs": "Registros", @@ -1205,8 +1203,8 @@ "batchGroup": "Procesamiento por lotes", "homeSubtitle": "Resumen del panel", "providersSubtitle": "Gestionar proveedores de IA", - "modelCatalog": "Catálogo de modelos", - "modelCatalogSubtitle": "Explora modelos de todos los proveedores", + "modelCatalog": "Modelos y combos", + "modelCatalogSubtitle": "Explora modelos y combos entre proveedores", "quotaTrackerSubtitle": "Supervisar los límites de uso", "providerQuotaSubtitle": "Supervisar los límites de uso de los proveedores", "runtimeSubtitle": "Resiliencia y sesiones en tiempo real", diff --git a/src/i18n/messages/et.json b/src/i18n/messages/et.json index e268bb276c02..2ae9857dea19 100644 --- a/src/i18n/messages/et.json +++ b/src/i18n/messages/et.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Teie tehisintellekti ühenduse URL-id", "apiManager": "API-võtmed", "apiManagerSubtitle": "API-võtmete ja juurdepääsu haldamine", - "modelCatalog": "Mudelid ja kombod", - "modelCatalogSubtitle": "Sirvi mudeleid ja kombosid erinevate pakkujate lõikes", "embeddedServices": "Manustatud teenused", "embeddedServicesSubtitle": "Valikulised kohalikud teenused", "logs": "Logid", @@ -1205,8 +1203,8 @@ "batchGroup": "Pakktöötlus", "homeSubtitle": "Töölaua ülevaade", "providersSubtitle": "Halda AI-teenusepakkujaid", - "modelCatalog": "Mudelite kataloog", - "modelCatalogSubtitle": "Sirvi mudeleid kõigi teenusepakkujate lõikes", + "modelCatalog": "Mudelid ja kombod", + "modelCatalogSubtitle": "Sirvi mudeleid ja kombosid erinevate pakkujate lõikes", "quotaTrackerSubtitle": "Jälgi kasutuslimiite", "providerQuotaSubtitle": "Jälgi teenusepakkuja kasutuslimiite", "runtimeSubtitle": "Reaalajas tõrkekindlus ja seansid", diff --git a/src/i18n/messages/fa.json b/src/i18n/messages/fa.json index 493333f01a49..7765c7bb17e2 100644 --- a/src/i18n/messages/fa.json +++ b/src/i18n/messages/fa.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL های اتصال هوش مصنوعی شما", "apiManager": "کلیدهای API", "apiManagerSubtitle": "کلیدهای API و دسترسی را مدیریت کنید", - "modelCatalog": "مدل‌ها و ترکیب‌ها", - "modelCatalogSubtitle": "مرور مدل‌ها و ترکیب‌ها در میان ارائه‌دهندگان", "embeddedServices": "سرویس‌های جاسازی‌شده", "embeddedServicesSubtitle": "مدیریت سرویس‌های پروکسی محلی", "logs": "گزارشها", @@ -1205,8 +1203,8 @@ "batchGroup": "پردازش دستهای", "homeSubtitle": "نمای کلی داشبورد", "providersSubtitle": "مدیریت ارائهدهندگان هوش مصنوعی", - "modelCatalog": "کاتالوگ مدل‌ها", - "modelCatalogSubtitle": "مرور مدل‌ها در میان ارائه‌دهندگان", + "modelCatalog": "مدل‌ها و ترکیب‌ها", + "modelCatalogSubtitle": "مرور مدل‌ها و ترکیب‌ها در میان ارائه‌دهندگان", "quotaTrackerSubtitle": "پیگیری محدودیتهای مصرف", "providerQuotaSubtitle": "پیگیری محدودیتهای مصرف ارائهدهنده", "runtimeSubtitle": "تابآوری و نشستهای بلادرنگ", diff --git a/src/i18n/messages/fi.json b/src/i18n/messages/fi.json index 54e37df4465d..793d022cee71 100644 --- a/src/i18n/messages/fi.json +++ b/src/i18n/messages/fi.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AI-yhteytesi URL-osoitteet", "apiManager": "API-avaimet", "apiManagerSubtitle": "Hallinnoi API-avaimia ja käyttöoikeuksia", - "modelCatalog": "Mallit ja yhdistelmät", - "modelCatalogSubtitle": "Selaa malleja ja yhdistelmiä eri palveluntarjoajilta", "embeddedServices": "Upotetut palvelut", "embeddedServicesSubtitle": "Hallitse paikallisia välityspalvelimia", "logs": "Lokit", @@ -1205,8 +1203,8 @@ "batchGroup": "Eräajo", "homeSubtitle": "Koontinäytön yleiskatsaus", "providersSubtitle": "Hallinnoi tekoälypalveluntarjoajia", - "modelCatalog": "Mallikatalogi", - "modelCatalogSubtitle": "Selaa malleja eri palveluntarjoajilta", + "modelCatalog": "Mallit ja yhdistelmät", + "modelCatalogSubtitle": "Selaa malleja ja yhdistelmiä eri palveluntarjoajilta", "quotaTrackerSubtitle": "Seuraa käyttörajoja", "providerQuotaSubtitle": "Seuraa palveluntarjoajien käyttörajoja", "runtimeSubtitle": "Reaaliaikainen vikasietoisuus ja istunnot", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 6c8258562063..bdb298c335db 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Vos URL de connexion IA", "apiManager": "Gestionnaire d'API", "apiManagerSubtitle": "Gérer les clés API et l'accès", - "modelCatalog": "Modèles & combinaisons", - "modelCatalogSubtitle": "Parcourir les modèles et les combinaisons de tous les fournisseurs", "embeddedServices": "Services Intégrés", "embeddedServicesSubtitle": "Gérer les services proxy locaux", "logs": "Journaux", @@ -1205,8 +1203,8 @@ "batchGroup": "Traitement par lots", "homeSubtitle": "Vue d’ensemble du tableau de bord", "providersSubtitle": "Gérer les fournisseurs d’IA", - "modelCatalog": "Catalogue de modèles", - "modelCatalogSubtitle": "Parcourir les modèles de tous les fournisseurs", + "modelCatalog": "Modèles & combinaisons", + "modelCatalogSubtitle": "Parcourir les modèles et les combinaisons de tous les fournisseurs", "quotaTrackerSubtitle": "Suivre les limites d’utilisation", "providerQuotaSubtitle": "Suivre les limites d’utilisation des fournisseurs", "runtimeSubtitle": "Résilience en temps réel et sessions", diff --git a/src/i18n/messages/ga.json b/src/i18n/messages/ga.json index 2b9ba7d2789d..dcfdbcdb2459 100644 --- a/src/i18n/messages/ga.json +++ b/src/i18n/messages/ga.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Do URLanna naisc AI", "apiManager": "Eochracha API", "apiManagerSubtitle": "Bainistigh eochracha API agus rochtain", - "modelCatalog": "Múnlaí & Teaglamaí", - "modelCatalogSubtitle": "Brabhsáil múnlaí agus teaglamaí trasna soláthraithe", "embeddedServices": "Seirbhísí Leabaithe", "embeddedServicesSubtitle": "Seirbhísí áitiúla roghnacha", "logs": "Logaí", @@ -1205,8 +1203,8 @@ "batchGroup": "Baisc", "homeSubtitle": "Forléargas deais", "providersSubtitle": "Bainistigh soláthraithe AI", - "modelCatalog": "Catalóg samhlacha", - "modelCatalogSubtitle": "Brabhsáil samhlacha ó sholáthraithe éagsúla", + "modelCatalog": "Múnlaí & Teaglamaí", + "modelCatalogSubtitle": "Brabhsáil múnlaí agus teaglamaí trasna soláthraithe", "quotaTrackerSubtitle": "Rianaigh teorainneacha úsáide", "providerQuotaSubtitle": "Rianaigh teorainneacha úsáide soláthraí", "runtimeSubtitle": "Athléimneacht agus seisiúin fíor-ama", diff --git a/src/i18n/messages/gu.json b/src/i18n/messages/gu.json index 3923c972bbbe..fdf2b0fbc598 100644 --- a/src/i18n/messages/gu.json +++ b/src/i18n/messages/gu.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "તમારા AI કનેક્શન URL", "apiManager": "API કીઝ", "apiManagerSubtitle": "API કી અને એક્સેસ મેનેજ કરો", - "modelCatalog": "મોડલ્સ અને કૉમ્બોઝ", - "modelCatalogSubtitle": "પ્રદાતાઓ વચ્ચે મોડલ્સ અને કૉમ્બોઝ બ્રાઉઝ કરો", "embeddedServices": "એમ્બેડ સેવાઓ", "embeddedServicesSubtitle": "સ્થાનિક પ્રોક્સી સેવાઓ મેનેજ કરો", "logs": "લૉગ્સ", @@ -1205,8 +1203,8 @@ "batchGroup": "બૅચ", "homeSubtitle": "ડૅશબોર્ડનું વિહંગાવલોકન", "providersSubtitle": "AI પ્રદાતાઓનું સંચાલન કરો", - "modelCatalog": "મોડેલ કેટલોગ", - "modelCatalogSubtitle": "પ્રદાતાઓમાં મોડેલ બ્રાઉઝ કરો", + "modelCatalog": "મોડલ્સ અને કૉમ્બોઝ", + "modelCatalogSubtitle": "પ્રદાતાઓ વચ્ચે મોડલ્સ અને કૉમ્બોઝ બ્રાઉઝ કરો", "quotaTrackerSubtitle": "વપરાશ મર્યાદાઓ ટ્રૅક કરો", "providerQuotaSubtitle": "પ્રદાતાની વપરાશ મર્યાદાઓ ટ્રૅક કરો", "runtimeSubtitle": "રીઅલ-ટાઇમ સ્થિતિસ્થાપકતા અને સત્રો", diff --git a/src/i18n/messages/ha.json b/src/i18n/messages/ha.json index cb73adfa3112..e16e6c157dbe 100644 --- a/src/i18n/messages/ha.json +++ b/src/i18n/messages/ha.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URLs na haɗin AI ɗinka", "apiManager": "Maɓallan API", "apiManagerSubtitle": "Sarrafa maɓallan API da samun dama", - "modelCatalog": "Samfura & Haɗe-haɗe", - "modelCatalogSubtitle": "Bincika samfura da haɗe-haɗe a duk faɗin masu ba da sabis", "embeddedServices": "Ayyukan da aka haɗa ciki", "embeddedServicesSubtitle": "Ayyukan gida na zaɓi", "logs": "Rajistoci", @@ -1205,8 +1203,8 @@ "batchGroup": "Aiki a Rukuni", "homeSubtitle": "Bayanin dashboard a taƙaice", "providersSubtitle": "Sarrafa masu samar da AI", - "modelCatalog": "Kundin samfura", - "modelCatalogSubtitle": "Bincika samfura daga masu samarwa daban-daban", + "modelCatalog": "Samfura & Haɗe-haɗe", + "modelCatalogSubtitle": "Bincika samfura da haɗe-haɗe a duk faɗin masu ba da sabis", "quotaTrackerSubtitle": "Bibiyi iyakokin amfani", "providerQuotaSubtitle": "Bibiyi iyakokin amfani na mai bayarwa", "runtimeSubtitle": "Juriya da zaman aiki na ainihin lokaci", diff --git a/src/i18n/messages/he.json b/src/i18n/messages/he.json index 472758cbf8c5..47c4d46a9ed8 100644 --- a/src/i18n/messages/he.json +++ b/src/i18n/messages/he.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "כתובות ה-URL של חיבור הבינה המלאכותית שלך", "apiManager": "מנהל API", "apiManagerSubtitle": "נהל מפתחות API וגישה", - "modelCatalog": "מודלים ושילובים", - "modelCatalogSubtitle": "עיון במודלים ובשילובים בין ספקים שונים", "embeddedServices": "שירותים מוטמעים", "embeddedServicesSubtitle": "ניהול שירותי פרוקסי מקומיים", "logs": "יומנים", @@ -1205,8 +1203,8 @@ "batchGroup": "עיבוד באצווה", "homeSubtitle": "סקירת לוח הבקרה", "providersSubtitle": "ניהול ספקי AI", - "modelCatalog": "קטלוג מודלים", - "modelCatalogSubtitle": "עיון במודלים מכל הספקים", + "modelCatalog": "מודלים ושילובים", + "modelCatalogSubtitle": "עיון במודלים ובשילובים בין ספקים שונים", "quotaTrackerSubtitle": "מעקב אחר מגבלות שימוש", "providerQuotaSubtitle": "מעקב אחר מגבלות השימוש של ספקים", "runtimeSubtitle": "עמידות וסשנים בזמן אמת", diff --git a/src/i18n/messages/hi.json b/src/i18n/messages/hi.json index d62a22f65b60..ff804716197a 100644 --- a/src/i18n/messages/hi.json +++ b/src/i18n/messages/hi.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "आपका AI कनेक्शन URL", "apiManager": "एपीआई प्रबंधक", "apiManagerSubtitle": "एपीआई कुंजी और पहुंच प्रबंधित करें", - "modelCatalog": "मॉडल और कॉम्बो", - "modelCatalogSubtitle": "सभी प्रदाताओं में मॉडल और कॉम्बो ब्राउज़ करें", "embeddedServices": "एम्बेडेड सेवाएं", "embeddedServicesSubtitle": "स्थानीय प्रॉक्सी सेवाओं का प्रबंधन करें", "logs": "लॉग", @@ -1205,8 +1203,8 @@ "batchGroup": "बैच", "homeSubtitle": "डैशबोर्ड अवलोकन", "providersSubtitle": "AI प्रदाताओं को प्रबंधित करें", - "modelCatalog": "मॉडल कैटलॉग", - "modelCatalogSubtitle": "सभी प्रदाताओं के मॉडल ब्राउज़ करें", + "modelCatalog": "मॉडल और कॉम्बो", + "modelCatalogSubtitle": "सभी प्रदाताओं में मॉडल और कॉम्बो ब्राउज़ करें", "quotaTrackerSubtitle": "उपयोग सीमाओं को ट्रैक करें", "providerQuotaSubtitle": "प्रदाता की उपयोग सीमाओं को ट्रैक करें", "runtimeSubtitle": "रीयल-टाइम लचीलापन और सत्र", diff --git a/src/i18n/messages/hr.json b/src/i18n/messages/hr.json index 101f870279cb..33eef504116b 100644 --- a/src/i18n/messages/hr.json +++ b/src/i18n/messages/hr.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Vaši URL-ovi za povezivanje s AI-jem", "apiManager": "API ključevi", "apiManagerSubtitle": "Upravljanje API ključevima i pristupom", - "modelCatalog": "Modeli i kombinacije", - "modelCatalogSubtitle": "Pregledajte modele i kombinacije među pružateljima", "embeddedServices": "Ugrađene usluge", "embeddedServicesSubtitle": "Neobavezne lokalne usluge", "logs": "Zapisnici", @@ -1205,8 +1203,8 @@ "batchGroup": "Skupna obrada", "homeSubtitle": "Pregled nadzorne ploče", "providersSubtitle": "Upravljanje AI pružateljima", - "modelCatalog": "Katalog modela", - "modelCatalogSubtitle": "Pregledajte modele svih pružatelja", + "modelCatalog": "Modeli i kombinacije", + "modelCatalogSubtitle": "Pregledajte modele i kombinacije među pružateljima", "quotaTrackerSubtitle": "Praćenje ograničenja korištenja", "providerQuotaSubtitle": "Praćenje ograničenja korištenja pružatelja", "runtimeSubtitle": "Otpornost i sesije u stvarnom vremenu", diff --git a/src/i18n/messages/hu.json b/src/i18n/messages/hu.json index e9013af01dc3..2ca81145aa43 100644 --- a/src/i18n/messages/hu.json +++ b/src/i18n/messages/hu.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Az Ön AI-kapcsolati URL-jei", "apiManager": "API-kezelő", "apiManagerSubtitle": "API-kulcsok és hozzáférés kezelése", - "modelCatalog": "Modellek és kombinációk", - "modelCatalogSubtitle": "Böngésszen a modellek és kombinációk között a szolgáltatóknál", "embeddedServices": "Beágyazott Szolgáltatások", "embeddedServicesSubtitle": "Helyi proxyszolgáltatások kezelése", "logs": "Naplók", @@ -1205,8 +1203,8 @@ "batchGroup": "Kötegelt feldolgozás", "homeSubtitle": "Irányítópult áttekintése", "providersSubtitle": "AI-szolgáltatók kezelése", - "modelCatalog": "Modellkatalógus", - "modelCatalogSubtitle": "Modellek böngészése szolgáltatók között", + "modelCatalog": "Modellek és kombinációk", + "modelCatalogSubtitle": "Böngésszen a modellek és kombinációk között a szolgáltatóknál", "quotaTrackerSubtitle": "Használati korlátok nyomon követése", "providerQuotaSubtitle": "Szolgáltatói használati korlátok nyomon követése", "runtimeSubtitle": "Valós idejű hibatűrés és munkamenetek", diff --git a/src/i18n/messages/hy.json b/src/i18n/messages/hy.json index 486a7c964d5f..55936db8ef56 100644 --- a/src/i18n/messages/hy.json +++ b/src/i18n/messages/hy.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Ձեր AI կապի URL-ները", "apiManager": "API բանալիներ", "apiManagerSubtitle": "Կառավարեք API բանալիներն ու հասանելիությունը", - "modelCatalog": "Մոդելներ և կոմբոներ", - "modelCatalogSubtitle": "Զննեք մոդելներն ու կոմբոները բոլոր մատակարարների շրջանում", "embeddedServices": "Ներկառուցված ծառայություններ", "embeddedServicesSubtitle": "Ընտրովի տեղային ծառայություններ", "logs": "Մատյաններ", @@ -1205,8 +1203,8 @@ "batchGroup": "Փաթեթային մշակում", "homeSubtitle": "Վահանակի ակնարկ", "providersSubtitle": "Կառավարել AI մատակարարներին", - "modelCatalog": "Մոդելների կատալոգ", - "modelCatalogSubtitle": "Դիտեք մոդելները բոլոր մատակարարներից", + "modelCatalog": "Մոդելներ և կոմբոներ", + "modelCatalogSubtitle": "Զննեք մոդելներն ու կոմբոները բոլոր մատակարարների շրջանում", "quotaTrackerSubtitle": "Հետևել օգտագործման սահմանաչափերին", "providerQuotaSubtitle": "Հետևել մատակարարների օգտագործման սահմանաչափերին", "runtimeSubtitle": "Իրական ժամանակի դիմակայունություն և աշխատաշրջաններ", diff --git a/src/i18n/messages/id.json b/src/i18n/messages/id.json index f39e39e43e86..5db3f7b46690 100644 --- a/src/i18n/messages/id.json +++ b/src/i18n/messages/id.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL koneksi AI Anda", "apiManager": "Manajer API", "apiManagerSubtitle": "Kelola kunci dan akses API", - "modelCatalog": "Model & Kombo", - "modelCatalogSubtitle": "Jelajahi model dan kombo di berbagai penyedia", "embeddedServices": "Layanan Tertanam", "embeddedServicesSubtitle": "Kelola layanan proxy lokal", "logs": "Log", @@ -1205,8 +1203,8 @@ "batchGroup": "Batch", "homeSubtitle": "Ringkasan dasbor", "providersSubtitle": "Kelola penyedia AI", - "modelCatalog": "Katalog model", - "modelCatalogSubtitle": "Jelajahi model dari berbagai penyedia", + "modelCatalog": "Model & Kombo", + "modelCatalogSubtitle": "Jelajahi model dan kombo di berbagai penyedia", "quotaTrackerSubtitle": "Lacak batas penggunaan", "providerQuotaSubtitle": "Lacak batas penggunaan penyedia", "runtimeSubtitle": "Ketahanan dan sesi secara real-time", diff --git a/src/i18n/messages/ig.json b/src/i18n/messages/ig.json index 6bdd345afd21..4e38c5f28ae8 100644 --- a/src/i18n/messages/ig.json +++ b/src/i18n/messages/ig.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL njikọ AI gị", "apiManager": "Igodo API", "apiManagerSubtitle": "Jikwaa igodo API na ohere nnweta", - "modelCatalog": "Ụdị & Ngwakọta", - "modelCatalogSubtitle": "Chọgharịa ụdị na ngwakọta n'ofe ndị na-eweta ọrụ", "embeddedServices": "Ọrụ agbakwunyere", "embeddedServicesSubtitle": "Ọrụ mpaghara nhọrọ", "logs": "Ndekọ", @@ -1205,8 +1203,8 @@ "batchGroup": "Ogbe", "homeSubtitle": "Nchịkọta dashboard", "providersSubtitle": "Jikwaa ndị na-eweta AI", - "modelCatalog": "Katalọgụ ụdị", - "modelCatalogSubtitle": "Chọgharịa ụdị n'ofe ndị na-eweta", + "modelCatalog": "Ụdị & Ngwakọta", + "modelCatalogSubtitle": "Chọgharịa ụdị na ngwakọta n'ofe ndị na-eweta ọrụ", "quotaTrackerSubtitle": "Sochie oke ojiji", "providerQuotaSubtitle": "Sochie oke ojiji nke onye na-eweta", "runtimeSubtitle": "Nkwụsi ike na nnọkọ ozugbo", diff --git a/src/i18n/messages/it.json b/src/i18n/messages/it.json index 62e7f0d63993..4ec6e208151f 100644 --- a/src/i18n/messages/it.json +++ b/src/i18n/messages/it.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "I tuoi URL di connessione AI", "apiManager": "Gestore API", "apiManagerSubtitle": "Gestisci le chiavi API e l'accesso", - "modelCatalog": "Modelli e combo", - "modelCatalogSubtitle": "Sfoglia modelli e combo tra i vari provider", "embeddedServices": "Servizi Integrati", "embeddedServicesSubtitle": "Gestisci i servizi proxy locali", "logs": "Registri", @@ -1205,8 +1203,8 @@ "batchGroup": "Elaborazione in batch", "homeSubtitle": "Panoramica della dashboard", "providersSubtitle": "Gestisci i provider di IA", - "modelCatalog": "Catalogo modelli", - "modelCatalogSubtitle": "Sfoglia i modelli di tutti i provider", + "modelCatalog": "Modelli e combo", + "modelCatalogSubtitle": "Sfoglia modelli e combo tra i vari provider", "quotaTrackerSubtitle": "Monitora i limiti di utilizzo", "providerQuotaSubtitle": "Monitora i limiti di utilizzo dei provider", "runtimeSubtitle": "Resilienza e sessioni in tempo reale", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index a2363e5f415e..61a45d7f93c9 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AI 接続 URL", "apiManager": "APIマネージャー", "apiManagerSubtitle": "API キーとアクセスを管理する", - "modelCatalog": "モデル & コンボ", - "modelCatalogSubtitle": "各プロバイダーのモデルとコンボを閲覧", "embeddedServices": "組み込みサービス", "embeddedServicesSubtitle": "ローカルプロキシサービスを管理する", "logs": "ログ", @@ -1205,8 +1203,8 @@ "batchGroup": "バッチ", "homeSubtitle": "ダッシュボード概要", "providersSubtitle": "AIプロバイダーを管理", - "modelCatalog": "モデルカタログ", - "modelCatalogSubtitle": "プロバイダー横断でモデルを閲覧", + "modelCatalog": "モデル & コンボ", + "modelCatalogSubtitle": "各プロバイダーのモデルとコンボを閲覧", "quotaTrackerSubtitle": "使用量上限を追跡", "providerQuotaSubtitle": "プロバイダーの使用量上限を追跡", "runtimeSubtitle": "リアルタイムの耐障害性とセッション", diff --git a/src/i18n/messages/ka.json b/src/i18n/messages/ka.json index 31297bb81456..7aeede4e50a8 100644 --- a/src/i18n/messages/ka.json +++ b/src/i18n/messages/ka.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "თქვენი AI კავშირის URL-ები", "apiManager": "API გასაღებები", "apiManagerSubtitle": "API გასაღებებისა და წვდომის მართვა", - "modelCatalog": "მოდელები და კომბოები", - "modelCatalogSubtitle": "დაათვალიერეთ მოდელები და კომბოები პროვაიდერებს შორის", "embeddedServices": "ჩაშენებული სერვისები", "embeddedServicesSubtitle": "არასავალდებულო ლოკალური სერვისები", "logs": "ჟურნალები", @@ -1205,8 +1203,8 @@ "batchGroup": "პაკეტური დამუშავება", "homeSubtitle": "მართვის პანელის მიმოხილვა", "providersSubtitle": "AI პროვაიდერების მართვა", - "modelCatalog": "მოდელების კატალოგი", - "modelCatalogSubtitle": "დაათვალიერეთ მოდელები ყველა პროვაიდერში", + "modelCatalog": "მოდელები და კომბოები", + "modelCatalogSubtitle": "დაათვალიერეთ მოდელები და კომბოები პროვაიდერებს შორის", "quotaTrackerSubtitle": "გამოყენების ლიმიტების თვალყურის დევნება", "providerQuotaSubtitle": "პროვაიდერის გამოყენების ლიმიტების თვალყურის დევნება", "runtimeSubtitle": "რეალურ დროში მდგრადობა და სესიები", diff --git a/src/i18n/messages/km.json b/src/i18n/messages/km.json index 57ce6a06141e..4f54bb393f3b 100644 --- a/src/i18n/messages/km.json +++ b/src/i18n/messages/km.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL សម្រាប់ការតភ្ជាប់ AI របស់អ្នក", "apiManager": "សោ API", "apiManagerSubtitle": "គ្រប់គ្រងសោ API និងសិទ្ធិចូលប្រើ", - "modelCatalog": "ម៉ូឌែល និងបន្សំ", - "modelCatalogSubtitle": "រកមើលម៉ូឌែល និងបន្សំនៅតាមអ្នកផ្តល់សេវាផ្សេងៗ", "embeddedServices": "សេវាកម្មដែលបានបង្កប់", "embeddedServicesSubtitle": "សេវាកម្មមូលដ្ឋានជាជម្រើស", "logs": "កំណត់ហេតុ", @@ -1205,8 +1203,8 @@ "batchGroup": "ដំណើរការជាបាច់", "homeSubtitle": "ទិដ្ឋភាពទូទៅនៃផ្ទាំងគ្រប់គ្រង", "providersSubtitle": "គ្រប់គ្រងអ្នកផ្តល់សេវា AI", - "modelCatalog": "កាតាឡុកម៉ូដែល", - "modelCatalogSubtitle": "រុករកម៉ូដែលពីអ្នកផ្តល់សេវាទាំងអស់", + "modelCatalog": "ម៉ូឌែល និងបន្សំ", + "modelCatalogSubtitle": "រកមើលម៉ូឌែល និងបន្សំនៅតាមអ្នកផ្តល់សេវាផ្សេងៗ", "quotaTrackerSubtitle": "តាមដានដែនកំណត់នៃការប្រើប្រាស់", "providerQuotaSubtitle": "តាមដានដែនកំណត់នៃការប្រើប្រាស់របស់អ្នកផ្តល់សេវា", "runtimeSubtitle": "ភាពធន់ និងវគ្គក្នុងពេលជាក់ស្តែង", diff --git a/src/i18n/messages/kn.json b/src/i18n/messages/kn.json index 811c10a6d6b3..9d0279f986f1 100644 --- a/src/i18n/messages/kn.json +++ b/src/i18n/messages/kn.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "ನಿಮ್ಮ AI ಸಂಪರ್ಕ URLs", "apiManager": "API ಕೀಗಳು", "apiManagerSubtitle": "API ಕೀಗಳು ಮತ್ತು ಪ್ರವೇಶವನ್ನು ನಿರ್ವಹಿಸಿ", - "modelCatalog": "ಮಾಡೆಲ್‌ಗಳು & ಕಾಂಬೋಗಳು", - "modelCatalogSubtitle": "ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾಡೆಲ್‌ಗಳು ಮತ್ತು ಕಾಂಬೋಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ", "embeddedServices": "ಅಂತರ್ನಿರ್ಮಿತ ಸೇವೆಗಳು", "embeddedServicesSubtitle": "ಐಚ್ಛಿಕ ಸ್ಥಳೀಯ ಸೇವೆಗಳು", "logs": "ಲಾಗ್ಗಳು", @@ -1205,8 +1203,8 @@ "batchGroup": "ಬ್ಯಾಚ್", "homeSubtitle": "ಡ್ಯಾಶ್ಬೋರ್ಡ್ ಅವಲೋಕನ", "providersSubtitle": "AI ಪ್ರೊವೈಡರ್ಗಳನ್ನು ನಿರ್ವಹಿಸಿ", - "modelCatalog": "ಮಾದರಿ ಕ್ಯಾಟಲಾಗ್", - "modelCatalogSubtitle": "ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾದರಿಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ", + "modelCatalog": "ಮಾಡೆಲ್‌ಗಳು & ಕಾಂಬೋಗಳು", + "modelCatalogSubtitle": "ಪೂರೈಕೆದಾರರಾದ್ಯಂತ ಮಾಡೆಲ್‌ಗಳು ಮತ್ತು ಕಾಂಬೋಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ", "quotaTrackerSubtitle": "ಬಳಕೆ ಮಿತಿಗಳನ್ನು ಟ್ರ್ಯಾಕ್ ಮಾಡಿ", "providerQuotaSubtitle": "ಪ್ರೊವೈಡರ್ ಬಳಕೆಯ ಮಿತಿಗಳನ್ನು ಟ್ರ್ಯಾಕ್ ಮಾಡಿ", "runtimeSubtitle": "ನೈಜ-ಸಮಯದ ಸ್ಥಿತಿಸ್ಥಾಪಕತೆ ಮತ್ತು ಸೆಷನ್ಗಳು", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index 0336dd835cb1..da101653825e 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "귀하의 AI 연결 URL", "apiManager": "API 키", "apiManagerSubtitle": "API 키 및 액세스 관리", - "modelCatalog": "모델 및 콤보", - "modelCatalogSubtitle": "여러 제공자의 모델 및 콤보 둘러보기", "embeddedServices": "내장 서비스", "embeddedServicesSubtitle": "로컬 프록시 서비스 관리", "logs": "로그", @@ -1205,8 +1203,8 @@ "batchGroup": "일괄 처리", "homeSubtitle": "대시보드 개요", "providersSubtitle": "AI 제공업체 관리", - "modelCatalog": "모델 카탈로그", - "modelCatalogSubtitle": "여러 제공업체의 모델 둘러보기", + "modelCatalog": "모델 및 콤보", + "modelCatalogSubtitle": "여러 제공자의 모델 및 콤보 둘러보기", "quotaTrackerSubtitle": "사용량 한도 추적", "providerQuotaSubtitle": "제공업체 사용량 한도 추적", "runtimeSubtitle": "실시간 복원력 및 세션", diff --git a/src/i18n/messages/lt.json b/src/i18n/messages/lt.json index dfc426f4b627..c684e7875333 100644 --- a/src/i18n/messages/lt.json +++ b/src/i18n/messages/lt.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Jūsų DI ryšio URL adresai", "apiManager": "API raktai", "apiManagerSubtitle": "Tvarkyti API raktus ir prieigą", - "modelCatalog": "Modeliai ir deriniai", - "modelCatalogSubtitle": "Naršykite modelius ir derinius iš įvairių teikėjų", "embeddedServices": "Įterptosios paslaugos", "embeddedServicesSubtitle": "Pasirenkamos vietinės paslaugos", "logs": "Žurnalai", @@ -1205,8 +1203,8 @@ "batchGroup": "Paketinis apdorojimas", "homeSubtitle": "Skydelio apžvalga", "providersSubtitle": "AI teikėjų valdymas", - "modelCatalog": "Modelių katalogas", - "modelCatalogSubtitle": "Naršykite visų tiekėjų modelius", + "modelCatalog": "Modeliai ir deriniai", + "modelCatalogSubtitle": "Naršykite modelius ir derinius iš įvairių teikėjų", "quotaTrackerSubtitle": "Naudojimo apribojimų stebėjimas", "providerQuotaSubtitle": "Teikėjo naudojimo apribojimų stebėjimas", "runtimeSubtitle": "Atsparumas realiuoju laiku ir seansai", diff --git a/src/i18n/messages/lv.json b/src/i18n/messages/lv.json index 09f67a93627c..b03ac155ef72 100644 --- a/src/i18n/messages/lv.json +++ b/src/i18n/messages/lv.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Jūsu AI savienojuma URL", "apiManager": "API atslēgas", "apiManagerSubtitle": "Pārvaldīt API atslēgas un piekļuvi", - "modelCatalog": "Modeļi un kombinācijas", - "modelCatalogSubtitle": "Pārlūkot modeļus un kombinācijas visos pakalpojumu sniedzējos", "embeddedServices": "Iegultie pakalpojumi", "embeddedServicesSubtitle": "Neobligāti lokālie pakalpojumi", "logs": "Žurnāli", @@ -1205,8 +1203,8 @@ "batchGroup": "Pakešu apstrāde", "homeSubtitle": "Informācijas paneļa pārskats", "providersSubtitle": "Pārvaldīt AI nodrošinātājus", - "modelCatalog": "Modeļu katalogs", - "modelCatalogSubtitle": "Pārlūkojiet visu pakalpojumu sniedzēju modeļus", + "modelCatalog": "Modeļi un kombinācijas", + "modelCatalogSubtitle": "Pārlūkot modeļus un kombinācijas visos pakalpojumu sniedzējos", "quotaTrackerSubtitle": "Sekot lietojuma limitiem", "providerQuotaSubtitle": "Sekot nodrošinātāja lietojuma limitiem", "runtimeSubtitle": "Reāllaika noturība un sesijas", diff --git a/src/i18n/messages/ml.json b/src/i18n/messages/ml.json index b7ee32689572..b21518409b7e 100644 --- a/src/i18n/messages/ml.json +++ b/src/i18n/messages/ml.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "നിങ്ങളുടെ AI കണക്ഷൻ URL-കൾ", "apiManager": "API കീകൾ", "apiManagerSubtitle": "API കീകളും ആക്സസും നിയന്ത്രിക്കുക", - "modelCatalog": "മോഡലുകളും കോമ്പോകളും", - "modelCatalogSubtitle": "വിവിധ പ്രൊവൈഡർമാരിലുടനീളമുള്ള മോഡലുകളും കോമ്പോകളും ബ്രൗസ് ചെയ്യുക", "embeddedServices": "എംബെഡഡ് സേവനങ്ങൾ", "embeddedServicesSubtitle": "ഐച്ഛിക ലോക്കൽ സേവനങ്ങൾ", "logs": "ലോഗുകൾ", @@ -1205,8 +1203,8 @@ "batchGroup": "ബാച്ച്", "homeSubtitle": "ഡാഷ്ബോർഡ് അവലോകനം", "providersSubtitle": "AI പ്രൊവൈഡർമാരെ നിയന്ത്രിക്കുക", - "modelCatalog": "മോഡൽ കാറ്റലോഗ്", - "modelCatalogSubtitle": "ദാതാക്കളിലുടനീളമുള്ള മോഡലുകൾ ബ്രൗസ് ചെയ്യുക", + "modelCatalog": "മോഡലുകളും കോമ്പോകളും", + "modelCatalogSubtitle": "വിവിധ പ്രൊവൈഡർമാരിലുടനീളമുള്ള മോഡലുകളും കോമ്പോകളും ബ്രൗസ് ചെയ്യുക", "quotaTrackerSubtitle": "ഉപയോഗ പരിധികൾ ട്രാക്ക് ചെയ്യുക", "providerQuotaSubtitle": "പ്രൊവൈഡർ ഉപയോഗ പരിധികൾ ട്രാക്ക് ചെയ്യുക", "runtimeSubtitle": "തത്സമയ പ്രതിരോധശേഷിയും സെഷനുകളും", diff --git a/src/i18n/messages/mr.json b/src/i18n/messages/mr.json index 44fe2df0075f..e86b92cd3002 100644 --- a/src/i18n/messages/mr.json +++ b/src/i18n/messages/mr.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "तुमचे AI कनेक्शन URL", "apiManager": "API कीज", "apiManagerSubtitle": "API की आणि प्रवेश व्यवस्थापित करा", - "modelCatalog": "मॉडेल्स आणि कॉम्बो", - "modelCatalogSubtitle": "विविध प्रदात्यांमधील मॉडेल्स आणि कॉम्बो ब्राउझ करा", "embeddedServices": "एम्बेडेड सेवा", "embeddedServicesSubtitle": "स्थानिक प्रॉक्सी सेवा व्यवस्थापित करा", "logs": "लॉग्स", @@ -1205,8 +1203,8 @@ "batchGroup": "बॅच", "homeSubtitle": "डॅशबोर्डचा आढावा", "providersSubtitle": "AI प्रदाते व्यवस्थापित करा", - "modelCatalog": "मॉडेल कॅटलॉग", - "modelCatalogSubtitle": "सर्व प्रदात्यांमधील मॉडेल्स ब्राउझ करा", + "modelCatalog": "मॉडेल्स आणि कॉम्बो", + "modelCatalogSubtitle": "विविध प्रदात्यांमधील मॉडेल्स आणि कॉम्बो ब्राउझ करा", "quotaTrackerSubtitle": "वापर मर्यादांचा मागोवा घ्या", "providerQuotaSubtitle": "प्रदात्याच्या वापर मर्यादांचा मागोवा घ्या", "runtimeSubtitle": "रिअल-टाइम लवचिकता आणि सत्रे", diff --git a/src/i18n/messages/ms.json b/src/i18n/messages/ms.json index 797293db1ae9..d13c74fb385d 100644 --- a/src/i18n/messages/ms.json +++ b/src/i18n/messages/ms.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL sambungan AI anda", "apiManager": "Pengurus API", "apiManagerSubtitle": "Urus kunci dan akses API", - "modelCatalog": "Model & Kombo", - "modelCatalogSubtitle": "Semak imbas model dan kombo merentas penyedia", "embeddedServices": "Perkhidmatan Terbenam", "embeddedServicesSubtitle": "Urus perkhidmatan proksi tempatan", "logs": "Log", @@ -1205,8 +1203,8 @@ "batchGroup": "Kelompok", "homeSubtitle": "Gambaran keseluruhan papan pemuka", "providersSubtitle": "Urus penyedia AI", - "modelCatalog": "Katalog model", - "modelCatalogSubtitle": "Layari model merentas pembekal", + "modelCatalog": "Model & Kombo", + "modelCatalogSubtitle": "Semak imbas model dan kombo merentas penyedia", "quotaTrackerSubtitle": "Jejak had penggunaan", "providerQuotaSubtitle": "Jejak had penggunaan penyedia", "runtimeSubtitle": "Ketahanan masa nyata & sesi", diff --git a/src/i18n/messages/mt.json b/src/i18n/messages/mt.json index 65e52a97aef0..c30345d23cc3 100644 --- a/src/i18n/messages/mt.json +++ b/src/i18n/messages/mt.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Il-URLs tal-konnessjoni tiegħek mal-IA", "apiManager": "Ċwievet tal-API", "apiManagerSubtitle": "Immaniġġja ċ-ċwievet tal-API u l-aċċess", - "modelCatalog": "Mudelli u Combos", - "modelCatalogSubtitle": "Esplora mudelli u combos fost il-fornituri", "embeddedServices": "Servizzi Inkorporati", "embeddedServicesSubtitle": "Servizzi lokali fakultattivi", "logs": "Reġistri", @@ -1205,8 +1203,8 @@ "batchGroup": "Lott", "homeSubtitle": "Ħarsa ġenerali tad-dashboard", "providersSubtitle": "Immaniġġja l-fornituri tal-IA", - "modelCatalog": "Katalgu tal-mudelli", - "modelCatalogSubtitle": "Ibbrawżja mudelli minn fornituri differenti", + "modelCatalog": "Mudelli u Combos", + "modelCatalogSubtitle": "Esplora mudelli u combos fost il-fornituri", "quotaTrackerSubtitle": "Segwi l-limiti tal-użu", "providerQuotaSubtitle": "Segwi l-limiti tal-użu tal-fornituri", "runtimeSubtitle": "Reżiljenza u sessjonijiet f'ħin reali", diff --git a/src/i18n/messages/my.json b/src/i18n/messages/my.json index 5709983c08de..4dbd06f889c0 100644 --- a/src/i18n/messages/my.json +++ b/src/i18n/messages/my.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "သင့် AI ချိတ်ဆက်မှု URL များ", "apiManager": "API သော့များ", "apiManagerSubtitle": "API သော့များနှင့် အသုံးပြုခွင့်ကို စီမံရန်", - "modelCatalog": "မော်ဒယ်များနှင့် Combos", - "modelCatalogSubtitle": "Provider များတစ်လျှောက် မော်ဒယ်များနှင့် combos များကို ရှာဖွေကြည့်ရှုပါ", "embeddedServices": "ပေါင်းစပ်ထည့်သွင်းထားသော ဝန်ဆောင်မှုများ", "embeddedServicesSubtitle": "ရွေးချယ်အသုံးပြုနိုင်သော စက်တွင်းဝန်ဆောင်မှုများ", "logs": "မှတ်တမ်းများ", @@ -1205,8 +1203,8 @@ "batchGroup": "အသုတ်လိုက်", "homeSubtitle": "ဒက်ရှ်ဘုတ် ခြုံငုံသုံးသပ်ချက်", "providersSubtitle": "AI ဝန်ဆောင်မှုပေးသူများကို စီမံခန့်ခွဲရန်", - "modelCatalog": "မော်ဒယ်ကတ်တလောက်", - "modelCatalogSubtitle": "ပံ့ပိုးသူများအားလုံးမှ မော်ဒယ်များကို ကြည့်ရှုပါ", + "modelCatalog": "မော်ဒယ်များနှင့် Combos", + "modelCatalogSubtitle": "Provider များတစ်လျှောက် မော်ဒယ်များနှင့် combos များကို ရှာဖွေကြည့်ရှုပါ", "quotaTrackerSubtitle": "အသုံးပြုမှု ကန့်သတ်ချက်များကို ခြေရာခံရန်", "providerQuotaSubtitle": "ဝန်ဆောင်မှုပေးသူ၏ အသုံးပြုမှု ကန့်သတ်ချက်များကို ခြေရာခံရန်", "runtimeSubtitle": "အချိန်နှင့်တစ်ပြေးညီ ခံနိုင်ရည်ရှိမှုနှင့် ဆက်ရှင်များ", diff --git a/src/i18n/messages/ne.json b/src/i18n/messages/ne.json index 8a4a6f9ba356..8d9f9ed245cb 100644 --- a/src/i18n/messages/ne.json +++ b/src/i18n/messages/ne.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "तपाईंका AI जडान URL हरू", "apiManager": "API कुञ्जीहरू", "apiManagerSubtitle": "API कुञ्जीहरू र पहुँच व्यवस्थापन गर्नुहोस्", - "modelCatalog": "मोडेल र कम्बोहरू", - "modelCatalogSubtitle": "विभिन्न प्रदायकहरूका मोडेल र कम्बोहरू ब्राउज गर्नुहोस्", "embeddedServices": "एम्बेडेड सेवाहरू", "embeddedServicesSubtitle": "वैकल्पिक स्थानीय सेवाहरू", "logs": "लगहरू", @@ -1205,8 +1203,8 @@ "batchGroup": "ब्याच", "homeSubtitle": "ड्यासबोर्ड अवलोकन", "providersSubtitle": "AI प्रदायकहरू व्यवस्थापन गर्नुहोस्", - "modelCatalog": "मोडेल सूची", - "modelCatalogSubtitle": "प्रदायकहरूभरिका मोडेलहरू हेर्नुहोस्", + "modelCatalog": "मोडेल र कम्बोहरू", + "modelCatalogSubtitle": "विभिन्न प्रदायकहरूका मोडेल र कम्बोहरू ब्राउज गर्नुहोस्", "quotaTrackerSubtitle": "प्रयोग सीमाहरू ट्र्याक गर्नुहोस्", "providerQuotaSubtitle": "प्रदायकका प्रयोग सीमाहरू ट्र्याक गर्नुहोस्", "runtimeSubtitle": "वास्तविक-समयको लचिलोपन र सत्रहरू", diff --git a/src/i18n/messages/nl.json b/src/i18n/messages/nl.json index c5a06d413f8e..b41f3195d9d1 100644 --- a/src/i18n/messages/nl.json +++ b/src/i18n/messages/nl.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Uw AI-verbindings-URL's", "apiManager": "API-beheerder", "apiManagerSubtitle": "Beheer API-sleutels en toegang", - "modelCatalog": "Modellen & combo's", - "modelCatalogSubtitle": "Blader door modellen en combo's van verschillende providers", "embeddedServices": "Ingebedde Diensten", "embeddedServicesSubtitle": "Beheer lokale proxydiensten", "logs": "Logboeken", @@ -1205,8 +1203,8 @@ "batchGroup": "Batch", "homeSubtitle": "Dashboardoverzicht", "providersSubtitle": "AI-providers beheren", - "modelCatalog": "Modelcatalogus", - "modelCatalogSubtitle": "Blader door modellen van alle providers", + "modelCatalog": "Modellen & combo's", + "modelCatalogSubtitle": "Blader door modellen en combo's van verschillende providers", "quotaTrackerSubtitle": "Gebruikslimieten bijhouden", "providerQuotaSubtitle": "Gebruikslimieten van providers bijhouden", "runtimeSubtitle": "Realtime veerkracht en sessies", diff --git a/src/i18n/messages/no.json b/src/i18n/messages/no.json index 6180335c83db..4ba93ef0fc2c 100644 --- a/src/i18n/messages/no.json +++ b/src/i18n/messages/no.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Dine AI-tilkoblings-URLer", "apiManager": "API-behandler", "apiManagerSubtitle": "Administrer API-nøkler og tilgang", - "modelCatalog": "Modeller og kombinasjoner", - "modelCatalogSubtitle": "Bla gjennom modeller og kombinasjoner på tvers av leverandører", "embeddedServices": "Innebygde tjenester", "embeddedServicesSubtitle": "Administrer lokale proxytjenester", "logs": "Logger", @@ -1205,8 +1203,8 @@ "batchGroup": "Gruppebehandling", "homeSubtitle": "Oversikt over kontrollpanelet", "providersSubtitle": "Administrer AI-leverandører", - "modelCatalog": "Modellkatalog", - "modelCatalogSubtitle": "Bla gjennom modeller på tvers av leverandører", + "modelCatalog": "Modeller og kombinasjoner", + "modelCatalogSubtitle": "Bla gjennom modeller og kombinasjoner på tvers av leverandører", "quotaTrackerSubtitle": "Spor bruksgrenser", "providerQuotaSubtitle": "Spor leverandørenes bruksgrenser", "runtimeSubtitle": "Robusthet og økter i sanntid", diff --git a/src/i18n/messages/or.json b/src/i18n/messages/or.json index bf5a5c3e2968..97e4def675df 100644 --- a/src/i18n/messages/or.json +++ b/src/i18n/messages/or.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "ଆପଣଙ୍କ AI ସଂଯୋଗ URLs", "apiManager": "API କୀଗୁଡ଼ିକ", "apiManagerSubtitle": "API କୀ ଏବଂ ପ୍ରବେଶ ପରିଚାଳନା କରନ୍ତୁ", - "modelCatalog": "ମଡେଲ୍ ଏବଂ କମ୍ବୋ", - "modelCatalogSubtitle": "ପ୍ରୋଭାଇଡର୍‌ଗୁଡ଼ିକ ମଧ୍ୟରେ ମଡେଲ୍ ଏବଂ କମ୍ବୋ ବ୍ରାଉଜ୍ କରନ୍ତୁ", "embeddedServices": "ଅନ୍ତର୍ନିହିତ ସେବାଗୁଡ଼ିକ", "embeddedServicesSubtitle": "ଇଚ୍ଛାଧୀନ ସ୍ଥାନୀୟ ସେବାଗୁଡ଼ିକ", "logs": "ଲଗ୍ଗୁଡ଼ିକ", @@ -1205,8 +1203,8 @@ "batchGroup": "ବ୍ୟାଚ୍", "homeSubtitle": "ଡ୍ୟାସ୍ବୋର୍ଡ ସାରାଂଶ", "providersSubtitle": "AI ପ୍ରଦାନକାରୀମାନଙ୍କୁ ପରିଚାଳନା କରନ୍ତୁ", - "modelCatalog": "ମଡେଲ କ୍ୟାଟାଲଗ", - "modelCatalogSubtitle": "ପ୍ରଦାନକାରୀଙ୍କ ମଧ୍ୟରେ ମଡେଲ ବ୍ରାଉଜ କରନ୍ତୁ", + "modelCatalog": "ମଡେଲ୍ ଏବଂ କମ୍ବୋ", + "modelCatalogSubtitle": "ପ୍ରୋଭାଇଡର୍‌ଗୁଡ଼ିକ ମଧ୍ୟରେ ମଡେଲ୍ ଏବଂ କମ୍ବୋ ବ୍ରାଉଜ୍ କରନ୍ତୁ", "quotaTrackerSubtitle": "ବ୍ୟବହାର ସୀମାଗୁଡ଼ିକୁ ଟ୍ରାକ୍ କରନ୍ତୁ", "providerQuotaSubtitle": "ପ୍ରଦାନକାରୀଙ୍କ ବ୍ୟବହାର ସୀମାଗୁଡ଼ିକୁ ଟ୍ରାକ୍ କରନ୍ତୁ", "runtimeSubtitle": "ବାସ୍ତବ-ସମୟ ସ୍ଥିତିସ୍ଥାପକତା ଓ ସେସନ୍ଗୁଡ଼ିକ", diff --git a/src/i18n/messages/pa.json b/src/i18n/messages/pa.json index 117f0e8e1025..cc965b074bf3 100644 --- a/src/i18n/messages/pa.json +++ b/src/i18n/messages/pa.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "ਤੁਹਾਡੇ AI ਕਨੈਕਸ਼ਨ URL", "apiManager": "API ਕੁੰਜੀਆਂ", "apiManagerSubtitle": "API ਕੁੰਜੀਆਂ ਅਤੇ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", - "modelCatalog": "ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼", - "modelCatalogSubtitle": "ਸਾਰੇ ਪ੍ਰੋਵਾਈਡਰਾਂ ਵਿੱਚ ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼ ਬ੍ਰਾਊਜ਼ ਕਰੋ", "embeddedServices": "ਐਂਬੈਡ ਕੀਤੀਆਂ ਸੇਵਾਵਾਂ", "embeddedServicesSubtitle": "ਵਿਕਲਪਿਕ ਲੋਕਲ ਸੇਵਾਵਾਂ", "logs": "ਲੌਗ", @@ -1205,8 +1203,8 @@ "batchGroup": "ਬੈਚ", "homeSubtitle": "ਡੈਸ਼ਬੋਰਡ ਦੀ ਸੰਖੇਪ ਜਾਣਕਾਰੀ", "providersSubtitle": "AI ਪ੍ਰਦਾਤਿਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", - "modelCatalog": "ਮਾਡਲ ਕੈਟਾਲਾਗ", - "modelCatalogSubtitle": "ਸਾਰੇ ਪ੍ਰਦਾਤਿਆਂ ਦੇ ਮਾਡਲ ਬ੍ਰਾਊਜ਼ ਕਰੋ", + "modelCatalog": "ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼", + "modelCatalogSubtitle": "ਸਾਰੇ ਪ੍ਰੋਵਾਈਡਰਾਂ ਵਿੱਚ ਮਾਡਲ ਅਤੇ ਕੰਬੋਜ਼ ਬ੍ਰਾਊਜ਼ ਕਰੋ", "quotaTrackerSubtitle": "ਵਰਤੋਂ ਦੀਆਂ ਸੀਮਾਵਾਂ ਟ੍ਰੈਕ ਕਰੋ", "providerQuotaSubtitle": "ਪ੍ਰਦਾਤਾ ਦੀਆਂ ਵਰਤੋਂ ਸੀਮਾਵਾਂ ਟ੍ਰੈਕ ਕਰੋ", "runtimeSubtitle": "ਰੀਅਲ-ਟਾਈਮ ਲਚਕੀਲਾਪਣ ਅਤੇ ਸੈਸ਼ਨ", diff --git a/src/i18n/messages/phi.json b/src/i18n/messages/phi.json index c4563619ef94..bc6d1ef73501 100644 --- a/src/i18n/messages/phi.json +++ b/src/i18n/messages/phi.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Ang iyong mga URL ng koneksyon sa AI", "apiManager": "Tagapamahala ng API", "apiManagerSubtitle": "Pamahalaan ang mga API key at access", - "modelCatalog": "Mga Modelo at Combo", - "modelCatalogSubtitle": "Mag-browse ng mga modelo at combo sa iba't ibang provider", "embeddedServices": "Mga Naka-embed na Serbisyo", "embeddedServicesSubtitle": "Pamahalaan ang mga lokal na proxy na serbisyo", "logs": "Mga log", @@ -1205,8 +1203,8 @@ "batchGroup": "Pangkat", "homeSubtitle": "Pangkalahatang-ideya ng dashboard", "providersSubtitle": "Pamahalaan ang mga AI provider", - "modelCatalog": "Katalogo ng modelo", - "modelCatalogSubtitle": "Mag-browse ng mga modelo mula sa iba't ibang provider", + "modelCatalog": "Mga Modelo at Combo", + "modelCatalogSubtitle": "Mag-browse ng mga modelo at combo sa iba't ibang provider", "quotaTrackerSubtitle": "Subaybayan ang mga limitasyon sa paggamit", "providerQuotaSubtitle": "Subaybayan ang mga limitasyon sa paggamit ng provider", "runtimeSubtitle": "Real-time na katatagan at mga session", diff --git a/src/i18n/messages/pl.json b/src/i18n/messages/pl.json index b0eb7fba6ebe..8e071660a7bc 100644 --- a/src/i18n/messages/pl.json +++ b/src/i18n/messages/pl.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Adresy URL połączeń AI", "apiManager": "Klucze API", "apiManagerSubtitle": "Zarządzanie kluczami API i dostępem", - "modelCatalog": "Modele i kombinacje", - "modelCatalogSubtitle": "Przeglądaj modele i kombinacje u różnych dostawców", "embeddedServices": "Usługi osadzone", "embeddedServicesSubtitle": "Zarządzanie lokalnymi usługami proxy", "logs": "Logi", @@ -1205,8 +1203,8 @@ "batchGroup": "Przetwarzanie wsadowe", "homeSubtitle": "Przegląd Dashboard", "providersSubtitle": "Zarządzanie AI providers", - "modelCatalog": "Katalog modeli", - "modelCatalogSubtitle": "Przeglądaj modele wszystkich dostawców", + "modelCatalog": "Modele i kombinacje", + "modelCatalogSubtitle": "Przeglądaj modele i kombinacje u różnych dostawców", "quotaTrackerSubtitle": "Śledzenie limitów użycia", "providerQuotaSubtitle": "Śledzenie limitów użycia provider", "runtimeSubtitle": "Niezawodność i sesje w czasie rzeczywistym", diff --git a/src/i18n/messages/pt-BR.json b/src/i18n/messages/pt-BR.json index 690a993f19f4..33ae37b6f2e1 100644 --- a/src/i18n/messages/pt-BR.json +++ b/src/i18n/messages/pt-BR.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Seus URLs de conexão de IA", "apiManager": "Gerenciador API", "apiManagerSubtitle": "Gerenciar chaves de API e acesso", - "modelCatalog": "Modelos e Combos", - "modelCatalogSubtitle": "Navegue por modelos e combos entre provedores", "embeddedServices": "Serviços Embarcados", "embeddedServicesSubtitle": "Gerenciar serviços de proxy locais", "logs": "Registros", @@ -1205,8 +1203,8 @@ "batchGroup": "Lote", "homeSubtitle": "Visão geral do painel", "providersSubtitle": "Gerenciar provedores de IA", - "modelCatalog": "Catálogo de modelos", - "modelCatalogSubtitle": "Navegar pelos modelos de todos os provedores", + "modelCatalog": "Modelos e Combos", + "modelCatalogSubtitle": "Navegue por modelos e combos entre provedores", "quotaTrackerSubtitle": "Acompanhar limites de uso", "providerQuotaSubtitle": "Acompanhar limites de uso por provedor", "runtimeSubtitle": "Resiliência e sessões em tempo real", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 3aab11bdc688..507eb240ffe2 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Seus URLs de conexão de IA", "apiManager": "Gerenciador de APIs", "apiManagerSubtitle": "Gerenciar chaves de API e acesso", - "modelCatalog": "Modelos e Combos", - "modelCatalogSubtitle": "Explorar modelos e combos entre fornecedores", "embeddedServices": "Serviços Integrados", "embeddedServicesSubtitle": "Gerenciar serviços proxy locais", "logs": "Registros", @@ -1205,8 +1203,8 @@ "batchGroup": "Lote", "homeSubtitle": "Visão geral do painel", "providersSubtitle": "Gerenciar provedores de IA", - "modelCatalog": "Catálogo de modelos", - "modelCatalogSubtitle": "Explore modelos de todos os fornecedores", + "modelCatalog": "Modelos e Combos", + "modelCatalogSubtitle": "Explorar modelos e combos entre fornecedores", "quotaTrackerSubtitle": "Acompanhar limites de uso", "providerQuotaSubtitle": "Rastreie os limites de uso do provedor", "runtimeSubtitle": "Resiliência e sessões em tempo real", diff --git a/src/i18n/messages/ro.json b/src/i18n/messages/ro.json index 813a8c678f27..8ab40fc4d8bf 100644 --- a/src/i18n/messages/ro.json +++ b/src/i18n/messages/ro.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Adresele URL ale conexiunii dvs. AI", "apiManager": "Manager API", "apiManagerSubtitle": "Gestionați cheile API și accesul", - "modelCatalog": "Modele & Combinații", - "modelCatalogSubtitle": "Răsfoiește modele și combinații de la diverși furnizori", "embeddedServices": "Servicii Integrate", "embeddedServicesSubtitle": "Gestionați serviciile proxy locale", "logs": "Bușteni", @@ -1205,8 +1203,8 @@ "batchGroup": "Procesare în lot", "homeSubtitle": "Prezentare generală a tabloului de bord", "providersSubtitle": "Gestionarea furnizorilor AI", - "modelCatalog": "Catalog de modele", - "modelCatalogSubtitle": "Răsfoiește modelele tuturor furnizorilor", + "modelCatalog": "Modele & Combinații", + "modelCatalogSubtitle": "Răsfoiește modele și combinații de la diverși furnizori", "quotaTrackerSubtitle": "Urmărirea limitelor de utilizare", "providerQuotaSubtitle": "Urmărirea limitelor de utilizare ale furnizorului", "runtimeSubtitle": "Reziliență și sesiuni în timp real", diff --git a/src/i18n/messages/ru.json b/src/i18n/messages/ru.json index a58b03c1adfa..3d6fb96d6993 100644 --- a/src/i18n/messages/ru.json +++ b/src/i18n/messages/ru.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL-адреса вашего подключения к AI", "apiManager": "Менеджер API", "apiManagerSubtitle": "Управление ключами API и доступом", - "modelCatalog": "Модели и комбо", - "modelCatalogSubtitle": "Просмотр моделей и комбо среди провайдеров", "embeddedServices": "Встроенные Сервисы", "embeddedServicesSubtitle": "Управление локальными прокси-сервисами", "logs": "Журналы", @@ -1205,8 +1203,8 @@ "batchGroup": "Пакетная обработка", "homeSubtitle": "Обзор панели управления", "providersSubtitle": "Управление AI-провайдерами", - "modelCatalog": "Каталог моделей", - "modelCatalogSubtitle": "Просматривайте модели всех провайдеров", + "modelCatalog": "Модели и комбо", + "modelCatalogSubtitle": "Просмотр моделей и комбо среди провайдеров", "quotaTrackerSubtitle": "Отслеживание лимитов использования", "providerQuotaSubtitle": "Отслеживание лимитов использования провайдера", "runtimeSubtitle": "Отказоустойчивость и сеансы в реальном времени", diff --git a/src/i18n/messages/si.json b/src/i18n/messages/si.json index 7b8c855d8d85..044c6a985315 100644 --- a/src/i18n/messages/si.json +++ b/src/i18n/messages/si.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "ඔබගේ AI සම්බන්ධතා URL", "apiManager": "API යතුරු", "apiManagerSubtitle": "API යතුරු සහ ප්රවේශය කළමනාකරණය කරන්න", - "modelCatalog": "මොඩල සහ සංයෝජන", - "modelCatalogSubtitle": "සපයන්නන් හරහා මොඩල සහ සංයෝජන පිරික්සන්න", "embeddedServices": "කාවැද්දූ සේවා", "embeddedServicesSubtitle": "විකල්ප දේශීය සේවා", "logs": "ලොග්", @@ -1205,8 +1203,8 @@ "batchGroup": "කාණ්ඩ සැකසීම", "homeSubtitle": "උපකරණ පුවරු සාරාංශය", "providersSubtitle": "AI සපයන්නන් කළමනාකරණය කරන්න", - "modelCatalog": "මාදිලි නාමාවලිය", - "modelCatalogSubtitle": "සපයන්නන් හරහා මාදිලි පිරික්සන්න", + "modelCatalog": "මොඩල සහ සංයෝජන", + "modelCatalogSubtitle": "සපයන්නන් හරහා මොඩල සහ සංයෝජන පිරික්සන්න", "quotaTrackerSubtitle": "භාවිත සීමා නිරීක්ෂණය කරන්න", "providerQuotaSubtitle": "සපයන්නාගේ භාවිත සීමා නිරීක්ෂණය කරන්න", "runtimeSubtitle": "තත්යකාලීන ප්රත්යස්ථතාව සහ සැසි", diff --git a/src/i18n/messages/sk.json b/src/i18n/messages/sk.json index db73a6339638..b7a77e68062c 100644 --- a/src/i18n/messages/sk.json +++ b/src/i18n/messages/sk.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Vaše webové adresy pripojenia AI", "apiManager": "Kľúče API", "apiManagerSubtitle": "Spravujte kľúče API a prístup", - "modelCatalog": "Modely a kombinácie", - "modelCatalogSubtitle": "Prehliadajte modely a kombinácie naprieč poskytovateľmi", "embeddedServices": "Zabudované Služby", "embeddedServicesSubtitle": "Spravovať lokálne proxy služby", "logs": "Denníky", @@ -1205,8 +1203,8 @@ "batchGroup": "Dávkové spracovanie", "homeSubtitle": "Prehľad ovládacieho panela", "providersSubtitle": "Spravovať poskytovateľov AI", - "modelCatalog": "Katalóg modelov", - "modelCatalogSubtitle": "Prehliadajte modely naprieč poskytovateľmi", + "modelCatalog": "Modely a kombinácie", + "modelCatalogSubtitle": "Prehliadajte modely a kombinácie naprieč poskytovateľmi", "quotaTrackerSubtitle": "Sledovať limity používania", "providerQuotaSubtitle": "Sledovať limity používania poskytovateľov", "runtimeSubtitle": "Odolnosť a relácie v reálnom čase", diff --git a/src/i18n/messages/sl.json b/src/i18n/messages/sl.json index d754cc472e69..ff67277d696a 100644 --- a/src/i18n/messages/sl.json +++ b/src/i18n/messages/sl.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL-ji vaših povezav z umetno inteligenco", "apiManager": "Ključi API", "apiManagerSubtitle": "Upravljanje ključev API in dostopa", - "modelCatalog": "Modeli in kombinacije", - "modelCatalogSubtitle": "Prebrskajte modele in kombinacije pri različnih ponudnikih", "embeddedServices": "Vdelane storitve", "embeddedServicesSubtitle": "Izbirne lokalne storitve", "logs": "Dnevniki", @@ -1205,8 +1203,8 @@ "batchGroup": "Paketna obdelava", "homeSubtitle": "Pregled nadzorne plošče", "providersSubtitle": "Upravljanje ponudnikov umetne inteligence", - "modelCatalog": "Katalog modelov", - "modelCatalogSubtitle": "Brskajte po modelih vseh ponudnikov", + "modelCatalog": "Modeli in kombinacije", + "modelCatalogSubtitle": "Prebrskajte modele in kombinacije pri različnih ponudnikih", "quotaTrackerSubtitle": "Spremljanje omejitev uporabe", "providerQuotaSubtitle": "Spremljanje omejitev uporabe ponudnikov", "runtimeSubtitle": "Odpornost in seje v realnem času", diff --git a/src/i18n/messages/sr.json b/src/i18n/messages/sr.json index 88b7ae2b3e6d..0e9766564289 100644 --- a/src/i18n/messages/sr.json +++ b/src/i18n/messages/sr.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL адресе за повезивање са AI-јем", "apiManager": "API кључеви", "apiManagerSubtitle": "Управљајте API кључевима и приступом", - "modelCatalog": "Модели и комбинације", - "modelCatalogSubtitle": "Прегледајте моделе и комбинације код различитих пружалаца услуга", "embeddedServices": "Уграђене услуге", "embeddedServicesSubtitle": "Необавезне локалне услуге", "logs": "Записи", @@ -1205,8 +1203,8 @@ "batchGroup": "Пакетна обрада", "homeSubtitle": "Преглед контролне табле", "providersSubtitle": "Управљање AI провајдерима", - "modelCatalog": "Каталог модела", - "modelCatalogSubtitle": "Прегледајте моделе свих провајдера", + "modelCatalog": "Модели и комбинације", + "modelCatalogSubtitle": "Прегледајте моделе и комбинације код различитих пружалаца услуга", "quotaTrackerSubtitle": "Праћење ограничења коришћења", "providerQuotaSubtitle": "Праћење ограничења коришћења провајдера", "runtimeSubtitle": "Отпорност и сесије у реалном времену", diff --git a/src/i18n/messages/sv.json b/src/i18n/messages/sv.json index 78a0bf46c9d2..50b3c25faf56 100644 --- a/src/i18n/messages/sv.json +++ b/src/i18n/messages/sv.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Dina AI-anslutningsadresser", "apiManager": "API-hanterare", "apiManagerSubtitle": "Hantera API-nycklar och åtkomst", - "modelCatalog": "Modeller & kombinationer", - "modelCatalogSubtitle": "Bläddra bland modeller och kombinationer från olika leverantörer", "embeddedServices": "Inbäddade Tjänster", "embeddedServicesSubtitle": "Hantera lokala proxytjänster", "logs": "Loggar", @@ -1205,8 +1203,8 @@ "batchGroup": "Batchbearbetning", "homeSubtitle": "Översikt över instrumentpanelen", "providersSubtitle": "Hantera AI-leverantörer", - "modelCatalog": "Modellkatalog", - "modelCatalogSubtitle": "Bläddra bland modeller från alla leverantörer", + "modelCatalog": "Modeller & kombinationer", + "modelCatalogSubtitle": "Bläddra bland modeller och kombinationer från olika leverantörer", "quotaTrackerSubtitle": "Spåra användningsgränser", "providerQuotaSubtitle": "Spåra leverantörernas användningsgränser", "runtimeSubtitle": "Feltolerans och sessioner i realtid", diff --git a/src/i18n/messages/sw.json b/src/i18n/messages/sw.json index e7da3ad23489..03928977c8bb 100644 --- a/src/i18n/messages/sw.json +++ b/src/i18n/messages/sw.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL zako za muunganisho wa AI", "apiManager": "Funguo za API", "apiManagerSubtitle": "Dhibiti funguo za API na ufikiaji", - "modelCatalog": "Miundo na Michanganyiko", - "modelCatalogSubtitle": "Vinjari miundo na michanganyiko katika watoa huduma wote", "embeddedServices": "Huduma Zilizounganishwa", "embeddedServicesSubtitle": "Dhibiti huduma za wakala wa ndani", "logs": "Kumbukumbu za Matukio", @@ -1205,8 +1203,8 @@ "batchGroup": "Kundi", "homeSubtitle": "Muhtasari wa dashibodi", "providersSubtitle": "Dhibiti watoa huduma wa AI", - "modelCatalog": "Katalogi ya miundo", - "modelCatalogSubtitle": "Vinjari miundo kutoka kwa watoa huduma wote", + "modelCatalog": "Miundo na Michanganyiko", + "modelCatalogSubtitle": "Vinjari miundo na michanganyiko katika watoa huduma wote", "quotaTrackerSubtitle": "Fuatilia vikomo vya matumizi", "providerQuotaSubtitle": "Fuatilia vikomo vya matumizi vya watoa huduma", "runtimeSubtitle": "Ustahimilivu na vipindi vya wakati halisi", diff --git a/src/i18n/messages/ta.json b/src/i18n/messages/ta.json index 022dcdc3a918..18488a2c7d11 100644 --- a/src/i18n/messages/ta.json +++ b/src/i18n/messages/ta.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "உங்கள் AI இணைப்பு URLகள்", "apiManager": "API விசைகள்", "apiManagerSubtitle": "API விசைகள் மற்றும் அணுகலை நிர்வகிக்கவும்", - "modelCatalog": "மாடல்கள் & காம்போக்கள்", - "modelCatalogSubtitle": "பல்வேறு வழங்குநர்களின் மாடல்கள் மற்றும் காம்போக்களை உலாவவும்", "embeddedServices": "உட்பொதிக்கப்பட்ட சேவைகள்", "embeddedServicesSubtitle": "உள்ளூர் proxy சேவைகளை நிர்வகிக்கவும்", "logs": "பதிவுகள்", @@ -1205,8 +1203,8 @@ "batchGroup": "தொகுதி", "homeSubtitle": "டாஷ்போர்டு மேலோட்டம்", "providersSubtitle": "AI வழங்குநர்களை நிர்வகிக்கவும்", - "modelCatalog": "மாடல் பட்டியல்", - "modelCatalogSubtitle": "வழங்குநர்கள் முழுவதும் மாடல்களை உலாவுக", + "modelCatalog": "மாடல்கள் & காம்போக்கள்", + "modelCatalogSubtitle": "பல்வேறு வழங்குநர்களின் மாடல்கள் மற்றும் காம்போக்களை உலாவவும்", "quotaTrackerSubtitle": "பயன்பாட்டு வரம்புகளைக் கண்காணிக்கவும்", "providerQuotaSubtitle": "வழங்குநரின் பயன்பாட்டு வரம்புகளைக் கண்காணிக்கவும்", "runtimeSubtitle": "நிகழ்நேர மீட்சித்திறன் மற்றும் அமர்வுகள்", diff --git a/src/i18n/messages/te.json b/src/i18n/messages/te.json index a20a8838dd2e..3107be4a403b 100644 --- a/src/i18n/messages/te.json +++ b/src/i18n/messages/te.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "మీ AI కనెక్షన్ URLలు", "apiManager": "API కీలు", "apiManagerSubtitle": "API కీలు మరియు యాక్సెస్‌ని నిర్వహించండి", - "modelCatalog": "మోడల్స్ & కాంబోలు", - "modelCatalogSubtitle": "వివిధ ప్రొవైడర్ల అంతటా మోడల్స్ మరియు కాంబోలను బ్రౌజ్ చేయండి", "embeddedServices": "ఎంబెడ్ సేవలు", "embeddedServicesSubtitle": "స్థానిక ప్రాక్సీ సేవలను నిర్వహించండి", "logs": "లాగ్లు", @@ -1205,8 +1203,8 @@ "batchGroup": "బ్యాచ్", "homeSubtitle": "డ్యాష్బోర్డ్ అవలోకనం", "providersSubtitle": "AI ప్రొవైడర్లను నిర్వహించండి", - "modelCatalog": "మోడల్ కేటలాగ్", - "modelCatalogSubtitle": "ప్రొవైడర్లన్నింటిలో మోడల్‌లను బ్రౌజ్ చేయండి", + "modelCatalog": "మోడల్స్ & కాంబోలు", + "modelCatalogSubtitle": "వివిధ ప్రొవైడర్ల అంతటా మోడల్స్ మరియు కాంబోలను బ్రౌజ్ చేయండి", "quotaTrackerSubtitle": "వినియోగ పరిమితులను ట్రాక్ చేయండి", "providerQuotaSubtitle": "ప్రొవైడర్ వినియోగ పరిమితులను ట్రాక్ చేయండి", "runtimeSubtitle": "రియల్టైమ్ రెసిలియన్స్ & సెషన్లు", diff --git a/src/i18n/messages/th.json b/src/i18n/messages/th.json index fec79e40333b..fa4c128d0f5c 100644 --- a/src/i18n/messages/th.json +++ b/src/i18n/messages/th.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL การเชื่อมต่อ AI ของคุณ", "apiManager": "ผู้จัดการ API", "apiManagerSubtitle": "จัดการคีย์ API และการเข้าถึง", - "modelCatalog": "โมเดลและคอมโบ", - "modelCatalogSubtitle": "เรียกดูโมเดลและคอมโบจากผู้ให้บริการต่างๆ", "embeddedServices": "บริการที่ฝังตัว", "embeddedServicesSubtitle": "จัดการบริการพร็อกซีในเครื่อง", "logs": "บันทึก", @@ -1205,8 +1203,8 @@ "batchGroup": "แบตช์", "homeSubtitle": "ภาพรวมแดชบอร์ด", "providersSubtitle": "จัดการผู้ให้บริการ AI", - "modelCatalog": "แคตตาล็อกโมเดล", - "modelCatalogSubtitle": "เรียกดูโมเดลจากผู้ให้บริการทั้งหมด", + "modelCatalog": "โมเดลและคอมโบ", + "modelCatalogSubtitle": "เรียกดูโมเดลและคอมโบจากผู้ให้บริการต่างๆ", "quotaTrackerSubtitle": "ติดตามขีดจำกัดการใช้งาน", "providerQuotaSubtitle": "ติดตามขีดจำกัดการใช้งานของผู้ให้บริการ", "runtimeSubtitle": "ความยืดหยุ่นและเซสชันแบบเรียลไทม์", diff --git a/src/i18n/messages/tr.json b/src/i18n/messages/tr.json index fb6064bf02ec..0807e20618b0 100644 --- a/src/i18n/messages/tr.json +++ b/src/i18n/messages/tr.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AI bağlantı URL'leriniz", "apiManager": "API Yöneticisi", "apiManagerSubtitle": "API anahtarlarını ve erişimi yönetin", - "modelCatalog": "Modeller ve Kombolar", - "modelCatalogSubtitle": "Sağlayıcılar genelinde modellere ve kombolara göz atın", "embeddedServices": "Gömülü Hizmetler", "embeddedServicesSubtitle": "Yerel proxy hizmetlerini yönetin", "logs": "Günlükler", @@ -1205,8 +1203,8 @@ "batchGroup": "Toplu İşlem", "homeSubtitle": "Pano genel görünümü", "providersSubtitle": "Yapay zekâ sağlayıcılarını yönetin", - "modelCatalog": "Model kataloğu", - "modelCatalogSubtitle": "Sağlayıcılar genelinde modellere göz atın", + "modelCatalog": "Modeller ve Kombolar", + "modelCatalogSubtitle": "Sağlayıcılar genelinde modellere ve kombolara göz atın", "quotaTrackerSubtitle": "Kullanım sınırlarını izleyin", "providerQuotaSubtitle": "Sağlayıcı kullanım sınırlarını izleyin", "runtimeSubtitle": "Gerçek zamanlı dayanıklılık ve oturumlar", diff --git a/src/i18n/messages/uk-UA.json b/src/i18n/messages/uk-UA.json index b36a87e99823..ab2554288e7d 100644 --- a/src/i18n/messages/uk-UA.json +++ b/src/i18n/messages/uk-UA.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Ваші URL-адреси підключення AI", "apiManager": "Менеджер API", "apiManagerSubtitle": "Керуйте ключами API та доступом", - "modelCatalog": "Моделі та комбо", - "modelCatalogSubtitle": "Переглядайте моделі та комбо від різних провайдерів", "embeddedServices": "Вбудовані сервіси", "embeddedServicesSubtitle": "Керування локальними проксі-сервісами", "logs": "Журнали", @@ -1205,8 +1203,8 @@ "batchGroup": "Пакетна обробка", "homeSubtitle": "Огляд панелі", "providersSubtitle": "Керування AI-провайдерами", - "modelCatalog": "Каталог моделей", - "modelCatalogSubtitle": "Переглядайте моделі всіх провайдерів", + "modelCatalog": "Моделі та комбо", + "modelCatalogSubtitle": "Переглядайте моделі та комбо від різних провайдерів", "quotaTrackerSubtitle": "Відстеження лімітів", "providerQuotaSubtitle": "Відстеження лімітів провайдерів", "runtimeSubtitle": "Стійкість і сесії в реальному часі", diff --git a/src/i18n/messages/ur.json b/src/i18n/messages/ur.json index d7b0b1404c95..384471e61b53 100644 --- a/src/i18n/messages/ur.json +++ b/src/i18n/messages/ur.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "آپ کے AI کنکشن کے URLs", "apiManager": "API کلیدیں", "apiManagerSubtitle": "API کیز اور رسائی کا نظم کریں۔", - "modelCatalog": "ماڈلز اور کمبوز", - "modelCatalogSubtitle": "مختلف فراہم کنندگان میں ماڈلز اور کمبوز براؤز کریں", "embeddedServices": "ایمبیڈڈ سروسز", "embeddedServicesSubtitle": "مقامی پراکسی سروسز کا انتظام کریں", "logs": "لاگز", @@ -1205,8 +1203,8 @@ "batchGroup": "بیچ", "homeSubtitle": "ڈیش بورڈ کا جائزہ", "providersSubtitle": "AI فراہم کنندگان کا نظم کریں", - "modelCatalog": "ماڈل کیٹلاگ", - "modelCatalogSubtitle": "فراہم کنندگان میں ماڈلز براؤز کریں", + "modelCatalog": "ماڈلز اور کمبوز", + "modelCatalogSubtitle": "مختلف فراہم کنندگان میں ماڈلز اور کمبوز براؤز کریں", "quotaTrackerSubtitle": "استعمال کی حدود ٹریک کریں", "providerQuotaSubtitle": "فراہم کنندہ کے استعمال کی حدود ٹریک کریں", "runtimeSubtitle": "ریئل ٹائم لچک اور سیشنز", diff --git a/src/i18n/messages/uz.json b/src/i18n/messages/uz.json index ed39d78ef634..862b64d6e08d 100644 --- a/src/i18n/messages/uz.json +++ b/src/i18n/messages/uz.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "AI ulanish URL manzillaringiz", "apiManager": "API kalitlari", "apiManagerSubtitle": "API kalitlari va kirishni boshqarish", - "modelCatalog": "Modellar va kombinatsiyalar", - "modelCatalogSubtitle": "Provayderlar boʻylab modellar va kombinatsiyalarni koʻrib chiqing", "embeddedServices": "Ichki xizmatlar", "embeddedServicesSubtitle": "Ixtiyoriy mahalliy xizmatlar", "logs": "Jurnallar", @@ -1205,8 +1203,8 @@ "batchGroup": "Paketli ishlov berish", "homeSubtitle": "Boshqaruv panelining umumiy ko‘rinishi", "providersSubtitle": "AI provayderlarini boshqarish", - "modelCatalog": "Modellar katalogi", - "modelCatalogSubtitle": "Provayderlar bo'ylab modellarni ko'rib chiqing", + "modelCatalog": "Modellar va kombinatsiyalar", + "modelCatalogSubtitle": "Provayderlar boʻylab modellar va kombinatsiyalarni koʻrib chiqing", "quotaTrackerSubtitle": "Foydalanish limitlarini kuzatish", "providerQuotaSubtitle": "Provayderdan foydalanish limitlarini kuzatish", "runtimeSubtitle": "Real vaqt rejimidagi barqarorlik va seanslar", diff --git a/src/i18n/messages/vi.json b/src/i18n/messages/vi.json index d25a46019c0b..5a5d6480e243 100644 --- a/src/i18n/messages/vi.json +++ b/src/i18n/messages/vi.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "URL kết nối AI của bạn", "apiManager": "Khóa API", "apiManagerSubtitle": "Quản lý khóa API và quyền truy cập", - "modelCatalog": "Mô hình & Combo", - "modelCatalogSubtitle": "Duyệt các mô hình và combo trên các nhà cung cấp", "embeddedServices": "Dịch vụ nhúng", "embeddedServicesSubtitle": "Quản lý các dịch vụ proxy cục bộ", "logs": "Nhật ký", @@ -1205,8 +1203,8 @@ "batchGroup": "Xử lý theo lô", "homeSubtitle": "Tổng quan bảng điều khiển", "providersSubtitle": "Quản lý nhà cung cấp AI", - "modelCatalog": "Danh mục mô hình", - "modelCatalogSubtitle": "Duyệt mô hình trên các nhà cung cấp", + "modelCatalog": "Mô hình & Combo", + "modelCatalogSubtitle": "Duyệt các mô hình và combo trên các nhà cung cấp", "quotaTrackerSubtitle": "Theo dõi giới hạn mức sử dụng", "providerQuotaSubtitle": "Theo dõi giới hạn mức sử dụng của nhà cung cấp", "runtimeSubtitle": "Khả năng phục hồi thời gian thực & phiên làm việc", diff --git a/src/i18n/messages/yo.json b/src/i18n/messages/yo.json index f846739ad26f..72406ef191d3 100644 --- a/src/i18n/messages/yo.json +++ b/src/i18n/messages/yo.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "Àwọn URL àsopọ̀ AI rẹ", "apiManager": "Àwọn Kọ́kọ́rọ́ API", "apiManagerSubtitle": "Ṣàkóso àwọn kọ́kọ́rọ́ API àti ìráàyèsí", - "modelCatalog": "Àwọn Mọ́dẹ́lì & Àkójọpọ̀", - "modelCatalogSubtitle": "Ṣàwárí àwọn mọ́dẹ́lì àti àkójọpọ̀ kọjá àwọn olùpèsè", "embeddedServices": "Àwọn Iṣẹ́ Tí a Fi Sínú", "embeddedServicesSubtitle": "Àwọn iṣẹ́ abẹ́lé àṣàyàn", "logs": "Àwọn Àkọsílẹ̀", @@ -1205,8 +1203,8 @@ "batchGroup": "Ìdìpọ̀", "homeSubtitle": "Àkópò Dashboard", "providersSubtitle": "Ṣàkóso àwọn olùpèsè AI", - "modelCatalog": "Àkójọ àwọn àwòṣe", - "modelCatalogSubtitle": "Wo àwọn àwòṣe láti ọ̀dọ̀ gbogbo olùpèsè", + "modelCatalog": "Àwọn Mọ́dẹ́lì & Àkójọpọ̀", + "modelCatalogSubtitle": "Ṣàwárí àwọn mọ́dẹ́lì àti àkójọpọ̀ kọjá àwọn olùpèsè", "quotaTrackerSubtitle": "Tọpinpin àwọn òpin lílò", "providerQuotaSubtitle": "Tọpinpin àwọn òpin lílò olùpèsè", "runtimeSubtitle": "Ìfaradà àti àwọn sáà ní àkókò gidi", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index 509de959ca81..45bff2bfacdc 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "您的 AI 连接 URL", "apiManager": "API 管理", "apiManagerSubtitle": "管理 API 密钥和访问", - "modelCatalog": "模型与组合", - "modelCatalogSubtitle": "浏览各提供商的模型和组合", "embeddedServices": "内嵌服务", "embeddedServicesSubtitle": "管理本地代理服务", "logs": "日志", @@ -1205,8 +1203,8 @@ "batchGroup": "批处理", "homeSubtitle": "仪表盘概览", "providersSubtitle": "管理 AI 提供者", - "modelCatalog": "模型目录", - "modelCatalogSubtitle": "浏览各提供者的模型", + "modelCatalog": "模型与组合", + "modelCatalogSubtitle": "浏览各提供者的模型和组合", "quotaTrackerSubtitle": "跟踪使用限制", "providerQuotaSubtitle": "跟踪提供者使用限制", "runtimeSubtitle": "实时弹性与会话", @@ -3221,7 +3219,7 @@ }, "modelCatalog": { "title": "模型与组合", - "subtitle": "浏览并对各提供商的模型及组合路由流水线进行健康检测。", + "subtitle": "浏览并对各提供者的模型及组合路由流水线进行健康检测。", "refresh": "刷新", "modelsTab": "模型", "combosTab": "组合", @@ -3237,15 +3235,15 @@ "noCombosMatch": "没有符合这些筛选条件的组合。", "clearFilters": "清除筛选条件", "searchModels": "搜索模型", - "searchModelsPlaceholder": "按模型、提供商或能力搜索", + "searchModelsPlaceholder": "按模型、提供者或能力搜索", "searchCombos": "搜索组合", "searchCombosPlaceholder": "按组合名称、模型或描述搜索", "modelCountSingle": "模型", "modelCountPlural": "模型", "comboCountSingle": "组合", "comboCountPlural": "组合", - "provider": "提供商", - "allProviders": "所有提供商", + "provider": "提供者", + "allProviders": "所有提供者", "type": "类型", "allTypes": "所有类型", "subtype": "子类型", @@ -3256,7 +3254,7 @@ "allPricing": "所有定价", "freeOnly": "仅免费", "nonFree": "标准 / 付费", - "providerHealth": "提供商健康状态", + "providerHealth": "提供者健康状态", "allHealthStates": "所有健康状态", "healthy": "健康", "degraded": "降级", @@ -3293,7 +3291,7 @@ "hoursAgo": "{count} 小时前", "tableRegion": "模型目录表格", "combosTableRegion": "组合目录表格", - "tableCaption": "所有提供商的模型目录", + "tableCaption": "所有提供者的模型目录", "combosTableCaption": "包含健康测试结果的组合目录", "selectAllModels": "选择本页所有模型", "selectAllCombos": "选择本页所有组合", @@ -3329,8 +3327,8 @@ "testsCancelledModels": "测试已取消(已测试 {completed}/{total} 个模型)", "testsCancelledCombos": "测试已取消(已测试 {completed}/{total} 个组合)", "bulkConfirmTitle": "开始批量测试?", - "bulkConfirmModels": "这将向您的提供商发送 {count} 个模型测试,并可能消耗配额。是否继续?", - "bulkConfirmCombos": "这将运行 {count} 个组合测试,并可能消耗提供商配额。是否继续?", + "bulkConfirmModels": "这将向您的提供者发送 {count} 个模型测试,并可能消耗配额。是否继续?", + "bulkConfirmCombos": "这将运行 {count} 个组合测试,并可能消耗提供者配额。是否继续?", "bulkConfirmStart": "开始测试", "errorDetail": "错误详情:{detail}", "httpError": "请求失败,HTTP {status}", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 28f04885da4f..16fac7afbaed 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -1030,8 +1030,6 @@ "endpointsSubtitle": "您的 AI 連線 URL", "apiManager": "API 管理", "apiManagerSubtitle": "管理 API 金鑰和訪問", - "modelCatalog": "模型與組合", - "modelCatalogSubtitle": "瀏覽各提供者的模型與組合", "embeddedServices": "內嵌服務", "embeddedServicesSubtitle": "管理本地代理服務", "logs": "日誌", @@ -1205,8 +1203,8 @@ "batchGroup": "批處理", "homeSubtitle": "儀表盤概覽", "providersSubtitle": "管理 AI 提供者", - "modelCatalog": "模型目錄", - "modelCatalogSubtitle": "瀏覽各提供者的模型", + "modelCatalog": "模型與組合", + "modelCatalogSubtitle": "瀏覽各提供者的模型與組合", "quotaTrackerSubtitle": "跟蹤使用限制", "providerQuotaSubtitle": "跟蹤提供者使用限制", "runtimeSubtitle": "即時彈性與會話",