chore: languages settings
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
history,
|
||||
matchRoutes,
|
||||
useAppData,
|
||||
useIntl,
|
||||
useLocation,
|
||||
useNavigate,
|
||||
type IRoute
|
||||
@@ -78,6 +79,7 @@ const mapRoutes = (routes: IRoute[], role: string) => {
|
||||
export default (props: any) => {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const intl = useIntl();
|
||||
const { clientRoutes, pluginManager } = useAppData();
|
||||
|
||||
const initialInfo = (useModel && useModel('@@initialState')) || {
|
||||
@@ -94,7 +96,10 @@ export default (props: any) => {
|
||||
locale: true
|
||||
};
|
||||
|
||||
const formatMessage = undefined;
|
||||
const formatMessage = (args) => {
|
||||
console.log('formatMessage', args);
|
||||
return intl.formatMessage({ id: args.id });
|
||||
};
|
||||
|
||||
const runtimeConfig = {
|
||||
...initialInfo,
|
||||
@@ -158,8 +163,8 @@ export default (props: any) => {
|
||||
history.push(pathname);
|
||||
}
|
||||
}}
|
||||
formatMessage={userConfig.formatMessage || formatMessage}
|
||||
menu={{ locale: userConfig.locale }}
|
||||
formatMessage={formatMessage}
|
||||
menu={{ locale: true }}
|
||||
logo={Logo}
|
||||
menuItemRender={(menuItemProps, defaultDom) => {
|
||||
console.log('meurender=========', { defaultDom });
|
||||
|
||||
@@ -16,6 +16,7 @@ export function getRightRenderContent(opts: {
|
||||
setInitialState: any;
|
||||
}) {
|
||||
console.log('runtimeConfig==', opts.runtimeConfig, opts);
|
||||
// const intl = useIntl();
|
||||
if (opts.runtimeConfig.rightRender) {
|
||||
return opts.runtimeConfig.rightRender(
|
||||
opts.initialState,
|
||||
@@ -64,7 +65,10 @@ export function getRightRenderContent(opts: {
|
||||
icon={
|
||||
<span style={{ fontSize: '12px' }}>
|
||||
<GlobalOutlined />
|
||||
<span className="m-l-8">语言</span>
|
||||
<span className="m-l-8">
|
||||
{/* {FormattedMessage({ id: 'common.settings.language' })} */}
|
||||
Language
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
></SelectLang>
|
||||
@@ -83,7 +87,8 @@ export function getRightRenderContent(opts: {
|
||||
label: (
|
||||
<>
|
||||
<SettingOutlined />
|
||||
设置
|
||||
{/* {intl.formatMessage({ id: 'common.button.settings' })} */}
|
||||
Settings
|
||||
</>
|
||||
),
|
||||
onClick: () => {
|
||||
@@ -107,7 +112,8 @@ export function getRightRenderContent(opts: {
|
||||
label: (
|
||||
<>
|
||||
<LogoutOutlined />
|
||||
退出登录
|
||||
{/* {intl.formatMessage({ id: 'common.button.logout' })} */}
|
||||
Logout
|
||||
</>
|
||||
),
|
||||
onClick: () => {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import common from './en-US/common';
|
||||
import menu from './en-US/menu';
|
||||
import models from './en-US/models';
|
||||
import playground from './en-US/playground';
|
||||
import resources from './en-US/resources';
|
||||
|
||||
export default {
|
||||
...common,
|
||||
...menu,
|
||||
...models
|
||||
...models,
|
||||
...playground,
|
||||
...resources
|
||||
};
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
'apikeys.title': 'API Keys',
|
||||
'apikeys.button.create': 'New API Key',
|
||||
'apikeys.form.expiretime': 'Expiration'
|
||||
};
|
||||
@@ -41,6 +41,7 @@ export default {
|
||||
'common.button.edit': 'Edit',
|
||||
'common.button.authorize': 'Role Authorization',
|
||||
'common.button.confirm': 'Confirm',
|
||||
'common.button.viewlog': 'View Logs',
|
||||
'common.table.operation': 'Operation',
|
||||
'common.table.createTime': 'Created',
|
||||
'common.table.updateTime': 'Updated',
|
||||
@@ -173,6 +174,10 @@ export default {
|
||||
'common.nodata.created': 'No {type} has been created yet',
|
||||
'common.nodata.added': 'No {type} has been added yet',
|
||||
'common.status.edited': 'Edited',
|
||||
'common.table.user': '用户',
|
||||
'common.settings.instructions': 'Instructions'
|
||||
'common.table.user': 'User',
|
||||
'common.settings.instructions': 'Instructions',
|
||||
'common.settings.language': 'Language',
|
||||
'common.delete.confirm':
|
||||
'Are you sure you want to delete the selected {type}?',
|
||||
'common.filter.name': 'Filter by name'
|
||||
};
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
export default {};
|
||||
export default {
|
||||
'menu.dashboard': 'Dashboard',
|
||||
'menu.playground': 'Playground',
|
||||
'menu.models': 'Models',
|
||||
'menu.resources': 'Resources',
|
||||
'menu.apikeys': 'API Keys',
|
||||
'menu.users': 'Users',
|
||||
'menu.profile': 'Profile',
|
||||
'menu.login': 'Login'
|
||||
};
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
export default {
|
||||
'models.button.deploy': 'Deploy Model'
|
||||
'models.button.deploy': 'Deploy Model',
|
||||
'models.title': 'Models',
|
||||
'models.table.models': 'models',
|
||||
'models.table.name': 'Model Name',
|
||||
'models.form.source': 'Source',
|
||||
'models.form.repoid': 'Repo ID',
|
||||
'models.form.repoid.desc': 'Only .gguf format is supported',
|
||||
'models.form.filename': 'File Name',
|
||||
'models.form.replicas': 'Replicas',
|
||||
'models.form.s3address': 'S3 Address',
|
||||
'models.openinplayground': 'Open in Playground',
|
||||
'models.instances': 'instances'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
'playground.system.tips': 'Enter system message here...',
|
||||
'playground.title': 'Playground',
|
||||
'playground.system': 'System',
|
||||
'playground.user': 'User',
|
||||
'playground.assistant': 'Assistant',
|
||||
'playground.newMessage': 'New Message',
|
||||
'playground.viewcode': 'View Code',
|
||||
'playground.model': 'Model',
|
||||
'playground.parameters': 'Parameters',
|
||||
'playground.viewcode.info':
|
||||
'You can use the following code to start integrating your current prompt and settings into your application.',
|
||||
'playground.completion': 'Completion',
|
||||
'playground.prompt': 'Prompt',
|
||||
'playground.tokenusage': 'Token Usage',
|
||||
'models.openinplayground': 'Open in Playground'
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export default {
|
||||
'resources.title': 'Resources',
|
||||
'resources.nodes': 'Nodes',
|
||||
'resources.table.hostname': 'Hostname',
|
||||
'resources.table.ip': 'IP',
|
||||
'resources.table.cpu': 'CPU',
|
||||
'resources.table.memory': 'Memory',
|
||||
'resources.table.gpu': 'GPU',
|
||||
'resources.table.disk': 'Storage',
|
||||
'resources.table.vram': 'VRAM'
|
||||
};
|
||||
@@ -1,9 +1,13 @@
|
||||
import menu from './en-US/menu';
|
||||
import common from './zh-CN/common';
|
||||
import models from './zh-CN/models';
|
||||
import playground from './zh-CN/playground';
|
||||
import resources from './zh-CN/resources';
|
||||
|
||||
export default {
|
||||
...common,
|
||||
...menu,
|
||||
...models
|
||||
...models,
|
||||
...playground,
|
||||
...resources
|
||||
};
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
'apikeys.title': 'API 密钥',
|
||||
'apikeys.button.create': '新建 API 密钥',
|
||||
'apikeys.form.expiretime': '过期时间'
|
||||
};
|
||||
@@ -40,6 +40,7 @@ export default {
|
||||
'common.button.edit': '编辑',
|
||||
'common.button.authorize': '角色授权',
|
||||
'common.button.confirm': '确定',
|
||||
'common.button.viewlog': '查看日志',
|
||||
'common.table.operation': '操作',
|
||||
'common.table.createTime': '创建时间',
|
||||
'common.table.updateTime': '更新时间',
|
||||
@@ -170,5 +171,8 @@ export default {
|
||||
'common.nodata.added': '尚未添加{type}',
|
||||
'common.status.edited': '已编辑',
|
||||
'common.table.user': '用户',
|
||||
'common.settings.instructions': '操作指引'
|
||||
'common.settings.instructions': '操作指引',
|
||||
'common.settings.language': '语言',
|
||||
'common.delete.confirm': '确定删除选中的{type}吗?',
|
||||
'common.filter.name': '名称查询'
|
||||
};
|
||||
|
||||
@@ -1 +1,10 @@
|
||||
export default {};
|
||||
export default {
|
||||
'menu.dashboard': '概览',
|
||||
'menu.playground': '对话',
|
||||
'menu.models': '模型',
|
||||
'menu.resources': '资源',
|
||||
'menu.apikeys': 'API 密钥',
|
||||
'menu.users': '用户',
|
||||
'menu.profile': '个人信息',
|
||||
'menu.login': '登录'
|
||||
};
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
export default {
|
||||
'models.button.deploy': 'Deploy Model'
|
||||
'models.button.deploy': '部署模型',
|
||||
'models.title': '模型',
|
||||
'models.table.models': '模型',
|
||||
'models.table.name': '模型名称',
|
||||
'models.form.source': '来源',
|
||||
'models.form.repoid': '仓库 ID',
|
||||
'models.form.repoid.desc': '只支持 .gguf 格式',
|
||||
'models.form.filename': '文件名',
|
||||
'models.form.replicas': '副本数',
|
||||
'models.form.s3address': 'S3 地址',
|
||||
'models.openinplayground': '在 Playground 中打开',
|
||||
'models.instances': '实例'
|
||||
};
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
export default {
|
||||
'playground.system.tips': '在这里输入系统消息...',
|
||||
'playground.title': '对话',
|
||||
'playground.system': '系统',
|
||||
'playground.user': '用户',
|
||||
'playground.assistant': '助手',
|
||||
'playground.newMessage': '新消息',
|
||||
'playground.viewcode': '查看代码',
|
||||
'playground.model': '模型',
|
||||
'playground.parameters': '参数',
|
||||
'playground.viewcode.info':
|
||||
'你可以使用以下代码将当前的提示和设置集成到你的应用程序中。',
|
||||
'playground.completion': '补全',
|
||||
'playground.prompt': '提示',
|
||||
'playground.tokenusage': 'Token 使用量'
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export default {
|
||||
'resources.title': '资源',
|
||||
'resources.nodes': '节点',
|
||||
'resources.table.hostname': '主机名',
|
||||
'resources.table.ip': 'IP',
|
||||
'resources.table.cpu': 'CPU',
|
||||
'resources.table.memory': '内存',
|
||||
'resources.table.gpu': 'GPU',
|
||||
'resources.table.disk': '磁盘',
|
||||
'resources.table.vram': '显存'
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { request } from '@umijs/max';
|
||||
import { FormData, ListItem } from '../config/types';
|
||||
|
||||
export const APIS_KEYS_API = '/api_keys';
|
||||
export const APIS_KEYS_API = '/api-keys';
|
||||
|
||||
export async function queryApisKeysList(
|
||||
params: Global.Pagination & { query?: string }
|
||||
|
||||
@@ -27,37 +27,6 @@ import { FormData, ListItem } from './config/types';
|
||||
|
||||
const { Column } = Table;
|
||||
|
||||
const list = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'local',
|
||||
secretKey: `auk_uzem...owsa`,
|
||||
lastusedTime: '2024-05-22 12:20:10',
|
||||
createTime: '2024-05-20 12:13:25'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'dev',
|
||||
secretKey: `auk_uzem...okwa`,
|
||||
lastusedTime: '2024-05-19 13:30:22',
|
||||
createTime: '2024-05-18 10:28:32'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'prod',
|
||||
secretKey: `auk_uzem...uuds`,
|
||||
lastusedTime: '2024-05-18 10:28:32',
|
||||
createTime: '2024-05-17 08:21:09'
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: 'test',
|
||||
secretKey: `auk_uzem...uksa`,
|
||||
lastusedTime: '2024-05-18 10:28:32',
|
||||
createTime: '2024-05-16 13:33:23'
|
||||
}
|
||||
];
|
||||
|
||||
const Models: React.FC = () => {
|
||||
const rowSelection = useTableRowSelection();
|
||||
const { sortOrder, setSortOrder } = useTableSort({
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
|
||||
export const MODELS_API = '/models';
|
||||
|
||||
export const MODEL_INSTANCE_API = '/model_instances';
|
||||
export const MODEL_INSTANCE_API = '/model-instances';
|
||||
|
||||
// ===================== Models =====================
|
||||
export async function queryModelsList(
|
||||
|
||||
@@ -5,6 +5,7 @@ import SealSelect from '@/components/seal-form/seal-select';
|
||||
import { PageAction } from '@/config';
|
||||
import { PageActionType } from '@/config/types';
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Form, Input, Modal } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -31,6 +32,7 @@ const sourceOptions = [
|
||||
const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
const { title, action, open, onOk, onCancel } = props || {};
|
||||
const [form] = Form.useForm();
|
||||
const intl = useIntl();
|
||||
const modelSource = Form.useWatch('source', form);
|
||||
const [repoOptions, setRepoOptions] = useState<
|
||||
{ label: string; value: string }[]
|
||||
@@ -42,7 +44,8 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
const initFormValue = () => {
|
||||
if (action === PageAction.CREATE && open) {
|
||||
form.setFieldsValue({
|
||||
source: 'huggingface'
|
||||
source: 'huggingface',
|
||||
replicas: 1
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -51,9 +54,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
initFormValue();
|
||||
}, [open]);
|
||||
|
||||
const handleInputRepoChange = (value: string) => {
|
||||
console.log('repo change', value);
|
||||
};
|
||||
const handleInputRepoChange = (value: string) => {};
|
||||
|
||||
const fileNamLabel = (item: any) => {
|
||||
return (
|
||||
@@ -87,7 +88,6 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
|
||||
const handleRepoOnBlur = (e: any) => {
|
||||
const repo = form.getFieldValue('huggingface_repo_id');
|
||||
console.log('repo blur', repo);
|
||||
handleRepoSelect(repo);
|
||||
};
|
||||
|
||||
@@ -119,28 +119,48 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
name="huggingface_repo_id"
|
||||
rules={[{ required: true }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.form.repoid' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealAutoComplete
|
||||
label="Repo ID"
|
||||
label={intl.formatMessage({ id: 'models.form.repoid' })}
|
||||
required
|
||||
showSearch
|
||||
onBlur={handleRepoOnBlur}
|
||||
onChange={handleInputRepoChange}
|
||||
onSearch={debounceSearch}
|
||||
options={repoOptions}
|
||||
description="Only .gguf format is supported"
|
||||
description={intl.formatMessage({ id: 'models.form.repoid.desc' })}
|
||||
>
|
||||
<Input.Search style={{ width: '520px' }}></Input.Search>
|
||||
</SealAutoComplete>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData>
|
||||
name="huggingface_filename"
|
||||
rules={[{ required: true }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.form.filename' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealAutoComplete
|
||||
showSearch
|
||||
label="File Name"
|
||||
label={intl.formatMessage({ id: 'models.form.filename' })}
|
||||
required
|
||||
options={fileOptions}
|
||||
></SealAutoComplete>
|
||||
@@ -152,8 +172,26 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
const renderS3Fields = () => {
|
||||
return (
|
||||
<>
|
||||
<Form.Item<FormData> name="s3_address" rules={[{ required: true }]}>
|
||||
<SealInput.Input label="S3 Address" required></SealInput.Input>
|
||||
<Form.Item<FormData>
|
||||
name="s3_address"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.form.s3address' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.s3address'
|
||||
})}
|
||||
required
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
@@ -164,9 +202,22 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
<>
|
||||
<Form.Item<FormData>
|
||||
name="ollama_library_model_name"
|
||||
rules={[{ required: true }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.table.name' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Input label="Model Name" required></SealInput.Input>
|
||||
<SealInput.Input
|
||||
label={intl.formatMessage({ id: 'models.table.name' })}
|
||||
required
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
@@ -212,28 +263,80 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
||||
}
|
||||
>
|
||||
<Form name="addModalForm" form={form} onFinish={onOk} preserve={false}>
|
||||
<Form.Item<FormData> name="name" rules={[{ required: true }]}>
|
||||
<SealInput.Input label="Name" required></SealInput.Input>
|
||||
<Form.Item<FormData>
|
||||
name="name"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'common.table.name' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Input
|
||||
label={intl.formatMessage({
|
||||
id: 'common.table.name'
|
||||
})}
|
||||
required
|
||||
></SealInput.Input>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> name="source" rules={[{ required: true }]}>
|
||||
<Form.Item<FormData>
|
||||
name="source"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.select'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.form.source' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealSelect
|
||||
label="Source"
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.source'
|
||||
})}
|
||||
options={sourceOptions}
|
||||
required
|
||||
onChange={handleSourceChange}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
{renderFieldsBySource()}
|
||||
<Form.Item<FormData> name="replicas" rules={[{ required: true }]}>
|
||||
<Form.Item<FormData>
|
||||
name="replicas"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
id: 'common.form.rule.input'
|
||||
},
|
||||
{ name: intl.formatMessage({ id: 'models.form.replicas' }) }
|
||||
)
|
||||
}
|
||||
]}
|
||||
>
|
||||
<SealInput.Number
|
||||
style={{ width: '100%' }}
|
||||
label="Replicas"
|
||||
label={intl.formatMessage({
|
||||
id: 'models.form.replicas'
|
||||
})}
|
||||
required
|
||||
min={1}
|
||||
></SealInput.Number>
|
||||
</Form.Item>
|
||||
<Form.Item<FormData> name="description">
|
||||
<SealInput.TextArea label="Description"></SealInput.TextArea>
|
||||
<SealInput.TextArea
|
||||
label={intl.formatMessage({
|
||||
id: 'common.table.description'
|
||||
})}
|
||||
></SealInput.TextArea>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -178,7 +178,6 @@ const Models: React.FC = () => {
|
||||
const handleAddModal = () => {
|
||||
setOpenAddModal(true);
|
||||
setAction(PageAction.CREATE);
|
||||
setTitle('Deploy Model');
|
||||
};
|
||||
|
||||
const handleClickMenu = (e: any) => {
|
||||
@@ -186,10 +185,9 @@ const Models: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleModalOk = async (data: FormData) => {
|
||||
console.log('handleModalOk', data);
|
||||
await createModel({ data });
|
||||
setOpenAddModal(false);
|
||||
message.success('successfully!');
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
};
|
||||
|
||||
const handleModalCancel = () => {
|
||||
@@ -203,10 +201,13 @@ const Models: React.FC = () => {
|
||||
const handleDelete = async (row: any) => {
|
||||
Modal.confirm({
|
||||
title: '',
|
||||
content: 'Are you sure you want to delete the selected models?',
|
||||
content: intl.formatMessage(
|
||||
{ id: 'common.delete.confirm' },
|
||||
{ type: intl.formatMessage({ id: 'models.table.models' }) }
|
||||
),
|
||||
async onOk() {
|
||||
await deleteModel(row.id);
|
||||
message.success('successfully!');
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
fetchData();
|
||||
},
|
||||
onCancel() {
|
||||
@@ -217,10 +218,13 @@ const Models: React.FC = () => {
|
||||
const handleDeleteBatch = () => {
|
||||
Modal.confirm({
|
||||
title: '',
|
||||
content: 'Are you sure you want to delete the selected models?',
|
||||
content: intl.formatMessage(
|
||||
{ id: 'common.delete.confirm' },
|
||||
{ type: intl.formatMessage({ id: 'models.table.models' }) }
|
||||
),
|
||||
async onOk() {
|
||||
await handleBatchRequest(rowSelection.selectedRowKeys, deleteModel);
|
||||
message.success('successfully!');
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
fetchData();
|
||||
},
|
||||
onCancel() {
|
||||
@@ -244,7 +248,7 @@ const Models: React.FC = () => {
|
||||
source: row.source
|
||||
};
|
||||
await createModelInstance({ data });
|
||||
message.success('successfully!');
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
@@ -258,11 +262,13 @@ const Models: React.FC = () => {
|
||||
const handleDeleteInstace = (row: any) => {
|
||||
Modal.confirm({
|
||||
title: '',
|
||||
content: 'Are you sure you want to delete the instance?',
|
||||
content: intl.formatMessage(
|
||||
{ id: 'common.delete.confirm' },
|
||||
{ type: intl.formatMessage({ id: 'models.instances' }) }
|
||||
),
|
||||
async onOk() {
|
||||
console.log('OK');
|
||||
await deleteModelInstance(row.id);
|
||||
message.success('successfully!');
|
||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
||||
fetchData();
|
||||
},
|
||||
onCancel() {
|
||||
@@ -343,7 +349,11 @@ const Models: React.FC = () => {
|
||||
<Col span={7}>
|
||||
{hoverChildIndex === `${item.id}-${index}` && (
|
||||
<Space size={20}>
|
||||
<Tooltip title="Delete">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'common.button.delete'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
danger
|
||||
@@ -351,7 +361,11 @@ const Models: React.FC = () => {
|
||||
icon={<DeleteOutlined></DeleteOutlined>}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="View Logs">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'common.button.viewlog'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => handleViewLogs(item)}
|
||||
@@ -375,7 +389,7 @@ const Models: React.FC = () => {
|
||||
<PageContainer
|
||||
ghost
|
||||
header={{
|
||||
title: 'Models'
|
||||
title: intl.formatMessage({ id: 'models.title' })
|
||||
}}
|
||||
extra={[]}
|
||||
>
|
||||
@@ -384,7 +398,7 @@ const Models: React.FC = () => {
|
||||
left={
|
||||
<Space>
|
||||
<Input
|
||||
placeholder="名称查询"
|
||||
placeholder={intl.formatMessage({ id: 'common.filter.name' })}
|
||||
style={{ width: 300 }}
|
||||
allowClear
|
||||
onChange={handleNameChange}
|
||||
@@ -413,7 +427,7 @@ const Models: React.FC = () => {
|
||||
onClick={handleDeleteBatch}
|
||||
disabled={!rowSelection.selectedRowKeys.length}
|
||||
>
|
||||
Delete
|
||||
{intl?.formatMessage?.({ id: 'common.button.delete' })}
|
||||
</Button>
|
||||
</Access>
|
||||
</Space>
|
||||
@@ -440,7 +454,7 @@ const Models: React.FC = () => {
|
||||
}}
|
||||
>
|
||||
<SealColumn
|
||||
title="Model Name"
|
||||
title={intl.formatMessage({ id: 'models.table.name' })}
|
||||
dataIndex="name"
|
||||
key="name"
|
||||
width={400}
|
||||
@@ -461,7 +475,7 @@ const Models: React.FC = () => {
|
||||
/>
|
||||
<SealColumn
|
||||
span={8}
|
||||
title="Create Time"
|
||||
title={intl.formatMessage({ id: 'common.table.createTime' })}
|
||||
dataIndex="created_at"
|
||||
key="createTime"
|
||||
defaultSortOrder="descend"
|
||||
@@ -474,12 +488,16 @@ const Models: React.FC = () => {
|
||||
/>
|
||||
<SealColumn
|
||||
span={8}
|
||||
title="Operation"
|
||||
title={intl.formatMessage({ id: 'common.table.operation' })}
|
||||
key="operation"
|
||||
render={(text, record) => {
|
||||
return !record.transition ? (
|
||||
<Space size={20}>
|
||||
<Tooltip title="Open in PlayGround">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({
|
||||
id: 'models.openinplayground'
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
@@ -487,7 +505,9 @@ const Models: React.FC = () => {
|
||||
icon={<WechatWorkOutlined />}
|
||||
></Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Delete">
|
||||
<Tooltip
|
||||
title={intl.formatMessage({ id: 'common.button.delete' })}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="primary"
|
||||
@@ -505,12 +525,12 @@ const Models: React.FC = () => {
|
||||
<AddModal
|
||||
open={openAddModal}
|
||||
action={action}
|
||||
title={title}
|
||||
title={intl.formatMessage({ id: 'models.button.deploy' })}
|
||||
onCancel={handleModalCancel}
|
||||
onOk={handleModalOk}
|
||||
></AddModal>
|
||||
<ViewLogsModal
|
||||
title="View Logs"
|
||||
title={intl.formatMessage({ id: 'common.button.viewlog' })}
|
||||
open={openLogModal}
|
||||
onCancel={handleLogModalCancel}
|
||||
></ViewLogsModal>
|
||||
|
||||
@@ -63,7 +63,7 @@ const Login = () => {
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
style={{ width: '400px', margin: '5% auto 0' }}
|
||||
style={{ width: '400px', margin: '0 auto', paddingTop: '5%' }}
|
||||
onFinish={handleLogin}
|
||||
>
|
||||
<div>{renderLogo()}</div>
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
PlusOutlined,
|
||||
SaveOutlined
|
||||
} from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Col, Row, Space } from 'antd';
|
||||
import '../style/chat-footer.less';
|
||||
|
||||
@@ -17,6 +18,7 @@ interface ChatFooterProps {
|
||||
}
|
||||
|
||||
const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
||||
const intl = useIntl();
|
||||
const { onSubmit, onClear, onNewMessage, onView, feedback, disabled } = props;
|
||||
return (
|
||||
<div className="chat-footer">
|
||||
@@ -29,14 +31,14 @@ const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
||||
icon={<PlusOutlined />}
|
||||
onClick={onNewMessage}
|
||||
>
|
||||
New Message
|
||||
{intl.formatMessage({ id: 'playground.newMessage' })}
|
||||
</Button>
|
||||
<Button
|
||||
icon={<DeleteOutlined></DeleteOutlined>}
|
||||
onClick={onClear}
|
||||
disabled={disabled}
|
||||
>
|
||||
Clear
|
||||
{intl.formatMessage({ id: 'common.button.clear' })}
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
@@ -48,7 +50,7 @@ const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
||||
onClick={onView}
|
||||
disabled={disabled}
|
||||
>
|
||||
View Code
|
||||
{intl.formatMessage({ id: 'playground.viewcode' })}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={disabled}
|
||||
@@ -56,7 +58,7 @@ const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
||||
icon={<SaveOutlined></SaveOutlined>}
|
||||
onClick={onSubmit}
|
||||
>
|
||||
Submit
|
||||
{intl.formatMessage({ id: 'common.button.submit' })}
|
||||
</Button>
|
||||
</Space>
|
||||
</Col>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import TransitionWrapper from '@/components/transition';
|
||||
import { EyeInvisibleOutlined } from '@ant-design/icons';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Input, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useRef, useState } from 'react';
|
||||
@@ -34,6 +35,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
|
||||
}
|
||||
]);
|
||||
|
||||
const intl = useIntl();
|
||||
const [systemMessage, setSystemMessage] = useState('');
|
||||
const [show, setShow] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -73,7 +75,8 @@ const MessageList: React.FC<MessageProps> = (props) => {
|
||||
...messageList
|
||||
]
|
||||
: [...messageList],
|
||||
...parameters
|
||||
...parameters,
|
||||
stream: true
|
||||
};
|
||||
const data = await execChatCompletions(chatParams);
|
||||
const assistant = _.get(data, ['choices', '0', 'message']);
|
||||
@@ -118,14 +121,15 @@ const MessageList: React.FC<MessageProps> = (props) => {
|
||||
|
||||
const handleUpdateMessage = (index: number, message: MessageItemProps) => {
|
||||
messageList[index] = message;
|
||||
console.log('updatemessage========', index, message);
|
||||
setMessageList([...messageList]);
|
||||
};
|
||||
|
||||
const renderLabel = () => {
|
||||
return (
|
||||
<div className="system-message-wrap ">
|
||||
<span className="title">System</span>
|
||||
<span className="title">
|
||||
{intl.formatMessage({ id: 'playground.system' })}
|
||||
</span>
|
||||
<Button type="primary" size="small">
|
||||
<EyeInvisibleOutlined />
|
||||
</Button>
|
||||
@@ -145,7 +149,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
|
||||
value={systemMessage}
|
||||
variant="filled"
|
||||
autoSize={true}
|
||||
placeholder="Enter system message here..."
|
||||
placeholder={intl.formatMessage({ id: 'playground.system.tips' })}
|
||||
onChange={handleSystemMessageChange}
|
||||
></Input.TextArea>
|
||||
</TransitionWrapper>
|
||||
@@ -193,9 +197,9 @@ const MessageList: React.FC<MessageProps> = (props) => {
|
||||
open={show}
|
||||
systemMessage={systemMessage}
|
||||
messageList={messageList}
|
||||
parameters={parameters}
|
||||
parameters={{ ...parameters, stream: true }}
|
||||
onCancel={handleCloseViewCode}
|
||||
title="View code"
|
||||
title={intl.formatMessage({ id: 'playground.viewcode' })}
|
||||
></ViewCodeModal>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MinusCircleOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Input } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { memo, useEffect, useRef, useState } from 'react';
|
||||
import { Roles } from '../config';
|
||||
import '../style/message-item.less';
|
||||
@@ -18,6 +18,7 @@ const MessageItem: React.FC<{
|
||||
isFocus: boolean;
|
||||
onDelete: () => void;
|
||||
}> = ({ message, isFocus, onDelete, updateMessage }) => {
|
||||
const intl = useIntl();
|
||||
const [roleType, setRoleType] = useState(message.role);
|
||||
const [isTyping, setIsTyping] = useState(false);
|
||||
const [messageContent, setMessageContent] = useState(message.content);
|
||||
@@ -87,7 +88,7 @@ const MessageItem: React.FC<{
|
||||
<div className="message-item">
|
||||
<div className="role-type">
|
||||
<Button onClick={handleRoleChange} type="text">
|
||||
{_.upperFirst(roleType)}
|
||||
{intl.formatMessage({ id: `playground.${roleType}` })}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="message-content-input">
|
||||
|
||||
@@ -3,6 +3,7 @@ import SealInput from '@/components/seal-form/seal-input';
|
||||
import SealSelect from '@/components/seal-form/seal-select';
|
||||
import { INPUT_WIDTH } from '@/constants';
|
||||
import { queryModelsList } from '@/pages/llmodels/apis';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Form, InputNumber, Slider } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -29,6 +30,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
||||
selectedModel,
|
||||
setParams
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const [ModelList, setModelList] = useState([]);
|
||||
const initialValues = {
|
||||
seed: null,
|
||||
@@ -137,17 +139,22 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
||||
onFinishFailed={handleOnFinishFailed}
|
||||
>
|
||||
<div>
|
||||
<h3 className="m-b-20 m-l-10">Model</h3>
|
||||
<h3 className="m-b-20 m-l-10">
|
||||
{intl.formatMessage({ id: 'playground.model' })}
|
||||
</h3>
|
||||
<Form.Item<ParamsSettingsFormProps>
|
||||
name="model"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<SealSelect options={ModelList} label="Model"></SealSelect>
|
||||
<SealSelect
|
||||
options={ModelList}
|
||||
label={intl.formatMessage({ id: 'playground.model' })}
|
||||
></SealSelect>
|
||||
</Form.Item>
|
||||
<h3 className="m-b-20 m-l-10 flex-between flex-center">
|
||||
<span>Parameters</span>
|
||||
<span>{intl.formatMessage({ id: 'playground.parameters' })}</span>
|
||||
<Button size="small" onClick={handleResetParams}>
|
||||
Reset
|
||||
{intl.formatMessage({ id: 'common.button.reset' })}
|
||||
</Button>
|
||||
</h3>
|
||||
<Form.Item<ParamsSettingsFormProps>
|
||||
@@ -195,10 +202,6 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
||||
onChange={(val) => handleFieldValueChange(val, 'max_tokens')}
|
||||
></Slider>
|
||||
</FieldWrapper>
|
||||
{/* <SealInput.Number
|
||||
label="Max Tokens"
|
||||
style={{ width: INPUT_WIDTH.mini }}
|
||||
></SealInput.Number> */}
|
||||
</Form.Item>
|
||||
<Form.Item<ParamsSettingsFormProps>
|
||||
name="top_p"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Space, Tooltip } from 'antd';
|
||||
import '../style/reference-params.less';
|
||||
|
||||
@@ -10,6 +11,7 @@ interface ReferenceParamsProps {
|
||||
}
|
||||
|
||||
const ReferenceParams = (props: ReferenceParamsProps) => {
|
||||
const intl = useIntl();
|
||||
const { usage } = props;
|
||||
if (!usage) {
|
||||
return null;
|
||||
@@ -19,12 +21,21 @@ const ReferenceParams = (props: ReferenceParamsProps) => {
|
||||
<Tooltip
|
||||
title={
|
||||
<Space>
|
||||
<span>Completion: {usage.completion_tokens}</span>
|
||||
<span>Prompt: {usage.prompt_tokens}</span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'playground.completion' })}:{' '}
|
||||
{usage.completion_tokens}
|
||||
</span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'playground.prompt' })}:{' '}
|
||||
{usage.prompt_tokens}
|
||||
</span>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<span>Token Usage: {usage.total_tokens}</span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'playground.tokenusage' })}:{' '}
|
||||
{usage.total_tokens}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import EditorWrap from '@/components/editor-wrap';
|
||||
import Editor from '@monaco-editor/react';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Modal, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
@@ -23,6 +24,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
parameters = {}
|
||||
} = props || {};
|
||||
|
||||
const intl = useIntl();
|
||||
const editorRef = useRef(null);
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
const [codeValue, setCodeValue] = useState('');
|
||||
@@ -34,16 +36,24 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
{ label: 'Nodejs', value: 'javascript' }
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
generateCode();
|
||||
}, [lang, systemMessage, messageList, parameters]);
|
||||
|
||||
const formatCode = () => {
|
||||
if (editorRef.current) {
|
||||
setTimeout(() => {
|
||||
editorRef.current
|
||||
?.getAction?.('editor.action.formatDocument')
|
||||
?.run()
|
||||
.then(() => {
|
||||
console.log('format success');
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
};
|
||||
const generateCode = () => {
|
||||
if (lang === 'shell') {
|
||||
const systemList = systemMessage
|
||||
? [{ role: 'system', content: systemMessage }]
|
||||
: [];
|
||||
const code = `curl ${window.location.origin}/v1/chat/completions \n-H "Content-Type: application/json" \n-H "Authorization: Bearer $\{GPUSTACK_API_KEY}\" \n-d '${JSON.stringify(
|
||||
const code = `curl ${window.location.origin}/v1/chat/completions \n-H "Content-Type: application/json" \n-H "Authorization: Bearer $\{GPUSTACK_API_KEY}" \n-d '${JSON.stringify(
|
||||
{
|
||||
...parameters,
|
||||
messages: [...systemList, ...messageList]
|
||||
@@ -92,19 +102,6 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
setLoaded(true);
|
||||
};
|
||||
|
||||
function formatCode() {
|
||||
if (editorRef.current) {
|
||||
setTimeout(() => {
|
||||
editorRef.current
|
||||
?.getAction?.('editor.action.formatDocument')
|
||||
?.run()
|
||||
.then(() => {
|
||||
console.log('format success');
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
const handleOnChangeLang = (value: string) => {
|
||||
setLang(value);
|
||||
};
|
||||
@@ -124,6 +121,10 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
generateCode();
|
||||
}, [lang, systemMessage, messageList, parameters]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
@@ -139,8 +140,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
footer={null}
|
||||
>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
You can use the following code to start integrating your current
|
||||
prompt and settings into your application.
|
||||
{intl.formatMessage({ id: 'playground.viewcode.info' })}
|
||||
</div>
|
||||
<Spin spinning={!loaded}>
|
||||
<EditorWrap
|
||||
@@ -162,10 +162,6 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
|
||||
/>
|
||||
</EditorWrap>
|
||||
</Spin>
|
||||
<div style={{ marginTop: '10px' }}>
|
||||
our API Key can be foundhere You should use environment variables or a
|
||||
secret management tool to expose your key to your applications.
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -5,10 +5,10 @@ export const Roles = {
|
||||
export const playGroundRoles = [
|
||||
{
|
||||
key: 'user',
|
||||
label: 'User'
|
||||
label: 'playground.user'
|
||||
},
|
||||
{
|
||||
key: 'assistant',
|
||||
label: 'Assistant'
|
||||
label: 'playground.assitant'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -4,6 +4,7 @@ import StatusTag from '@/components/status-tag';
|
||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||
import useTableSort from '@/hooks/use-table-sort';
|
||||
import { SyncOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Input, Space, Table } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
@@ -16,6 +17,7 @@ const Models: React.FC = () => {
|
||||
const { sortOrder, setSortOrder } = useTableSort({
|
||||
defaultSortOrder: 'descend'
|
||||
});
|
||||
const intl = useIntl();
|
||||
const [total, setTotal] = useState(0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dataSource, setDataSource] = useState<ListItem[]>([]);
|
||||
@@ -86,7 +88,9 @@ const Models: React.FC = () => {
|
||||
left={
|
||||
<Space>
|
||||
<Input
|
||||
placeholder="名称查询"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'common.filter.name'
|
||||
})}
|
||||
style={{ width: 300 }}
|
||||
onChange={handleNameChange}
|
||||
></Input>
|
||||
@@ -114,9 +118,13 @@ const Models: React.FC = () => {
|
||||
onChange: handlePageChange
|
||||
}}
|
||||
>
|
||||
<Column title="Host Name" dataIndex="hostname" key="hostname" />
|
||||
<Column
|
||||
title="State"
|
||||
title={intl.formatMessage({ id: 'resources.table.hostname' })}
|
||||
dataIndex="hostname"
|
||||
key="hostname"
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'common.table.status' })}
|
||||
dataIndex="state"
|
||||
key="state"
|
||||
render={(text, record: ListItem) => {
|
||||
@@ -145,7 +153,7 @@ const Models: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title="Memory"
|
||||
title={intl.formatMessage({ id: 'resources.table.memory' })}
|
||||
dataIndex="memory"
|
||||
key="Memory"
|
||||
render={(text, record: ListItem) => {
|
||||
@@ -177,7 +185,15 @@ const Models: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title="VRAM"
|
||||
title={intl.formatMessage({ id: 'resources.table.disk' })}
|
||||
dataIndex="storage"
|
||||
key="storage"
|
||||
render={(text, record: ListItem) => {
|
||||
return <ProgressBar percent={0}></ProgressBar>;
|
||||
}}
|
||||
/>
|
||||
<Column
|
||||
title={intl.formatMessage({ id: 'resources.table.vram' })}
|
||||
dataIndex="VRAM"
|
||||
key="VRAM"
|
||||
render={(text, record: ListItem) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import type { TabsProps } from 'antd';
|
||||
import { Tabs } from 'antd';
|
||||
import { useState } from 'react';
|
||||
@@ -20,6 +21,8 @@ const items: TabsProps['items'] = [
|
||||
const Resources = () => {
|
||||
const [activeKey, setActiveKey] = useState('test');
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const handleChangeTab = (key: string) => {
|
||||
setActiveKey(key);
|
||||
};
|
||||
@@ -28,7 +31,7 @@ const Resources = () => {
|
||||
<PageContainer
|
||||
ghost
|
||||
header={{
|
||||
title: 'Resources'
|
||||
title: intl.formatMessage({ id: 'resources.title' })
|
||||
}}
|
||||
extra={[]}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user