Commit 06194801 by CaIon

feat: limit dashboard flow nodes

parent d58029c6
import assert from 'node:assert/strict' import assert from 'node:assert/strict'
import { describe, test } from 'node:test' import { describe, test } from 'node:test'
import type { FlowQuotaDataItem } from '../types' import type { FlowQuotaDataItem } from '../types'
import { import {
buildDashboardFlowData, buildDashboardFlowData,
...@@ -52,6 +53,42 @@ const rows: FlowQuotaDataItem[] = [ ...@@ -52,6 +53,42 @@ const rows: FlowQuotaDataItem[] = [
}, },
] ]
const topLimitRows: FlowQuotaDataItem[] = [
{
user_id: 1,
username: 'alpha',
use_group: 'vip',
channel_id: 201,
channel_name: 'channel-a',
model_name: 'model-a',
quota: 100,
token_used: 1_000,
count: 1,
},
{
user_id: 2,
username: 'beta',
use_group: 'default',
channel_id: 202,
channel_name: 'channel-b',
model_name: 'model-b',
quota: 80,
token_used: 10,
count: 20,
},
{
user_id: 3,
username: 'gamma',
use_group: 'free',
channel_id: 203,
channel_name: 'channel-c',
model_name: 'model-c',
quota: 10,
token_used: 2_000,
count: 5,
},
]
describe('dashboard flow data', () => { describe('dashboard flow data', () => {
test('builds normal user token-group-model flow', () => { test('builds normal user token-group-model flow', () => {
const result = buildDashboardFlowData(rows.slice(0, 2), 'quota', { const result = buildDashboardFlowData(rows.slice(0, 2), 'quota', {
...@@ -183,6 +220,113 @@ describe('dashboard flow data', () => { ...@@ -183,6 +220,113 @@ describe('dashboard flow data', () => {
assert.notEqual(options.users[0].color, options.users[1].color) assert.notEqual(options.users[0].color, options.users[1].color)
}) })
test('aggregates overflow nodes into per-column Other buckets', () => {
const result = buildDashboardFlowData(topLimitRows, 'quota', {
role: 'admin',
topNodeLimit: 2,
overflowMode: 'aggregate',
otherNodeLabel: (kind) => `Other ${kind}`,
})
const nodeIds = result.flow.nodes.map((node) => node.id)
const otherUser = result.flow.nodes.find(
(node) => node.id === 'user:__other__'
)
const otherFirstStepLink = result.flow.links.find(
(link) =>
link.source === 'user:__other__' && link.target === 'group:__other__'
)
const firstStepTotal = result.flow.links
.filter((link) => link.source.startsWith('user:'))
.reduce((sum, link) => sum + link.value, 0)
assert.equal(result.summary.quota, 190)
assert.equal(firstStepTotal, 190)
assert.equal(otherUser?.label, 'Other user')
assert.equal(otherFirstStepLink?.value, 10)
assert.equal(nodeIds.includes('user:3'), false)
assert.equal(nodeIds.includes('group:free'), false)
assert.equal(nodeIds.includes('model:model-c'), false)
assert.equal(nodeIds.includes('channel:203'), false)
assert.equal(nodeIds.includes('user:__other__'), true)
assert.equal(nodeIds.includes('group:__other__'), true)
assert.equal(nodeIds.includes('model:__other__'), true)
assert.equal(nodeIds.includes('channel:__other__'), true)
})
test('hides overflow paths when overflow mode is hide', () => {
const result = buildDashboardFlowData(topLimitRows, 'quota', {
role: 'admin',
topNodeLimit: 2,
overflowMode: 'hide',
otherNodeLabel: (kind) => `Other ${kind}`,
})
const nodeIds = result.flow.nodes.map((node) => node.id)
const firstStepTotal = result.flow.links
.filter((link) => link.source.startsWith('user:'))
.reduce((sum, link) => sum + link.value, 0)
assert.equal(result.summary.quota, 190)
assert.equal(firstStepTotal, 180)
assert.equal(nodeIds.includes('user:3'), false)
assert.equal(nodeIds.includes('user:__other__'), false)
assert.equal(nodeIds.includes('model:__other__'), false)
})
test('ranks top nodes using the selected flow metric', () => {
const byQuota = buildDashboardFlowData(topLimitRows, 'quota', {
role: 'admin',
topNodeLimit: 1,
overflowMode: 'aggregate',
})
const byRequests = buildDashboardFlowData(topLimitRows, 'requests', {
role: 'admin',
topNodeLimit: 1,
overflowMode: 'aggregate',
})
const byTokens = buildDashboardFlowData(topLimitRows, 'tokens', {
role: 'admin',
topNodeLimit: 1,
overflowMode: 'aggregate',
})
assert.equal(
byQuota.flow.nodes.some((node) => node.id === 'user:1'),
true
)
assert.equal(
byRequests.flow.nodes.some((node) => node.id === 'user:2'),
true
)
assert.equal(
byTokens.flow.nodes.some((node) => node.id === 'user:3'),
true
)
})
test('applies top limits only to visible stages', () => {
const result = buildDashboardFlowData(topLimitRows, 'quota', {
role: 'admin',
visibleStages: ['user', 'model'],
topNodeLimit: 1,
overflowMode: 'aggregate',
})
const nodeIds = result.flow.nodes.map((node) => node.id)
assert.equal(nodeIds.includes('user:1'), true)
assert.equal(nodeIds.includes('user:__other__'), true)
assert.equal(nodeIds.includes('model:model-a'), true)
assert.equal(nodeIds.includes('model:__other__'), true)
assert.equal(nodeIds.includes('group:__other__'), false)
assert.equal(nodeIds.includes('channel:__other__'), false)
assert.deepEqual(
result.flow.links.map((link) => [link.source, link.target, link.value]),
[
['user:__other__', 'model:__other__', 90],
['user:1', 'model:model-a', 100],
]
)
})
test('builds Sankey spec with quota token request tooltips', () => { test('builds Sankey spec with quota token request tooltips', () => {
const result = buildDashboardFlowData(rows.slice(0, 1), 'quota', { const result = buildDashboardFlowData(rows.slice(0, 1), 'quota', {
role: 'root', role: 'root',
......
...@@ -24,11 +24,13 @@ import type { ...@@ -24,11 +24,13 @@ import type {
FlowFilterOptions, FlowFilterOptions,
FlowMetric, FlowMetric,
FlowNodeKind, FlowNodeKind,
FlowOverflowMode,
FlowQuotaDataItem, FlowQuotaDataItem,
FlowRole, FlowRole,
FlowSummary, FlowSummary,
ProcessedFlowData, ProcessedFlowData,
} from '@/features/dashboard/types' } from '@/features/dashboard/types'
import { getDashboardChartColors } from './charts' import { getDashboardChartColors } from './charts'
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
...@@ -53,14 +55,32 @@ type FlowPathNode = { ...@@ -53,14 +55,32 @@ type FlowPathNode = {
kind: FlowNodeKind kind: FlowNodeKind
} }
type PreparedFlowPath = {
path: FlowPathNode[]
metrics: FlowMetrics
}
type FlowNodeRank = {
node: FlowPathNode
value: number
}
type FlowPathContext = { type FlowPathContext = {
deletedTokenLabel?: (tokenId: number) => string deletedTokenLabel?: (tokenId: number) => string
} }
type FlowGraphOptions = {
topNodeLimit?: number
overflowMode?: FlowOverflowMode
otherNodeLabel?: (kind: FlowNodeKind) => string
}
const EMPTY_FLOW_PATH_CONTEXT: FlowPathContext = {} const EMPTY_FLOW_PATH_CONTEXT: FlowPathContext = {}
const DEFAULT_FLOW_ROLE: FlowRole = 'user' const DEFAULT_FLOW_ROLE: FlowRole = 'user'
const DEFAULT_FLOW_OVERFLOW_MODE: FlowOverflowMode = 'aggregate'
const DEFAULT_FLOW_SANKEY_LABELS: FlowSankeyLabels = { const DEFAULT_FLOW_SANKEY_LABELS: FlowSankeyLabels = {
quota: 'Quota', quota: 'Quota',
tokens: 'Tokens', tokens: 'Tokens',
...@@ -70,6 +90,24 @@ const DEFAULT_FLOW_SANKEY_LABELS: FlowSankeyLabels = { ...@@ -70,6 +90,24 @@ const DEFAULT_FLOW_SANKEY_LABELS: FlowSankeyLabels = {
const DEFAULT_FLOW_CHART_COLOR = '#1664FF' const DEFAULT_FLOW_CHART_COLOR = '#1664FF'
const OTHER_FLOW_NODE_IDS: Record<FlowNodeKind, string> = {
user: 'user:__other__',
node: 'node:__other__',
token: 'token:__other__',
group: 'group:__other__',
model: 'model:__other__',
channel: 'channel:__other__',
}
const DEFAULT_OTHER_FLOW_NODE_LABELS: Record<FlowNodeKind, string> = {
user: 'Other users',
node: 'Other nodes',
token: 'Other tokens',
group: 'Other groups',
model: 'Other models',
channel: 'Other channels',
}
function numberValue(value: unknown): number { function numberValue(value: unknown): number {
const n = Number(value) const n = Number(value)
return Number.isFinite(n) ? n : 0 return Number.isFinite(n) ? n : 0
...@@ -107,13 +145,11 @@ function nodeNameNode(row: FlowQuotaDataItem): FlowPathNode { ...@@ -107,13 +145,11 @@ function nodeNameNode(row: FlowQuotaDataItem): FlowPathNode {
} }
} }
function tokenNode( function tokenNode(row: FlowQuotaDataItem, ctx: FlowPathContext): FlowPathNode {
row: FlowQuotaDataItem,
ctx: FlowPathContext
): FlowPathNode {
const tokenID = numberValue(row.token_id) const tokenID = numberValue(row.token_id)
return { return {
id: tokenID > 0 ? `token:${tokenID}` : `token:${row.token_name || 'unknown'}`, id:
tokenID > 0 ? `token:${tokenID}` : `token:${row.token_name || 'unknown'}`,
label: row.token_name || deletedTokenLabel(tokenID, ctx), label: row.token_name || deletedTokenLabel(tokenID, ctx),
kind: 'token', kind: 'token',
} }
...@@ -192,15 +228,12 @@ function resolveVisibleStages( ...@@ -192,15 +228,12 @@ function resolveVisibleStages(
return filtered.length >= MIN_FLOW_STAGES ? filtered : stages return filtered.length >= MIN_FLOW_STAGES ? filtered : stages
} }
function flowPath( function flowPathForStages(
row: FlowQuotaDataItem, row: FlowQuotaDataItem,
role: FlowRole, stages: FlowNodeKind[],
visibleStages?: FlowNodeKind[],
ctx: FlowPathContext = EMPTY_FLOW_PATH_CONTEXT ctx: FlowPathContext = EMPTY_FLOW_PATH_CONTEXT
): FlowPathNode[] { ): FlowPathNode[] {
return resolveVisibleStages(role, visibleStages).map((stage) => return stages.map((stage) => NODE_BUILDERS[stage](row, ctx))
NODE_BUILDERS[stage](row, ctx)
)
} }
function colorAt(index: number, palette?: readonly string[]): string { function colorAt(index: number, palette?: readonly string[]): string {
...@@ -252,18 +285,6 @@ function stableColorMap( ...@@ -252,18 +285,6 @@ function stableColorMap(
return map return map
} }
function rootColorKeys(
rows: FlowQuotaDataItem[],
role: FlowRole,
visibleStages?: FlowNodeKind[]
): string[] {
return Array.from(
new Set(
rows.map((row) => flowPath(row, role, visibleStages)[0]?.id ?? 'unknown')
)
).sort((a, b) => a.localeCompare(b))
}
function filterRows( function filterRows(
rows: FlowQuotaDataItem[], rows: FlowQuotaDataItem[],
options: FlowBuildOptions = {} options: FlowBuildOptions = {}
...@@ -392,26 +413,137 @@ function buildSummary(rows: FlowQuotaDataItem[]): FlowSummary { ...@@ -392,26 +413,137 @@ function buildSummary(rows: FlowQuotaDataItem[]): FlowSummary {
) )
} }
function normalizeTopNodeLimit(limit?: number): number | undefined {
if (limit === undefined) return undefined
const parsed = Math.floor(limit)
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined
}
function otherFlowNode(
kind: FlowNodeKind,
labeler?: (kind: FlowNodeKind) => string
): FlowPathNode {
return {
id: OTHER_FLOW_NODE_IDS[kind],
label: labeler?.(kind) ?? DEFAULT_OTHER_FLOW_NODE_LABELS[kind],
kind,
}
}
function buildTopNodeSets(
rows: FlowQuotaDataItem[],
metric: FlowMetric,
stages: FlowNodeKind[],
limit: number | undefined,
ctx: FlowPathContext
): Map<FlowNodeKind, Set<string>> | undefined {
if (!limit) return undefined
const totals = new Map<FlowNodeKind, Map<string, FlowNodeRank>>()
for (const stage of stages) {
totals.set(stage, new Map())
}
for (const row of rows) {
const metrics = rowMetrics(row)
const value = metricValue(metrics, metric)
const path = flowPathForStages(row, stages, ctx)
for (const node of path) {
const stageTotals = totals.get(node.kind)
if (!stageTotals) continue
const current = stageTotals.get(node.id) ?? { node, value: 0 }
current.value += value
stageTotals.set(node.id, current)
}
}
const topSets = new Map<FlowNodeKind, Set<string>>()
for (const [kind, stageTotals] of totals) {
const topIds = Array.from(stageTotals.values())
.sort(
(a, b) =>
b.value - a.value ||
a.node.label.localeCompare(b.node.label) ||
a.node.id.localeCompare(b.node.id)
)
.slice(0, limit)
.map((rank) => rank.node.id)
topSets.set(kind, new Set(topIds))
}
return topSets
}
function isTopFlowNode(
node: FlowPathNode,
topNodeSets?: Map<FlowNodeKind, Set<string>>
): boolean {
const topNodes = topNodeSets?.get(node.kind)
return !topNodes || topNodes.has(node.id)
}
function applyTopNodeLimit(
path: FlowPathNode[],
topNodeSets: Map<FlowNodeKind, Set<string>> | undefined,
mode: FlowOverflowMode,
labeler?: (kind: FlowNodeKind) => string
): FlowPathNode[] | undefined {
if (!topNodeSets) return path
const containsOverflowNode = path.some(
(node) => !isTopFlowNode(node, topNodeSets)
)
if (!containsOverflowNode) return path
if (mode === 'hide') return undefined
return path.map((node) =>
isTopFlowNode(node, topNodeSets) ? node : otherFlowNode(node.kind, labeler)
)
}
function buildFlowGraph( function buildFlowGraph(
rows: FlowQuotaDataItem[], rows: FlowQuotaDataItem[],
metric: FlowMetric, metric: FlowMetric,
role: FlowRole, role: FlowRole,
palette?: readonly string[], palette?: readonly string[],
visibleStages?: FlowNodeKind[], visibleStages?: FlowNodeKind[],
ctx: FlowPathContext = EMPTY_FLOW_PATH_CONTEXT ctx: FlowPathContext = EMPTY_FLOW_PATH_CONTEXT,
options: FlowGraphOptions = {}
): DashboardFlowGraph { ): DashboardFlowGraph {
const stages = resolveVisibleStages(role, visibleStages)
const topNodeSets = buildTopNodeSets(
rows,
metric,
stages,
normalizeTopNodeLimit(options.topNodeLimit),
ctx
)
const overflowMode = options.overflowMode ?? DEFAULT_FLOW_OVERFLOW_MODE
const preparedPaths: PreparedFlowPath[] = []
for (const row of rows) {
const path = applyTopNodeLimit(
flowPathForStages(row, stages, ctx),
topNodeSets,
overflowMode,
options.otherNodeLabel
)
if (!path) continue
preparedPaths.push({ path, metrics: rowMetrics(row) })
}
const nodes = new Map<string, DashboardFlowNode>() const nodes = new Map<string, DashboardFlowNode>()
const links = new Map<string, DashboardFlowLink>() const links = new Map<string, DashboardFlowLink>()
const colors = stableColorMap( const colors = stableColorMap(
rootColorKeys(rows, role, visibleStages), preparedPaths
.map((prepared) => prepared.path[0]?.id)
.filter((id): id is string => Boolean(id))
.sort((a, b) => a.localeCompare(b)),
palette palette
) )
for (const row of rows) { for (const prepared of preparedPaths) {
const path = flowPath(row, role, visibleStages, ctx) const { path, metrics } = prepared
const root = path[0] const root = path[0]
if (!root) continue if (!root) continue
const metrics = rowMetrics(row)
const color = colors.get(root.id) ?? colorAt(0, palette) const color = colors.get(root.id) ?? colorAt(0, palette)
for (const node of path) { for (const node of path) {
...@@ -430,8 +562,8 @@ function buildFlowGraph( ...@@ -430,8 +562,8 @@ function buildFlowGraph(
a.source.localeCompare(b.source) || a.target.localeCompare(b.target) a.source.localeCompare(b.source) || a.target.localeCompare(b.target)
) )
const firstStepSources = new Set( const firstStepSources = new Set(
rows preparedPaths
.map((row) => flowPath(row, role, visibleStages)[0]?.id) .map((prepared) => prepared.path[0]?.id)
.filter((id): id is string => Boolean(id)) .filter((id): id is string => Boolean(id))
) )
const total = flowLinks const total = flowLinks
...@@ -512,9 +644,21 @@ export function buildDashboardFlowData( ...@@ -512,9 +644,21 @@ export function buildDashboardFlowData(
return { return {
summary: buildSummary(filteredRows), summary: buildSummary(filteredRows),
flow: buildFlowGraph(filteredRows, metric, role, palette, options.visibleStages, { flow: buildFlowGraph(
deletedTokenLabel: options.deletedTokenLabel, filteredRows,
}), metric,
role,
palette,
options.visibleStages,
{
deletedTokenLabel: options.deletedTokenLabel,
},
{
topNodeLimit: options.topNodeLimit,
overflowMode: options.overflowMode,
otherNodeLabel: options.otherNodeLabel,
}
),
filterOptions: buildFlowFilterOptions(rows, metric, palette), filterOptions: buildFlowFilterOptions(rows, metric, palette),
} }
} }
......
...@@ -50,6 +50,8 @@ export interface FlowQuotaDataItem { ...@@ -50,6 +50,8 @@ export interface FlowQuotaDataItem {
export type FlowMetric = 'quota' | 'tokens' | 'requests' export type FlowMetric = 'quota' | 'tokens' | 'requests'
export type FlowOverflowMode = 'aggregate' | 'hide'
export type FlowRole = 'user' | 'admin' | 'root' export type FlowRole = 'user' | 'admin' | 'root'
export type FlowNodeKind = export type FlowNodeKind =
...@@ -65,9 +67,12 @@ export interface FlowBuildOptions { ...@@ -65,9 +67,12 @@ export interface FlowBuildOptions {
selectedUsers?: string[] selectedUsers?: string[]
colorPalette?: readonly string[] colorPalette?: readonly string[]
visibleStages?: FlowNodeKind[] visibleStages?: FlowNodeKind[]
topNodeLimit?: number
overflowMode?: FlowOverflowMode
// Resolves the label for a token whose record no longer exists (deleted). // Resolves the label for a token whose record no longer exists (deleted).
// Lets the caller inject a localized string such as "Deleted (123)". // Lets the caller inject a localized string such as "Deleted (123)".
deletedTokenLabel?: (tokenId: number) => string deletedTokenLabel?: (tokenId: number) => string
otherNodeLabel?: (kind: FlowNodeKind) => string
} }
export interface DashboardFlowNode { export interface DashboardFlowNode {
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "by", "by": "by",
"By category": "By category", "By category": "By category",
"By model author": "By model author", "By model author": "By model author",
"By quota": "By quota",
"By requests": "By requests",
"By tokens": "By tokens",
"Cache": "Cache", "Cache": "Cache",
"Cache create (1h) price": "Cache create (1h) price", "Cache create (1h) price": "Cache create (1h) price",
"Cache create price": "Cache create price", "Cache create price": "Cache create price",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "Choose between system preference, light mode, or dark mode", "Choose between system preference, light mode, or dark mode": "Choose between system preference, light mode, or dark mode",
"Choose channels to sync upstream ratio configurations from": "Choose channels to sync upstream ratio configurations from", "Choose channels to sync upstream ratio configurations from": "Choose channels to sync upstream ratio configurations from",
"Choose Group": "Choose Group", "Choose Group": "Choose Group",
"Choose how flow widths are calculated.": "Choose how flow widths are calculated.",
"Choose how quota values are shown to users": "Choose how quota values are shown to users", "Choose how quota values are shown to users": "Choose how quota values are shown to users",
"Choose how the platform will operate": "Choose how the platform will operate", "Choose how the platform will operate": "Choose how the platform will operate",
"Choose how to filter domains": "Choose how to filter domains", "Choose how to filter domains": "Choose how to filter domains",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "Disk Hits", "Disk Hits": "Disk Hits",
"Disk Threshold (%)": "Disk Threshold (%)", "Disk Threshold (%)": "Disk Threshold (%)",
"Display in Currency": "Display in Currency", "Display in Currency": "Display in Currency",
"Display limit": "Display limit",
"Display Mode": "Display Mode", "Display Mode": "Display Mode",
"Display name": "Display name", "Display name": "Display name",
"Display Name": "Display Name", "Display Name": "Display Name",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "Floating", "Floating": "Floating",
"Flow": "Flow", "Flow": "Flow",
"Flow Filters": "Flow Filters", "Flow Filters": "Flow Filters",
"Flow width metric": "Flow width metric",
"FluentRead extension not detected. Please ensure it is installed and active.": "FluentRead extension not detected. Please ensure it is installed and active.", "FluentRead extension not detected. Please ensure it is installed and active.": "FluentRead extension not detected. Please ensure it is installed and active.",
"Flush interval (minutes)": "Flush interval (minutes)", "Flush interval (minutes)": "Flush interval (minutes)",
"Follow the guided steps to prepare your workspace before the first login.": "Follow the guided steps to prepare your workspace before the first login.", "Follow the guided steps to prepare your workspace before the first login.": "Follow the guided steps to prepare your workspace before the first login.",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "More than 999 days left", "More than 999 days left": "More than 999 days left",
"More...": "More...", "More...": "More...",
"Most-used models in the selected period and category": "Most-used models in the selected period and category", "Most-used models in the selected period and category": "Most-used models in the selected period and category",
"Merge into Other": "Merge into Other",
"Move": "Move", "Move": "Move",
"Move a request header": "Move a request header", "Move a request header": "Move a request header",
"Move affiliate rewards to your main balance": "Move affiliate rewards to your main balance", "Move affiliate rewards to your main balance": "Move affiliate rewards to your main balance",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "org-...", "org-...": "org-...",
"Original Model": "Original Model", "Original Model": "Original Model",
"Other": "Other", "Other": "Other",
"Other channels": "Other channels",
"Other groups": "Other groups",
"Other models": "Other models",
"Other nodes": "Other nodes",
"Other tokens": "Other tokens",
"Other users": "Other users",
"Outage": "Outage", "Outage": "Outage",
"Output": "Output", "Output": "Output",
"Output aspect ratio": "Output aspect ratio", "Output aspect ratio": "Output aspect ratio",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "Output tokens", "Output tokens": "Output tokens",
"Output Tokens": "Output Tokens", "Output Tokens": "Output Tokens",
"Overage limited": "Overage limited", "Overage limited": "Overage limited",
"Overflow items": "Overflow items",
"overall": "overall", "overall": "overall",
"Overnight range": "Overnight range", "Overnight range": "Overnight range",
"override": "override", "override": "override",
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "par", "by": "par",
"By category": "Par catégorie", "By category": "Par catégorie",
"By model author": "Par auteur du modèle", "By model author": "Par auteur du modèle",
"By quota": "Par quota",
"By requests": "Par requêtes",
"By tokens": "Par jetons",
"Cache": "Cache", "Cache": "Cache",
"Cache create (1h) price": "Prix de création du cache (1 h)", "Cache create (1h) price": "Prix de création du cache (1 h)",
"Cache create price": "Prix de création du cache", "Cache create price": "Prix de création du cache",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "Choisissez entre la préférence système, le mode clair ou le mode sombre", "Choose between system preference, light mode, or dark mode": "Choisissez entre la préférence système, le mode clair ou le mode sombre",
"Choose channels to sync upstream ratio configurations from": "Choisissez les canaux à partir desquels synchroniser les configurations de ratio amont", "Choose channels to sync upstream ratio configurations from": "Choisissez les canaux à partir desquels synchroniser les configurations de ratio amont",
"Choose Group": "Choisir un groupe", "Choose Group": "Choisir un groupe",
"Choose how flow widths are calculated.": "Choisissez comment l'épaisseur des flux est calculée.",
"Choose how quota values are shown to users": "Choisissez comment les valeurs de quota sont affichées aux utilisateurs", "Choose how quota values are shown to users": "Choisissez comment les valeurs de quota sont affichées aux utilisateurs",
"Choose how the platform will operate": "Choisissez le mode de fonctionnement de la plateforme", "Choose how the platform will operate": "Choisissez le mode de fonctionnement de la plateforme",
"Choose how to filter domains": "Choisissez comment filtrer les domaines", "Choose how to filter domains": "Choisissez comment filtrer les domaines",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "Hits disque", "Disk Hits": "Hits disque",
"Disk Threshold (%)": "Seuil disque (%)", "Disk Threshold (%)": "Seuil disque (%)",
"Display in Currency": "Afficher en devise", "Display in Currency": "Afficher en devise",
"Display limit": "Limite d'affichage",
"Display Mode": "Mode d'affichage", "Display Mode": "Mode d'affichage",
"Display name": "Nom d'affichage", "Display name": "Nom d'affichage",
"Display Name": "Nom d'affichage", "Display Name": "Nom d'affichage",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "Flottant", "Floating": "Flottant",
"Flow": "Flux", "Flow": "Flux",
"Flow Filters": "Filtres de flux", "Flow Filters": "Filtres de flux",
"Flow width metric": "Indicateur de largeur du flux",
"FluentRead extension not detected. Please ensure it is installed and active.": "Extension FluentRead non détectée. Veuillez vous assurer qu'elle est installée et activée.", "FluentRead extension not detected. Please ensure it is installed and active.": "Extension FluentRead non détectée. Veuillez vous assurer qu'elle est installée et activée.",
"Flush interval (minutes)": "Intervalle d’écriture (minutes)", "Flush interval (minutes)": "Intervalle d’écriture (minutes)",
"Follow the guided steps to prepare your workspace before the first login.": "Suivez les étapes guidées pour préparer votre espace de travail avant la première connexion.", "Follow the guided steps to prepare your workspace before the first login.": "Suivez les étapes guidées pour préparer votre espace de travail avant la première connexion.",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "Plus de 999 jours restants", "More than 999 days left": "Plus de 999 jours restants",
"More...": "Plus...", "More...": "Plus...",
"Most-used models in the selected period and category": "Modèles les plus utilisés dans la période et catégorie choisies", "Most-used models in the selected period and category": "Modèles les plus utilisés dans la période et catégorie choisies",
"Merge into Other": "Fusionner dans Autres",
"Move": "Déplacer", "Move": "Déplacer",
"Move a request header": "Déplacer un en-tête de requête", "Move a request header": "Déplacer un en-tête de requête",
"Move affiliate rewards to your main balance": "Transférer les récompenses d'affiliation vers votre solde principal", "Move affiliate rewards to your main balance": "Transférer les récompenses d'affiliation vers votre solde principal",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "org-...", "org-...": "org-...",
"Original Model": "Modèle Original", "Original Model": "Modèle Original",
"Other": "Autre", "Other": "Autre",
"Other channels": "Autres canaux",
"Other groups": "Autres groupes",
"Other models": "Autres modèles",
"Other nodes": "Autres nœuds",
"Other tokens": "Autres jetons",
"Other users": "Autres utilisateurs",
"Outage": "Interruption", "Outage": "Interruption",
"Output": "Sortie", "Output": "Sortie",
"Output aspect ratio": "Format d'image de sortie", "Output aspect ratio": "Format d'image de sortie",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "Jetons de sortie", "Output tokens": "Jetons de sortie",
"Output Tokens": "Tokens de sortie", "Output Tokens": "Tokens de sortie",
"Overage limited": "Dépassement limité", "Overage limited": "Dépassement limité",
"Overflow items": "Éléments excédentaires",
"overall": "global", "overall": "global",
"Overnight range": "Plage nocturne", "Overnight range": "Plage nocturne",
"override": "remplacer", "override": "remplacer",
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "によって", "by": "によって",
"By category": "カテゴリ別", "By category": "カテゴリ別",
"By model author": "モデル提供者別", "By model author": "モデル提供者別",
"By quota": "クォータ別",
"By requests": "リクエスト数別",
"By tokens": "トークン数別",
"Cache": "キャッシュ", "Cache": "キャッシュ",
"Cache create (1h) price": "キャッシュ作成価格 (1時間)", "Cache create (1h) price": "キャッシュ作成価格 (1時間)",
"Cache create price": "キャッシュ作成価格", "Cache create price": "キャッシュ作成価格",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "システム設定、ライトモード、またはダークモードから選択します", "Choose between system preference, light mode, or dark mode": "システム設定、ライトモード、またはダークモードから選択します",
"Choose channels to sync upstream ratio configurations from": "アップストリームの比率設定を同期するチャネルを選択してください", "Choose channels to sync upstream ratio configurations from": "アップストリームの比率設定を同期するチャネルを選択してください",
"Choose Group": "グループを選択", "Choose Group": "グループを選択",
"Choose how flow widths are calculated.": "フローの線幅をどの指標で計算するかを選択します。",
"Choose how quota values are shown to users": "クォータ値がユーザーにどのように表示されるかを選択してください", "Choose how quota values are shown to users": "クォータ値がユーザーにどのように表示されるかを選択してください",
"Choose how the platform will operate": "プラットフォームの運用方法を選択", "Choose how the platform will operate": "プラットフォームの運用方法を選択",
"Choose how to filter domains": "ドメインをフィルタリングする方法を選択してください", "Choose how to filter domains": "ドメインをフィルタリングする方法を選択してください",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "ディスクヒット", "Disk Hits": "ディスクヒット",
"Disk Threshold (%)": "ディスク閾値 (%)", "Disk Threshold (%)": "ディスク閾値 (%)",
"Display in Currency": "通貨で表示", "Display in Currency": "通貨で表示",
"Display limit": "表示数",
"Display Mode": "表示モード", "Display Mode": "表示モード",
"Display name": "表示名", "Display name": "表示名",
"Display Name": "表示名", "Display Name": "表示名",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "フローティング", "Floating": "フローティング",
"Flow": "フロー", "Flow": "フロー",
"Flow Filters": "フローフィルター", "Flow Filters": "フローフィルター",
"Flow width metric": "線幅の指標",
"FluentRead extension not detected. Please ensure it is installed and active.": "FluentRead 拡張機能が検出されませんでした。インストールされていて有効になっていることを確認してください。", "FluentRead extension not detected. Please ensure it is installed and active.": "FluentRead 拡張機能が検出されませんでした。インストールされていて有効になっていることを確認してください。",
"Flush interval (minutes)": "書き込み間隔(分)", "Flush interval (minutes)": "書き込み間隔(分)",
"Follow the guided steps to prepare your workspace before the first login.": "初回ログイン前に、ガイド付きの手順に従ってワークスペースを準備してください。", "Follow the guided steps to prepare your workspace before the first login.": "初回ログイン前に、ガイド付きの手順に従ってワークスペースを準備してください。",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "999日以上", "More than 999 days left": "999日以上",
"More...": "その他...", "More...": "その他...",
"Most-used models in the selected period and category": "選択した期間とカテゴリで最も使われているモデル", "Most-used models in the selected period and category": "選択した期間とカテゴリで最も使われているモデル",
"Merge into Other": "その他にまとめる",
"Move": "移動", "Move": "移動",
"Move a request header": "リクエストヘッダーを移動", "Move a request header": "リクエストヘッダーを移動",
"Move affiliate rewards to your main balance": "アフィリエイト報酬をメイン残高に移動する", "Move affiliate rewards to your main balance": "アフィリエイト報酬をメイン残高に移動する",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "org-...", "org-...": "org-...",
"Original Model": "オリジナルモデル", "Original Model": "オリジナルモデル",
"Other": "その他", "Other": "その他",
"Other channels": "その他のチャネル",
"Other groups": "その他のグループ",
"Other models": "その他のモデル",
"Other nodes": "その他のノード",
"Other tokens": "その他のトークン",
"Other users": "その他のユーザー",
"Outage": "ダウンタイム", "Outage": "ダウンタイム",
"Output": "出力", "Output": "出力",
"Output aspect ratio": "出力アスペクト比", "Output aspect ratio": "出力アスペクト比",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "出力トークン", "Output tokens": "出力トークン",
"Output Tokens": "出力トークン", "Output Tokens": "出力トークン",
"Overage limited": "超過利用制限中", "Overage limited": "超過利用制限中",
"Overflow items": "超過項目",
"overall": "全体", "overall": "全体",
"Overnight range": "日跨ぎ範囲", "Overnight range": "日跨ぎ範囲",
"override": "上書き", "override": "上書き",
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "от", "by": "от",
"By category": "По категориям", "By category": "По категориям",
"By model author": "По автору модели", "By model author": "По автору модели",
"By quota": "По квоте",
"By requests": "По запросам",
"By tokens": "По токенам",
"Cache": "Кэш", "Cache": "Кэш",
"Cache create (1h) price": "Цена создания кэша (1 ч)", "Cache create (1h) price": "Цена создания кэша (1 ч)",
"Cache create price": "Цена создания кэша", "Cache create price": "Цена создания кэша",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "Выберите между системными настройками, светлым режимом или темным режимом", "Choose between system preference, light mode, or dark mode": "Выберите между системными настройками, светлым режимом или темным режимом",
"Choose channels to sync upstream ratio configurations from": "Выберите каналы для синхронизации конфигураций соотношений из вышестоящих источников", "Choose channels to sync upstream ratio configurations from": "Выберите каналы для синхронизации конфигураций соотношений из вышестоящих источников",
"Choose Group": "Выбрать группу", "Choose Group": "Выбрать группу",
"Choose how flow widths are calculated.": "Выберите, как рассчитывается ширина потоков.",
"Choose how quota values are shown to users": "Выберите, как значения квоты отображаются пользователям", "Choose how quota values are shown to users": "Выберите, как значения квоты отображаются пользователям",
"Choose how the platform will operate": "Выберите режим работы платформы", "Choose how the platform will operate": "Выберите режим работы платформы",
"Choose how to filter domains": "Выберите, как фильтровать домены", "Choose how to filter domains": "Выберите, как фильтровать домены",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "Попаданий диска", "Disk Hits": "Попаданий диска",
"Disk Threshold (%)": "Порог диска (%)", "Disk Threshold (%)": "Порог диска (%)",
"Display in Currency": "Отображать в валюте", "Display in Currency": "Отображать в валюте",
"Display limit": "Лимит отображения",
"Display Mode": "Режим отображения", "Display Mode": "Режим отображения",
"Display name": "Отображаемое имя", "Display name": "Отображаемое имя",
"Display Name": "Отображаемое имя", "Display Name": "Отображаемое имя",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "Плавающая", "Floating": "Плавающая",
"Flow": "Поток", "Flow": "Поток",
"Flow Filters": "Фильтры потока", "Flow Filters": "Фильтры потока",
"Flow width metric": "Метрика ширины потока",
"FluentRead extension not detected. Please ensure it is installed and active.": "Расширение FluentRead не обнаружено. Убедитесь, что оно установлено и активно.", "FluentRead extension not detected. Please ensure it is installed and active.": "Расширение FluentRead не обнаружено. Убедитесь, что оно установлено и активно.",
"Flush interval (minutes)": "Интервал записи (минуты)", "Flush interval (minutes)": "Интервал записи (минуты)",
"Follow the guided steps to prepare your workspace before the first login.": "Следуйте пошаговым инструкциям, чтобы подготовить рабочее пространство перед первым входом.", "Follow the guided steps to prepare your workspace before the first login.": "Следуйте пошаговым инструкциям, чтобы подготовить рабочее пространство перед первым входом.",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "Более 999 дней", "More than 999 days left": "Более 999 дней",
"More...": "Подробнее...", "More...": "Подробнее...",
"Most-used models in the selected period and category": "Самые используемые модели в выбранном периоде и категории", "Most-used models in the selected period and category": "Самые используемые модели в выбранном периоде и категории",
"Merge into Other": "Объединить в «Другое»",
"Move": "Переместить", "Move": "Переместить",
"Move a request header": "Переместить заголовок запроса", "Move a request header": "Переместить заголовок запроса",
"Move affiliate rewards to your main balance": "Перевести партнерские вознаграждения на основной баланс", "Move affiliate rewards to your main balance": "Перевести партнерские вознаграждения на основной баланс",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "орг-...", "org-...": "орг-...",
"Original Model": "Оригинальная модель", "Original Model": "Оригинальная модель",
"Other": "Другое", "Other": "Другое",
"Other channels": "Другие каналы",
"Other groups": "Другие группы",
"Other models": "Другие модели",
"Other nodes": "Другие узлы",
"Other tokens": "Другие токены",
"Other users": "Другие пользователи",
"Outage": "Простой", "Outage": "Простой",
"Output": "Вывод", "Output": "Вывод",
"Output aspect ratio": "Соотношение сторон", "Output aspect ratio": "Соотношение сторон",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "Выходные токены", "Output tokens": "Выходные токены",
"Output Tokens": "Выходные токены", "Output Tokens": "Выходные токены",
"Overage limited": "Ограничение перерасхода", "Overage limited": "Ограничение перерасхода",
"Overflow items": "Элементы сверх лимита",
"overall": "всего", "overall": "всего",
"Overnight range": "Диапазон через полночь", "Overnight range": "Диапазон через полночь",
"override": "переопределить", "override": "переопределить",
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "by", "by": "by",
"By category": "Theo danh mục", "By category": "Theo danh mục",
"By model author": "Theo nhà phát triển mô hình", "By model author": "Theo nhà phát triển mô hình",
"By quota": "Theo hạn ngạch",
"By requests": "Theo số yêu cầu",
"By tokens": "Theo số token",
"Cache": "Bộ nhớ đệm", "Cache": "Bộ nhớ đệm",
"Cache create (1h) price": "Giá tạo cache (1 giờ)", "Cache create (1h) price": "Giá tạo cache (1 giờ)",
"Cache create price": "Giá tạo cache", "Cache create price": "Giá tạo cache",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "Lựa chọn giữa tùy chọn hệ thống, chế độ sáng hoặc chế độ tối", "Choose between system preference, light mode, or dark mode": "Lựa chọn giữa tùy chọn hệ thống, chế độ sáng hoặc chế độ tối",
"Choose channels to sync upstream ratio configurations from": "Chọn các kênh để đồng bộ cấu hình tỷ lệ đường lên từ", "Choose channels to sync upstream ratio configurations from": "Chọn các kênh để đồng bộ cấu hình tỷ lệ đường lên từ",
"Choose Group": "Chọn Nhóm", "Choose Group": "Chọn Nhóm",
"Choose how flow widths are calculated.": "Chọn cách tính độ rộng của các luồng.",
"Choose how quota values are shown to users": "Chọn cách hiển thị giá trị hạn ngạch cho người dùng", "Choose how quota values are shown to users": "Chọn cách hiển thị giá trị hạn ngạch cho người dùng",
"Choose how the platform will operate": "Chọn cách nền tảng sẽ hoạt động", "Choose how the platform will operate": "Chọn cách nền tảng sẽ hoạt động",
"Choose how to filter domains": "Chọn cách lọc tên miền", "Choose how to filter domains": "Chọn cách lọc tên miền",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "Lượt truy cập đĩa", "Disk Hits": "Lượt truy cập đĩa",
"Disk Threshold (%)": "Ngưỡng đĩa (%)", "Disk Threshold (%)": "Ngưỡng đĩa (%)",
"Display in Currency": "Hiển thị tiền tệ", "Display in Currency": "Hiển thị tiền tệ",
"Display limit": "Giới hạn hiển thị",
"Display Mode": "Chế độ hiển thị", "Display Mode": "Chế độ hiển thị",
"Display name": "Tên hiển thị", "Display name": "Tên hiển thị",
"Display Name": "Tên hiển thị", "Display Name": "Tên hiển thị",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "Nổi", "Floating": "Nổi",
"Flow": "Luồng", "Flow": "Luồng",
"Flow Filters": "Bộ lọc luồng", "Flow Filters": "Bộ lọc luồng",
"Flow width metric": "Chỉ số độ rộng luồng",
"FluentRead extension not detected. Please ensure it is installed and active.": "Không phát hiện tiện ích mở rộng FluentRead. Vui lòng đảm bảo nó đã được cài đặt và kích hoạt.", "FluentRead extension not detected. Please ensure it is installed and active.": "Không phát hiện tiện ích mở rộng FluentRead. Vui lòng đảm bảo nó đã được cài đặt và kích hoạt.",
"Flush interval (minutes)": "Khoảng ghi xuống DB (phút)", "Flush interval (minutes)": "Khoảng ghi xuống DB (phút)",
"Follow the guided steps to prepare your workspace before the first login.": "Thực hiện theo các bước hướng dẫn để chuẩn bị không gian làm việc của bạn trước lần đăng nhập đầu tiên.", "Follow the guided steps to prepare your workspace before the first login.": "Thực hiện theo các bước hướng dẫn để chuẩn bị không gian làm việc của bạn trước lần đăng nhập đầu tiên.",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "Hơn 999 ngày", "More than 999 days left": "Hơn 999 ngày",
"More...": "Thêm...", "More...": "Thêm...",
"Most-used models in the selected period and category": "Mô hình được dùng nhiều nhất trong khoảng thời gian và danh mục đã chọn", "Most-used models in the selected period and category": "Mô hình được dùng nhiều nhất trong khoảng thời gian và danh mục đã chọn",
"Merge into Other": "Gộp vào Khác",
"Move": "Di chuyển", "Move": "Di chuyển",
"Move a request header": "Di chuyển header yêu cầu", "Move a request header": "Di chuyển header yêu cầu",
"Move affiliate rewards to your main balance": "Chuyển phần thưởng liên kết vào số dư chính của bạn", "Move affiliate rewards to your main balance": "Chuyển phần thưởng liên kết vào số dư chính của bạn",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "org-...", "org-...": "org-...",
"Original Model": "Nguyên mẫu", "Original Model": "Nguyên mẫu",
"Other": "Khác", "Other": "Khác",
"Other channels": "Kênh khác",
"Other groups": "Nhóm khác",
"Other models": "Mô hình khác",
"Other nodes": "Nút khác",
"Other tokens": "Token khác",
"Other users": "Người dùng khác",
"Outage": "Gián đoạn", "Outage": "Gián đoạn",
"Output": "Đầu ra", "Output": "Đầu ra",
"Output aspect ratio": "Tỉ lệ khung hình", "Output aspect ratio": "Tỉ lệ khung hình",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "Token đầu ra", "Output tokens": "Token đầu ra",
"Output Tokens": "Token đầu ra", "Output Tokens": "Token đầu ra",
"Overage limited": "Đã giới hạn vượt mức", "Overage limited": "Đã giới hạn vượt mức",
"Overflow items": "Mục vượt giới hạn",
"overall": "tổng", "overall": "tổng",
"Overnight range": "Khoảng qua nửa đêm", "Overnight range": "Khoảng qua nửa đêm",
"override": "ghi đè", "override": "ghi đè",
......
...@@ -625,6 +625,9 @@ ...@@ -625,6 +625,9 @@
"by": "由", "by": "由",
"By category": "按行业", "By category": "按行业",
"By model author": "按模型厂商", "By model author": "按模型厂商",
"By quota": "按额度",
"By requests": "按请求数",
"By tokens": "按 Token",
"Cache": "缓存", "Cache": "缓存",
"Cache create (1h) price": "1 小时缓存写入价格", "Cache create (1h) price": "1 小时缓存写入价格",
"Cache create price": "缓存写入价格", "Cache create price": "缓存写入价格",
...@@ -746,6 +749,7 @@ ...@@ -746,6 +749,7 @@
"Choose between system preference, light mode, or dark mode": "选择系统偏好、浅色模式或深色模式", "Choose between system preference, light mode, or dark mode": "选择系统偏好、浅色模式或深色模式",
"Choose channels to sync upstream ratio configurations from": "选择要同步上游比例配置的渠道", "Choose channels to sync upstream ratio configurations from": "选择要同步上游比例配置的渠道",
"Choose Group": "选择分组", "Choose Group": "选择分组",
"Choose how flow widths are calculated.": "选择分流图连线宽度的计算方式。",
"Choose how quota values are shown to users": "选择如何向用户展示配额值", "Choose how quota values are shown to users": "选择如何向用户展示配额值",
"Choose how the platform will operate": "选择平台的运行模式", "Choose how the platform will operate": "选择平台的运行模式",
"Choose how to filter domains": "选择如何过滤域名", "Choose how to filter domains": "选择如何过滤域名",
...@@ -1315,6 +1319,7 @@ ...@@ -1315,6 +1319,7 @@
"Disk Hits": "磁盘命中", "Disk Hits": "磁盘命中",
"Disk Threshold (%)": "磁盘阈值 (%)", "Disk Threshold (%)": "磁盘阈值 (%)",
"Display in Currency": "以货币显示", "Display in Currency": "以货币显示",
"Display limit": "显示数量",
"Display Mode": "显示模式", "Display Mode": "显示模式",
"Display name": "显示名称", "Display name": "显示名称",
"Display Name": "显示名称", "Display Name": "显示名称",
...@@ -1868,6 +1873,7 @@ ...@@ -1868,6 +1873,7 @@
"Floating": "浮动", "Floating": "浮动",
"Flow": "分流", "Flow": "分流",
"Flow Filters": "分流筛选", "Flow Filters": "分流筛选",
"Flow width metric": "连线粗细",
"FluentRead extension not detected. Please ensure it is installed and active.": "未检测到 FluentRead 扩展。请确保已安装并激活。", "FluentRead extension not detected. Please ensure it is installed and active.": "未检测到 FluentRead 扩展。请确保已安装并激活。",
"Flush interval (minutes)": "刷库间隔(分钟)", "Flush interval (minutes)": "刷库间隔(分钟)",
"Follow the guided steps to prepare your workspace before the first login.": "请按照引导步骤在首次登录前准备您的工作区。", "Follow the guided steps to prepare your workspace before the first login.": "请按照引导步骤在首次登录前准备您的工作区。",
...@@ -2551,6 +2557,7 @@ ...@@ -2551,6 +2557,7 @@
"More than 999 days left": "剩余超过 999 天", "More than 999 days left": "剩余超过 999 天",
"More...": "更多...", "More...": "更多...",
"Most-used models in the selected period and category": "所选时间范围与分类下使用率最高的模型", "Most-used models in the selected period and category": "所选时间范围与分类下使用率最高的模型",
"Merge into Other": "合并为其他",
"Move": "移动", "Move": "移动",
"Move a request header": "移动请求头", "Move a request header": "移动请求头",
"Move affiliate rewards to your main balance": "将推广奖励转移到您的主余额", "Move affiliate rewards to your main balance": "将推广奖励转移到您的主余额",
...@@ -2936,6 +2943,12 @@ ...@@ -2936,6 +2943,12 @@
"org-...": "org-...", "org-...": "org-...",
"Original Model": "原始模型", "Original Model": "原始模型",
"Other": "其他", "Other": "其他",
"Other channels": "其他渠道",
"Other groups": "其他分组",
"Other models": "其他模型",
"Other nodes": "其他节点",
"Other tokens": "其他令牌",
"Other users": "其他用户",
"Outage": "中断", "Outage": "中断",
"Output": "输出", "Output": "输出",
"Output aspect ratio": "输出宽高比", "Output aspect ratio": "输出宽高比",
...@@ -2945,6 +2958,7 @@ ...@@ -2945,6 +2958,7 @@
"Output tokens": "输出 token", "Output tokens": "输出 token",
"Output Tokens": "输出 Token", "Output Tokens": "输出 Token",
"Overage limited": "超额受限", "Overage limited": "超额受限",
"Overflow items": "超出项",
"overall": "总体", "overall": "总体",
"Overnight range": "跨日范围", "Overnight range": "跨日范围",
"override": "覆盖", "override": "覆盖",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment