chore: locales

This commit is contained in:
jialin
2026-04-22 13:16:48 +08:00
committed by jialin
parent c92f56ec8f
commit 128f59ed6f
15 changed files with 287 additions and 97 deletions
+27 -1
View File
@@ -1,5 +1,31 @@
export default { export default {
'usage.title': 'Usage', 'usage.title': 'Usage',
'usage.filter.user': 'Filter by user', 'usage.filter.user': 'Filter by user',
'usage.filter.model': 'Filter by model' 'usage.filter.model': 'Filter by model',
'usage.filter.apikey': 'Filter by API key',
'usage.filter.metric': 'Metric',
'usage.filter.groupBy': 'Group by',
'usage.filter.group.user': 'User',
'usage.filter.group.model': 'Model',
'usage.filter.group.apikey': 'API Key',
'usage.filter.inputTokens': 'Input Tokens',
'usage.filter.outputTokens': 'Output Tokens',
'usage.filter.totalTokens': 'Total Tokens',
'usage.filter.apiRequests': 'API Requests',
'usage.filter.modelsUsed': 'Models Used',
'usage.table.user.modelsUsed': 'Models Used',
'usage.table.user.apiKeysUsed': 'API Keys Used',
'usage.table.lastActive': 'Last Active',
'usage.filter.granularity': 'Granularity',
'usage.filter.granularity.day': 'Day',
'usage.filter.granularity.week': 'Week',
'usage.filter.granularity.month': 'Month',
'usage.tabs.models': 'Models',
'usage.tabs.apikeys': 'API Keys',
'usage.tabs.users': 'User',
'usage.export.chart': 'Export Chart Data',
'usage.export.table': 'Export Table Data',
'usage.user.currentAccount': 'Current Account',
'usage.table.cluster': 'Cluster',
'usage.table.provider': 'Provider'
}; };
+29 -3
View File
@@ -1,5 +1,31 @@
export default { export default {
'usage.title': '使用状況', 'usage.title': 'Usage',
'usage.filter.user': 'ユーザーでフィルタ', 'usage.filter.user': 'Filter by user',
'usage.filter.model': 'モデルでフィルタ' 'usage.filter.model': 'Filter by model',
'usage.filter.apikey': 'Filter by API key',
'usage.filter.metric': 'Metric',
'usage.filter.groupBy': 'Group by',
'usage.filter.group.user': 'User',
'usage.filter.group.model': 'Model',
'usage.filter.group.apikey': 'API Key',
'usage.filter.inputTokens': 'Input Tokens',
'usage.filter.outputTokens': 'Output Tokens',
'usage.filter.totalTokens': 'Total Tokens',
'usage.filter.apiRequests': 'API Requests',
'usage.filter.modelsUsed': 'Models Used',
'usage.table.user.modelsUsed': 'Models Used',
'usage.table.user.apiKeysUsed': 'API Keys Used',
'usage.table.lastActive': 'Last Active',
'usage.filter.granularity': 'Granularity',
'usage.filter.granularity.day': 'Day',
'usage.filter.granularity.week': 'Week',
'usage.filter.granularity.month': 'Month',
'usage.tabs.models': 'Models',
'usage.tabs.apikeys': 'API Keys',
'usage.tabs.users': 'User',
'usage.export.chart': 'Export Chart Data',
'usage.export.table': 'Export Table Data',
'usage.user.currentAccount': 'Current Account',
'usage.table.cluster': 'Cluster',
'usage.table.provider': 'Provider'
}; };
+29 -3
View File
@@ -1,5 +1,31 @@
export default { export default {
'usage.title': 'Использование', 'usage.title': 'Usage',
'usage.filter.user': 'Фильтр по пользователю', 'usage.filter.user': 'Filter by user',
'usage.filter.model': 'Фильтр по модели' 'usage.filter.model': 'Filter by model',
'usage.filter.apikey': 'Filter by API key',
'usage.filter.metric': 'Metric',
'usage.filter.groupBy': 'Group by',
'usage.filter.group.user': 'User',
'usage.filter.group.model': 'Model',
'usage.filter.group.apikey': 'API Key',
'usage.filter.inputTokens': 'Input Tokens',
'usage.filter.outputTokens': 'Output Tokens',
'usage.filter.totalTokens': 'Total Tokens',
'usage.filter.apiRequests': 'API Requests',
'usage.filter.modelsUsed': 'Models Used',
'usage.table.user.modelsUsed': 'Models Used',
'usage.table.user.apiKeysUsed': 'API Keys Used',
'usage.table.lastActive': 'Last Active',
'usage.filter.granularity': 'Granularity',
'usage.filter.granularity.day': 'Day',
'usage.filter.granularity.week': 'Week',
'usage.filter.granularity.month': 'Month',
'usage.tabs.models': 'Models',
'usage.tabs.apikeys': 'API Keys',
'usage.tabs.users': 'User',
'usage.export.chart': 'Export Chart Data',
'usage.export.table': 'Export Table Data',
'usage.user.currentAccount': 'Current Account',
'usage.table.cluster': 'Cluster',
'usage.table.provider': 'Provider'
}; };
+29 -3
View File
@@ -1,5 +1,31 @@
export default { export default {
'usage.title': 'Kullanım', 'usage.title': 'Usage',
'usage.filter.user': 'Kullanıcıya göre filtrele', 'usage.filter.user': 'Filter by user',
'usage.filter.model': 'Modele göre filtrele' 'usage.filter.model': 'Filter by model',
'usage.filter.apikey': 'Filter by API key',
'usage.filter.metric': 'Metric',
'usage.filter.groupBy': 'Group by',
'usage.filter.group.user': 'User',
'usage.filter.group.model': 'Model',
'usage.filter.group.apikey': 'API Key',
'usage.filter.inputTokens': 'Input Tokens',
'usage.filter.outputTokens': 'Output Tokens',
'usage.filter.totalTokens': 'Total Tokens',
'usage.filter.apiRequests': 'API Requests',
'usage.filter.modelsUsed': 'Models Used',
'usage.table.user.modelsUsed': 'Models Used',
'usage.table.user.apiKeysUsed': 'API Keys Used',
'usage.table.lastActive': 'Last Active',
'usage.filter.granularity': 'Granularity',
'usage.filter.granularity.day': 'Day',
'usage.filter.granularity.week': 'Week',
'usage.filter.granularity.month': 'Month',
'usage.tabs.models': 'Models',
'usage.tabs.apikeys': 'API Keys',
'usage.tabs.users': 'User',
'usage.export.chart': 'Export Chart Data',
'usage.export.table': 'Export Table Data',
'usage.user.currentAccount': 'Current Account',
'usage.table.cluster': 'Cluster',
'usage.table.provider': 'Provider'
}; };
+27 -1
View File
@@ -1,5 +1,31 @@
export default { export default {
'usage.title': '使用量', 'usage.title': '使用量',
'usage.filter.user': '按用户查询', 'usage.filter.user': '按用户查询',
'usage.filter.model': '按模型查询' 'usage.filter.model': '按模型查询',
'usage.filter.apikey': '按 API 密钥查询',
'usage.filter.metric': '指标',
'usage.filter.groupBy': '分组',
'usage.filter.group.user': '用户',
'usage.filter.group.model': '模型',
'usage.filter.group.apikey': 'API 密钥',
'usage.filter.inputTokens': '输入 Token 数',
'usage.filter.outputTokens': '输出 Token 数',
'usage.filter.totalTokens': '总 Token 数',
'usage.filter.apiRequests': 'API 请求数',
'usage.filter.modelsUsed': '使用的模型数',
'usage.table.user.modelsUsed': '使用的模型',
'usage.table.user.apiKeysUsed': '使用的 API 密钥',
'usage.table.lastActive': '最后活跃时间',
'usage.filter.granularity': '粒度',
'usage.filter.granularity.day': '按天',
'usage.filter.granularity.week': '按周',
'usage.filter.granularity.month': '按月',
'usage.tabs.models': '模型',
'usage.tabs.apikeys': 'API 密钥',
'usage.tabs.users': '用户',
'usage.export.chart': '导出图表数据',
'usage.export.table': '导出表格数据',
'usage.user.currentAccount': '当前账户',
'usage.table.cluster': '集群',
'usage.table.provider': '提供商'
}; };
+24 -5
View File
@@ -2,6 +2,7 @@ import CardWrapper from '@/components/card-wrapper';
import MixLineBar from '@/components/echarts/mix-line-bar'; import MixLineBar from '@/components/echarts/mix-line-bar';
import BaseSelect from '@/components/seal-form/base/select'; import BaseSelect from '@/components/seal-form/base/select';
import { baseColorMap } from '@/pages/dashboard/config'; import { baseColorMap } from '@/pages/dashboard/config';
import { useIntl } from '@umijs/max';
import { Segmented } from 'antd'; import { Segmented } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
@@ -42,6 +43,7 @@ const labelFormatter = (v: any) => {
}; };
const DailyUsage: React.FC<DailyUsageProps> = (props) => { const DailyUsage: React.FC<DailyUsageProps> = (props) => {
const intl = useIntl();
const { const {
timeSeriesData, timeSeriesData,
metric, metric,
@@ -102,8 +104,15 @@ const DailyUsage: React.FC<DailyUsageProps> = (props) => {
<div className="group"> <div className="group">
<BaseSelect <BaseSelect
variant="borderless" variant="borderless"
prefix={<ControlLabel>Metric</ControlLabel>} prefix={
options={metricOptions} <ControlLabel>
{intl.formatMessage({ id: 'usage.filter.metric' })}
</ControlLabel>
}
options={metricOptions.map((item) => ({
label: intl.formatMessage({ id: item.label }),
value: item.value
}))}
value={metric} value={metric}
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
onChange={onMetricChange} onChange={onMetricChange}
@@ -113,8 +122,15 @@ const DailyUsage: React.FC<DailyUsageProps> = (props) => {
<BaseSelect <BaseSelect
allowClear allowClear
variant="borderless" variant="borderless"
prefix={<ControlLabel>Group by</ControlLabel>} prefix={
options={groupByOptions} <ControlLabel>
{intl.formatMessage({ id: 'usage.filter.groupBy' })}
</ControlLabel>
}
options={groupByOptions.map((item) => ({
label: intl.formatMessage({ id: item.label }),
value: item.value
}))}
value={groupBy} value={groupBy}
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
onChange={handleOnGroupByChange} onChange={handleOnGroupByChange}
@@ -123,7 +139,10 @@ const DailyUsage: React.FC<DailyUsageProps> = (props) => {
</div> </div>
<Segmented <Segmented
size="small" size="small"
options={granularities} options={granularities.map((item) => ({
label: intl.formatMessage({ id: item.label }),
value: item.value
}))}
value={granularity} value={granularity}
onChange={onGranularityChange} onChange={onGranularityChange}
></Segmented> ></Segmented>
+28 -12
View File
@@ -23,6 +23,14 @@ const ExportData: React.FC<{
activeModels: ValueType[][]; activeModels: ValueType[][];
activeApiKeys: ValueType[][]; activeApiKeys: ValueType[][];
}; };
commonFilters: {
scope: string;
start_date: string;
end_date: string;
models: string[];
users: string[];
api_keys: string[];
};
handlePickerChange: (picker: DateType) => void; handlePickerChange: (picker: DateType) => void;
}> = (props) => { }> = (props) => {
@@ -54,6 +62,8 @@ const ExportData: React.FC<{
key: 'exportTableData' key: 'exportTableData'
}); });
console.log('initialState========', initialState);
const { filters, commonFilters, filterBar } = useUsageFilters({ const { filters, commonFilters, filterBar } = useUsageFilters({
initialScope: initialScope, initialScope: initialScope,
metaData, metaData,
@@ -102,7 +112,7 @@ const ExportData: React.FC<{
} }
}, },
{ {
title: 'Cluster', title: intl.formatMessage({ id: 'usage.table.cluster' }),
dataIndex: ['model', 'identity', 'value', 'cluster_name'], dataIndex: ['model', 'identity', 'value', 'cluster_name'],
render: (text: string) => { render: (text: string) => {
return <AutoTooltip ghost>{text}</AutoTooltip>; return <AutoTooltip ghost>{text}</AutoTooltip>;
@@ -129,26 +139,26 @@ const ExportData: React.FC<{
} }
}, },
{ {
title: 'API Key', title: intl.formatMessage({ id: 'usage.filter.group.apikey' }),
dataIndex: ['api_key', 'label'], dataIndex: ['api_key', 'label'],
render: (text: string, record: any) => { render: (text: string, record: any) => {
return <AutoTooltip ghost>{text}</AutoTooltip>; return <AutoTooltip ghost>{text}</AutoTooltip>;
} }
}, },
{ {
title: 'Input Tokens', title: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
dataIndex: 'input_tokens' dataIndex: 'input_tokens'
}, },
{ {
title: 'Output Tokens', title: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
dataIndex: 'output_tokens' dataIndex: 'output_tokens'
}, },
{ {
title: 'Total Tokens', title: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
dataIndex: 'total_tokens' dataIndex: 'total_tokens'
}, },
{ {
title: 'API Requests', title: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
dataIndex: 'api_requests' dataIndex: 'api_requests'
} }
]; ];
@@ -183,13 +193,19 @@ const ExportData: React.FC<{
fieldLabels: { fieldLabels: {
date: intl.formatMessage({ id: 'dashboard.usage.export.date' }), date: intl.formatMessage({ id: 'dashboard.usage.export.date' }),
user: intl.formatMessage({ id: 'dashboard.usage.export.user' }), user: intl.formatMessage({ id: 'dashboard.usage.export.user' }),
cluster: 'Cluster', cluster: intl.formatMessage({ id: 'usage.table.cluster' }),
model: intl.formatMessage({ id: 'dashboard.usage.export.model' }), model: intl.formatMessage({ id: 'dashboard.usage.export.model' }),
api_key: 'API Key', api_key: intl.formatMessage({ id: 'usage.table.provider' }),
input_tokens: 'Input Tokens', input_tokens: intl.formatMessage({
output_tokens: 'Output Tokens', id: 'usage.filter.inputTokens'
total_tokens: 'Total Tokens', }),
api_requests: 'API Requests' output_tokens: intl.formatMessage({
id: 'usage.filter.outputTokens'
}),
total_tokens: intl.formatMessage({
id: 'usage.filter.totalTokens'
}),
api_requests: intl.formatMessage({ id: 'usage.filter.apiRequests' })
}, },
formatMap: {} formatMap: {}
} }
+32 -11
View File
@@ -36,16 +36,28 @@ interface FilterBarProps {
modelOptions: GroupOption<UsageFilterItem>[]; modelOptions: GroupOption<UsageFilterItem>[];
userOptions: OptionType[]; userOptions: OptionType[];
apiKeyOptions: GroupOption<UsageFilterItem>[]; apiKeyOptions: GroupOption<UsageFilterItem>[];
activeModels: valueType[][];
activeApiKeys: valueType[][];
handlePickerChange: (picker: DateType) => void; handlePickerChange: (picker: DateType) => void;
onScopeChange: (value: string) => void; onScopeChange: (value: string) => void;
onDateChange: (dates: any, dateStrings: [string, string]) => void; onDateChange: (dates: any, dateStrings: [string, string]) => void;
onModelsChange: (value: string[]) => void; onModelsChange: (value: string[]) => void;
onUsersChange: (value: string[]) => void; onUsersChange: (value: string[]) => void;
onApiKeysChange: (value: string[]) => void; onApiKeysChange: (value: string[]) => void;
handleActiveModelsChange: (value: valueType[][]) => void;
handleActiveApiKeysChange: (value: valueType[][]) => void;
onExport?: () => void; onExport?: () => void;
handleSearch?: () => void; handleSearch?: () => void;
onExportChart?: () => void; onExportChart?: () => void;
onExportTable?: () => void; onExportTable?: () => void;
commonFilters?: {
scope: string;
start_date: string;
end_date: string;
models: string[];
users: string[];
api_keys: string[];
};
} }
const FilterBar: React.FC<FilterBarProps> = (props) => { const FilterBar: React.FC<FilterBarProps> = (props) => {
@@ -58,6 +70,10 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
modelOptions, modelOptions,
userOptions, userOptions,
apiKeyOptions, apiKeyOptions,
activeModels,
activeApiKeys,
handleActiveModelsChange,
handleActiveApiKeysChange,
handlePickerChange, handlePickerChange,
onDateChange, onDateChange,
onModelsChange, onModelsChange,
@@ -104,8 +120,8 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
} }
] ]
}); });
const [activeModels, setActiveModels] = React.useState<valueType[][]>([]); // const [activeModels, setActiveModels] = React.useState<valueType[][]>([]);
const [activeApiKeys, setActiveApiKeys] = React.useState<valueType[][]>([]); // const [activeApiKeys, setActiveApiKeys] = React.useState<valueType[][]>([]);
const initialInfo = useModel('@@initialState'); const initialInfo = useModel('@@initialState');
const { initialState } = initialInfo || {}; const { initialState } = initialInfo || {};
@@ -116,7 +132,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
label: ( label: (
<span className="flex-center gap-8"> <span className="flex-center gap-8">
<IconFont type="icon-chart-01" style={{ fontSize: 14 }} /> <IconFont type="icon-chart-01" style={{ fontSize: 14 }} />
<span>Export Chart Data</span> <span>{intl.formatMessage({ id: 'usage.export.chart' })}</span>
</span> </span>
), ),
onClick: onExportChart onClick: onExportChart
@@ -126,7 +142,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
label: ( label: (
<span className="flex-center gap-8"> <span className="flex-center gap-8">
<IconFont type="icon-table" style={{ fontSize: 14 }} /> <IconFont type="icon-table" style={{ fontSize: 14 }} />
<span>Export Table Data</span> <span>{intl.formatMessage({ id: 'usage.export.table' })}</span>
</span> </span>
), ),
onClick: onExportTable onClick: onExportTable
@@ -134,13 +150,14 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
]; ];
const handleOnModelsChange = (value: valueType[][], selectedOptions: any) => { const handleOnModelsChange = (value: valueType[][], selectedOptions: any) => {
setActiveModels(value); // setActiveModels(value);
const selectedValues: string[] = value.map((item) => { const selectedValues: string[] = value.map((item) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
return item[item.length - 1] as string; // Get the last value in the array return item[item.length - 1] as string; // Get the last value in the array
} }
return item as string; return item as string;
}); });
handleActiveModelsChange(value);
onModelsChange(selectedValues); onModelsChange(selectedValues);
}; };
@@ -148,13 +165,14 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
value: valueType[][], value: valueType[][],
selectedOptions: any selectedOptions: any
) => { ) => {
setActiveApiKeys(value); // setActiveApiKeys(value);
const selectedValues: string[] = value.map((item) => { const selectedValues: string[] = value.map((item) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
return item[item.length - 1] as string; // Get the last value in the array return item[item.length - 1] as string; // Get the last value in the array
} }
return item as string; return item as string;
}); });
handleActiveApiKeysChange(value);
onApiKeysChange(selectedValues); onApiKeysChange(selectedValues);
}; };
@@ -254,7 +272,10 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
<span className="flex-center gap-8"> <span className="flex-center gap-8">
<span>{data.label}</span> <span>{data.label}</span>
{data.isCurrent && ( {data.isCurrent && (
<span className="text-tertiary"> [Current Account]</span> <span className="text-tertiary">
{' '}
[{intl.formatMessage({ id: 'usage.user.currentAccount' })}]
</span>
)} )}
</span> </span>
); );
@@ -312,7 +333,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
}} }}
maxTagCount={1} maxTagCount={1}
size="small" size="small"
placeholder={'Filter by model'} placeholder={intl.formatMessage({ id: 'usage.filter.model' })}
options={modelOptions} options={modelOptions}
showCheckedStrategy="SHOW_CHILD" showCheckedStrategy="SHOW_CHILD"
displayRender={displayRender} displayRender={displayRender}
@@ -329,7 +350,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
showSearch showSearch
mode="multiple" mode="multiple"
options={userOptions} options={userOptions}
placeholder="Filter by user" placeholder={intl.formatMessage({ id: 'usage.filter.user' })}
styles={{ styles={{
wrapper: { flex: 1, maxWidth: 240, minWidth: 150 } wrapper: { flex: 1, maxWidth: 240, minWidth: 150 }
}} }}
@@ -367,7 +388,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
}} }}
maxTagCount={1} maxTagCount={1}
size="small" size="small"
placeholder="Filter by API key" placeholder={intl.formatMessage({ id: 'usage.filter.apikey' })}
options={apiKeyOptions} options={apiKeyOptions}
showCheckedStrategy="SHOW_CHILD" showCheckedStrategy="SHOW_CHILD"
value={activeApiKeys} value={activeApiKeys}
@@ -384,7 +405,7 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
mode="multiple" mode="multiple"
options={apiKeyOptions?.[0]?.children || []} options={apiKeyOptions?.[0]?.children || []}
maxTagCount={0} maxTagCount={0}
placeholder="Filter by API key" placeholder={intl.formatMessage({ id: 'usage.filter.apikey' })}
styles={{ styles={{
wrapper: { flex: 1, maxWidth: 240, minWidth: 100 } wrapper: { flex: 1, maxWidth: 240, minWidth: 100 }
}} }}
+10 -21
View File
@@ -7,60 +7,49 @@ export const groupByOptions = [
// }, // },
{ {
value: 'model', value: 'model',
label: 'Model' label: 'usage.filter.group.model'
}, },
{ {
value: 'user', value: 'user',
label: 'User' label: 'usage.filter.group.user'
}, },
{ {
value: 'api_key', value: 'api_key',
label: 'API Key' label: 'usage.filter.group.apikey'
} }
]; ];
export const granularities = [ export const granularities = [
{ {
value: 'day', value: 'day',
label: 'Day' label: 'usage.filter.granularity.day'
}, },
{ {
value: 'week', value: 'week',
label: 'Week' label: 'usage.filter.granularity.week'
}, },
{ {
value: 'month', value: 'month',
label: 'Month' label: 'usage.filter.granularity.month'
} }
]; ];
export const metricOptions = [ export const metricOptions = [
{ {
value: 'input_tokens', value: 'input_tokens',
label: 'Input Tokens' label: 'usage.filter.inputTokens'
}, },
{ {
value: 'output_tokens', value: 'output_tokens',
label: 'Output Tokens' label: 'usage.filter.outputTokens'
}, },
{ {
value: 'total_tokens', value: 'total_tokens',
label: 'Total Tokens' label: 'usage.filter.totalTokens'
}, },
{ {
value: 'api_requests', value: 'api_requests',
label: 'API Requests' label: 'usage.filter.apiRequests'
}
];
export const scopeOptions = [
{
value: 'all',
label: 'All Users'
},
{
value: 'self',
label: 'My Usage'
} }
]; ];
@@ -28,7 +28,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'User', title: intl.formatMessage({ id: 'usage.tabs.users' }),
dataIndex: ['api_key', 'identity', 'value', 'user_name'], dataIndex: ['api_key', 'identity', 'value', 'user_name'],
key: 'user_name', key: 'user_name',
render: (text: string, record: ListItem) => ( render: (text: string, record: ListItem) => (
@@ -38,7 +38,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Models Used', title: intl.formatMessage({ id: 'usage.filter.modelsUsed' }),
dataIndex: 'models_called', dataIndex: 'models_called',
key: 'models_called', key: 'models_called',
sorter: tableSorter(2), sorter: tableSorter(2),
@@ -47,7 +47,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Input Tokens', title: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
dataIndex: 'input_tokens', dataIndex: 'input_tokens',
key: 'input_tokens', key: 'input_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -55,7 +55,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Output Tokens', title: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
dataIndex: 'output_tokens', dataIndex: 'output_tokens',
key: 'output_tokens', key: 'output_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -63,7 +63,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Total Tokens', title: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
dataIndex: 'total_tokens', dataIndex: 'total_tokens',
key: 'total_tokens', key: 'total_tokens',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -73,7 +73,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'API Requests', title: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
dataIndex: 'api_requests', dataIndex: 'api_requests',
key: 'api_requests', key: 'api_requests',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -83,7 +83,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'Last Active', title: intl.formatMessage({ id: 'usage.table.lastActive' }),
dataIndex: 'last_active', dataIndex: 'last_active',
key: 'last_active', key: 'last_active',
sorter: tableSorter(3), sorter: tableSorter(3),
+5 -4
View File
@@ -5,6 +5,7 @@ import {
} from '@/atoms/usage'; } from '@/atoms/usage';
import { exportJsonToExcel } from '@/utils/excel-reader'; import { exportJsonToExcel } from '@/utils/excel-reader';
import { useStore } from 'jotai'; import { useStore } from 'jotai';
import _ from 'lodash';
import useAPIKeysColumns from './use-apikeys-columns'; import useAPIKeysColumns from './use-apikeys-columns';
import useModelsColumns from './use-models-columns'; import useModelsColumns from './use-models-columns';
import useUsersColumns from './use-users-columns'; import useUsersColumns from './use-users-columns';
@@ -26,11 +27,11 @@ const useExportTable = () => {
jsonData: modelsTableData.dataList || [], jsonData: modelsTableData.dataList || [],
sheetName: 'models', sheetName: 'models',
fields: modelsColumns fields: modelsColumns
.map((col: any) => col.dataIndex) .map((col: any) => _.join(col.dataIndex, '_'))
.filter(Boolean) as string[], .filter(Boolean) as string[],
fieldLabels: modelsColumns.reduce( fieldLabels: modelsColumns.reduce(
(map, col) => { (map, col) => {
map[col.dataIndex] = col.title; map[_.join(col.dataIndex, '_')] = col.title;
return map; return map;
}, },
{} as Record<string, any> {} as Record<string, any>
@@ -45,7 +46,7 @@ const useExportTable = () => {
.filter(Boolean) as string[], .filter(Boolean) as string[],
fieldLabels: apiKeysColumns.reduce( fieldLabels: apiKeysColumns.reduce(
(map, col) => { (map, col) => {
map[col.dataIndex] = col.title; map[_.join(col.dataIndex, '_')] = col.title;
return map; return map;
}, },
{} as Record<string, any> {} as Record<string, any>
@@ -60,7 +61,7 @@ const useExportTable = () => {
.filter(Boolean) as string[], .filter(Boolean) as string[],
fieldLabels: usersColumns.reduce( fieldLabels: usersColumns.reduce(
(map, col) => { (map, col) => {
map[col.dataIndex] = col.title; map[_.join(col.dataIndex, '_')] = col.title;
return map; return map;
}, },
{} as Record<string, any> {} as Record<string, any>
+7 -7
View File
@@ -33,7 +33,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Cluster', title: intl.formatMessage({ id: 'usage.table.cluster' }),
dataIndex: ['model', 'identity', 'value', 'cluster_name'], dataIndex: ['model', 'identity', 'value', 'cluster_name'],
key: 'cluster_name', key: 'cluster_name',
sorter: tableSorter(2), sorter: tableSorter(2),
@@ -42,7 +42,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Provider', title: intl.formatMessage({ id: 'usage.table.provider' }),
dataIndex: 'provider_name', dataIndex: 'provider_name',
key: 'provider_name', key: 'provider_name',
render: (text: string, record: ListItem) => ( render: (text: string, record: ListItem) => (
@@ -57,7 +57,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Input Tokens', title: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
dataIndex: 'input_tokens', dataIndex: 'input_tokens',
key: 'input_tokens', key: 'input_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -65,7 +65,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Output Tokens', title: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
dataIndex: 'output_tokens', dataIndex: 'output_tokens',
key: 'output_tokens', key: 'output_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -73,7 +73,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Total Tokens', title: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
dataIndex: 'total_tokens', dataIndex: 'total_tokens',
key: 'total_tokens', key: 'total_tokens',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -83,7 +83,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'API Requests', title: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
dataIndex: 'api_requests', dataIndex: 'api_requests',
key: 'api_requests', key: 'api_requests',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -93,7 +93,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'Last Active', title: intl.formatMessage({ id: 'usage.table.lastActive' }),
dataIndex: 'last_active', dataIndex: 'last_active',
key: 'last_active', key: 'last_active',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -184,6 +184,14 @@ export const useUsageFilters = ({
} }
}; };
const handleActiveModelsChange = (value: ValueType[][]) => {
setActiveModels(value);
};
const handleActiveApiKeysChange = (value: ValueType[][]) => {
setActiveApiKeys(value);
};
const handleFilterChange = ( const handleFilterChange = (
type: 'models' | 'users' | 'api_keys', type: 'models' | 'users' | 'api_keys',
value: string[] value: string[]
@@ -248,6 +256,8 @@ export const useUsageFilters = ({
activeApiKeys, activeApiKeys,
activeModels, activeModels,
handleSearch, handleSearch,
handleActiveModelsChange,
handleActiveApiKeysChange,
onScopeChange: handleScopeChange, onScopeChange: handleScopeChange,
onDateChange: handleDateChange, onDateChange: handleDateChange,
onModelsChange: (value: string[]) => handleFilterChange('models', value), onModelsChange: (value: string[]) => handleFilterChange('models', value),
+7 -7
View File
@@ -32,7 +32,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Models Used', title: intl.formatMessage({ id: 'usage.filter.modelsUsed' }),
dataIndex: 'models_called', dataIndex: 'models_called',
key: 'models_called', key: 'models_called',
render: (text: string, record: ListItem) => ( render: (text: string, record: ListItem) => (
@@ -42,7 +42,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'API Keys Used', title: intl.formatMessage({ id: 'usage.table.user.apiKeysUsed' }),
dataIndex: 'api_keys_used', dataIndex: 'api_keys_used',
key: 'api_keys_used', key: 'api_keys_used',
sorter: tableSorter(2), sorter: tableSorter(2),
@@ -51,7 +51,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Input Tokens', title: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
dataIndex: 'input_tokens', dataIndex: 'input_tokens',
key: 'input_tokens', key: 'input_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -59,7 +59,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Output Tokens', title: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
dataIndex: 'output_tokens', dataIndex: 'output_tokens',
key: 'output_tokens', key: 'output_tokens',
render: (text: string[], record: ListItem) => ( render: (text: string[], record: ListItem) => (
@@ -67,7 +67,7 @@ const useModelsColumns = (): Array<{
) )
}, },
{ {
title: 'Total Tokens', title: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
dataIndex: 'total_tokens', dataIndex: 'total_tokens',
key: 'total_tokens', key: 'total_tokens',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -77,7 +77,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'API Requests', title: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
dataIndex: 'api_requests', dataIndex: 'api_requests',
key: 'api_requests', key: 'api_requests',
sorter: tableSorter(3), sorter: tableSorter(3),
@@ -87,7 +87,7 @@ const useModelsColumns = (): Array<{
render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip> render: (text: number) => <AutoTooltip ghost>{text}</AutoTooltip>
}, },
{ {
title: 'Last Active', title: intl.formatMessage({ id: 'usage.table.lastActive' }),
dataIndex: 'last_active', dataIndex: 'last_active',
key: 'last_active', key: 'last_active',
sorter: tableSorter(3), sorter: tableSorter(3),
+16 -12
View File
@@ -2,6 +2,7 @@ import { SimpleCard } from '@/components/card-wrapper/simple-card';
import { baseColorMap } from '@/pages/dashboard/config'; import { baseColorMap } from '@/pages/dashboard/config';
import { formatLargeNumber } from '@/utils'; import { formatLargeNumber } from '@/utils';
import { useModel } from '@@/plugin-model'; import { useModel } from '@@/plugin-model';
import { useIntl } from '@umijs/max';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import BreakdownTabs from './components/breakdown-tabs'; import BreakdownTabs from './components/breakdown-tabs';
import DailyUsage from './components/daily-usage'; import DailyUsage from './components/daily-usage';
@@ -14,6 +15,7 @@ import useQueryUsageMetaData from './services/use-query-meta-data';
type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year'; type DateType = 'date' | 'week' | 'month' | 'quarter' | 'year';
const Usage: React.FC = () => { const Usage: React.FC = () => {
const intl = useIntl();
const initialInfo = useModel('@@initialState'); const initialInfo = useModel('@@initialState');
const { initialState } = initialInfo || {}; const { initialState } = initialInfo || {};
const { exportTable } = useExportTable(); const { exportTable } = useExportTable();
@@ -22,27 +24,27 @@ const Usage: React.FC = () => {
const summaryColumns = [ const summaryColumns = [
{ {
title: 'Input Tokens', title: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
dataIndex: 'input_tokens', dataIndex: 'input_tokens',
key: 'input_tokens' key: 'input_tokens'
}, },
{ {
title: 'Output Tokens', title: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
dataIndex: 'output_tokens', dataIndex: 'output_tokens',
key: 'output_tokens' key: 'output_tokens'
}, },
{ {
title: 'Total Tokens', title: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
dataIndex: 'total_tokens', dataIndex: 'total_tokens',
key: 'total_tokens' key: 'total_tokens'
}, },
{ {
title: 'API Requests', title: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
dataIndex: 'api_requests', dataIndex: 'api_requests',
key: 'api_requests' key: 'api_requests'
}, },
{ {
title: 'Models Used', title: intl.formatMessage({ id: 'usage.filter.modelsUsed' }),
dataIndex: 'models_called', dataIndex: 'models_called',
key: 'models_called' key: 'models_called'
} }
@@ -90,31 +92,31 @@ const Usage: React.FC = () => {
return [ return [
{ {
label: formatLargeNumber(summary.input_tokens) as string, label: formatLargeNumber(summary.input_tokens) as string,
value: 'Input tokens', value: intl.formatMessage({ id: 'usage.filter.inputTokens' }),
color: baseColorMap.baseR3 color: baseColorMap.baseR3
// iconType: 'roundRect' // iconType: 'roundRect'
}, },
{ {
label: formatLargeNumber(summary.output_tokens) as string, label: formatLargeNumber(summary.output_tokens) as string,
value: 'Output tokens', value: intl.formatMessage({ id: 'usage.filter.outputTokens' }),
color: baseColorMap.base color: baseColorMap.base
// iconType: 'roundRect' // iconType: 'roundRect'
}, },
{ {
label: formatLargeNumber(summary.total_tokens) as string, label: formatLargeNumber(summary.total_tokens) as string,
value: 'Total tokens', value: intl.formatMessage({ id: 'usage.filter.totalTokens' }),
color: baseColorMap.baseL1 color: baseColorMap.baseL1
// iconType: 'roundRect' // iconType: 'roundRect'
}, },
{ {
label: formatLargeNumber(summary.api_requests) as string, label: formatLargeNumber(summary.api_requests) as string,
value: 'API requests', value: intl.formatMessage({ id: 'usage.filter.apiRequests' }),
color: baseColorMap.baseR1 color: baseColorMap.baseR1
// iconType: 'circle' // iconType: 'circle'
}, },
{ {
label: summary.models_called.toString(), label: summary.models_called.toString(),
value: 'Models used', value: intl.formatMessage({ id: 'usage.filter.modelsUsed' }),
color: baseColorMap.baseR2 color: baseColorMap.baseR2
// iconType: 'roundRect' // iconType: 'roundRect'
} }
@@ -176,7 +178,9 @@ const Usage: React.FC = () => {
groupBy={chartFilters.group_by} groupBy={chartFilters.group_by}
granularity={chartFilters.granularity} granularity={chartFilters.granularity}
onMetricChange={(value) => handleChartFilterChange('metric', value)} onMetricChange={(value) => handleChartFilterChange('metric', value)}
onGroupByChange={(value) => handleChartFilterChange('group_by', value)} onGroupByChange={(value) =>
handleChartFilterChange('group_by', value as string)
}
onGranularityChange={(value) => onGranularityChange={(value) =>
handleChartFilterChange('granularity', value) handleChartFilterChange('granularity', value)
} }
@@ -191,7 +195,7 @@ const Usage: React.FC = () => {
metaData={metaData} metaData={metaData}
granularity={chartFilters.granularity} granularity={chartFilters.granularity}
initialScope={commonFilters.scope} initialScope={commonFilters.scope}
initialCommonFilters={commonFilters} commonFilters={commonFilters}
open={openExportModal} open={openExportModal}
handlePickerChange={handlePickerChange} handlePickerChange={handlePickerChange}
onCancel={() => setOpenExportModal(false)} onCancel={() => setOpenExportModal(false)}