chore: playground api request
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import '../styles/row-children.less';
|
||||||
|
|
||||||
|
const RowChildren = (props: any) => {
|
||||||
|
const { children } = props;
|
||||||
|
return <div className="row-children">{children}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(RowChildren);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
import { DownOutlined, RightOutlined } from '@ant-design/icons';
|
||||||
import { Button, Checkbox, Col, Row } from 'antd';
|
import { Button, Checkbox, Col, Empty, Row, Spin } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
@@ -17,11 +17,15 @@ const TableRow: React.FC<
|
|||||||
rowSelection,
|
rowSelection,
|
||||||
rowKey,
|
rowKey,
|
||||||
columns,
|
columns,
|
||||||
onExpand
|
onExpand,
|
||||||
|
renderChildren,
|
||||||
|
loadChildren
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
const [checked, setChecked] = useState(false);
|
const [checked, setChecked] = useState(false);
|
||||||
|
const [childrenData, setChildrenData] = useState<any[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (rowSelection) {
|
if (rowSelection) {
|
||||||
@@ -34,9 +38,18 @@ const TableRow: React.FC<
|
|||||||
}
|
}
|
||||||
}, [rowSelection]);
|
}, [rowSelection]);
|
||||||
|
|
||||||
const handleRowExpand = () => {
|
const handleRowExpand = async () => {
|
||||||
setExpanded(!expanded);
|
try {
|
||||||
onExpand?.(!expanded, record);
|
setExpanded(!expanded);
|
||||||
|
onExpand?.(!expanded, record);
|
||||||
|
setLoading(true);
|
||||||
|
const data = await loadChildren?.(record);
|
||||||
|
setChildrenData(data || []);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setChildrenData([]);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectChange = (e: any) => {
|
const handleSelectChange = (e: any) => {
|
||||||
@@ -126,7 +139,13 @@ const TableRow: React.FC<
|
|||||||
</div>
|
</div>
|
||||||
{expanded && (
|
{expanded && (
|
||||||
<div className="expanded-row">
|
<div className="expanded-row">
|
||||||
<div className="expanded-row-content">rowchildren</div>
|
<Spin spinning={loading}>
|
||||||
|
{childrenData.length ? (
|
||||||
|
renderChildren?.(childrenData)
|
||||||
|
) : (
|
||||||
|
<Empty></Empty>
|
||||||
|
)}
|
||||||
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ import './styles/index.less';
|
|||||||
import { SealColumnProps, SealTableProps } from './types';
|
import { SealColumnProps, SealTableProps } from './types';
|
||||||
|
|
||||||
const SealTable: React.FC<SealTableProps> = (props) => {
|
const SealTable: React.FC<SealTableProps> = (props) => {
|
||||||
const { children, rowKey, onExpand, loading, expandable, rowSelection } =
|
const {
|
||||||
props;
|
children,
|
||||||
|
rowKey,
|
||||||
|
onExpand,
|
||||||
|
loading,
|
||||||
|
expandable,
|
||||||
|
rowSelection,
|
||||||
|
renderChildren,
|
||||||
|
loadChildren
|
||||||
|
} = props;
|
||||||
|
|
||||||
const [selectAll, setSelectAll] = useState(false);
|
const [selectAll, setSelectAll] = useState(false);
|
||||||
const [indeterminate, setIndeterminate] = useState(false);
|
const [indeterminate, setIndeterminate] = useState(false);
|
||||||
@@ -121,6 +129,8 @@ const SealTable: React.FC<SealTableProps> = (props) => {
|
|||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
expandable={expandable}
|
expandable={expandable}
|
||||||
rowKey={rowKey}
|
rowKey={rowKey}
|
||||||
|
renderChildren={renderChildren}
|
||||||
|
loadChildren={loadChildren}
|
||||||
onExpand={onExpand}
|
onExpand={onExpand}
|
||||||
></TableRow>
|
></TableRow>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
}
|
}
|
||||||
.expanded-row {
|
.expanded-row {
|
||||||
background-color: var(--color-white-1);
|
background-color: var(--color-white-1);
|
||||||
padding: 16px 20px;
|
padding: 16px 16px;
|
||||||
border: 1px solid var(--color-fill-1);
|
border: 1px solid var(--color-fill-1);
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
border-radius: 0 0 var(--ant-table-header-border-radius)
|
border-radius: 0 0 var(--ant-table-header-border-radius)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
.row-children {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 54px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-radius: var(--ant-table-header-border-radius);
|
||||||
|
background-color: var(--color-fill-1);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--ant-table-row-hover-bg);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ export interface SealTableProps {
|
|||||||
dataSource: any[];
|
dataSource: any[];
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
onExpand?: (expanded: boolean, record: any) => void;
|
onExpand?: (expanded: boolean, record: any) => void;
|
||||||
|
renderChildren?: (data: any) => React.ReactNode;
|
||||||
|
loadChildren?: (record: any) => Promise<any[]>;
|
||||||
rowKey: string;
|
rowKey: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
const TypingEffect: React.FC<{ text?: string }> = ({ text = '' }) => {
|
||||||
|
const [displayedText, setDisplayedText] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let index = 0;
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
setDisplayedText((prev) => prev + text[index]);
|
||||||
|
index += 1;
|
||||||
|
if (index === text.length) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, [text]);
|
||||||
|
|
||||||
|
return <div>{displayedText}</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TypingEffect;
|
||||||
Vendored
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
declare namespace Global {
|
declare namespace Global {
|
||||||
interface Pagination {
|
interface Pagination {
|
||||||
page: number;
|
page: number;
|
||||||
perPage: number;
|
perPage?: number;
|
||||||
watch?: boolean;
|
watch?: boolean;
|
||||||
}
|
}
|
||||||
interface PageResponse<T> {
|
interface PageResponse<T> {
|
||||||
|
|||||||
@@ -29,3 +29,11 @@ export const StatusColorMap: Record<StatusType, { text: string; bg: string }> =
|
|||||||
bg: `var(--ant-color-fill)`
|
bg: `var(--ant-color-fill)`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const StatusMaps = {
|
||||||
|
error: 'error',
|
||||||
|
warning: 'warning',
|
||||||
|
transitioning: 'transitioning',
|
||||||
|
success: 'success',
|
||||||
|
inactive: 'inactive'
|
||||||
|
};
|
||||||
|
|||||||
@@ -164,12 +164,21 @@ const Models: React.FC = () => {
|
|||||||
dataIndex="GPU"
|
dataIndex="GPU"
|
||||||
key="GPU"
|
key="GPU"
|
||||||
render={(text, record: ListItem) => {
|
render={(text, record: ListItem) => {
|
||||||
return <RenderProgress percent={0}></RenderProgress>;
|
return (
|
||||||
|
<RenderProgress
|
||||||
|
percent={_.get(record, [
|
||||||
|
'status',
|
||||||
|
'gpu',
|
||||||
|
'0',
|
||||||
|
'core_utilization_rate'
|
||||||
|
])}
|
||||||
|
></RenderProgress>
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Column
|
<Column
|
||||||
title="VRAM"
|
title="VRAM"
|
||||||
dataIndex="GRAM"
|
dataIndex="VRAM"
|
||||||
key="VRAM"
|
key="VRAM"
|
||||||
render={(text, record: ListItem) => {
|
render={(text, record: ListItem) => {
|
||||||
return <RenderProgress percent={0}></RenderProgress>;
|
return <RenderProgress percent={0}></RenderProgress>;
|
||||||
|
|||||||
@@ -3,27 +3,7 @@ import { memo, useMemo } from 'react';
|
|||||||
|
|
||||||
const RenderProgress = memo((props: { percent: number }) => {
|
const RenderProgress = memo((props: { percent: number }) => {
|
||||||
const { percent } = props;
|
const { percent } = props;
|
||||||
// const { record, dataIndex } = props;
|
console.log('percent====', percent);
|
||||||
// const value1 = useMemo(() => {
|
|
||||||
// let value = _.get(record, ['resources', 'allocable', dataIndex]);
|
|
||||||
// if (['gram', 'memory'].includes(dataIndex)) {
|
|
||||||
// value = _.toNumber(value.replace(/GiB|Gib/, ''));
|
|
||||||
// }
|
|
||||||
// return value;
|
|
||||||
// }, [record, dataIndex]);
|
|
||||||
|
|
||||||
// const value2 = useMemo(() => {
|
|
||||||
// let value = _.get(record, ['resources', 'capacity', dataIndex]);
|
|
||||||
// if (['gram', 'memory'].includes(dataIndex)) {
|
|
||||||
// value = _.toNumber(value.replace(/GiB|Gib/, ''));
|
|
||||||
// }
|
|
||||||
// return value;
|
|
||||||
// }, [record, dataIndex]);
|
|
||||||
|
|
||||||
// if (!value1 || !value2) {
|
|
||||||
// return <Progress percent={0} strokeColor="var(--ant-color-primary)" />;
|
|
||||||
// }
|
|
||||||
// const percent = _.round(value1 / value2, 2) * 100;
|
|
||||||
const strokeColor = useMemo(() => {
|
const strokeColor = useMemo(() => {
|
||||||
if (percent <= 50) {
|
if (percent <= 50) {
|
||||||
return 'var(--ant-color-primary)';
|
return 'var(--ant-color-primary)';
|
||||||
@@ -35,7 +15,7 @@ const RenderProgress = memo((props: { percent: number }) => {
|
|||||||
}, [percent]);
|
}, [percent]);
|
||||||
return (
|
return (
|
||||||
<Progress
|
<Progress
|
||||||
steps={5}
|
steps={10}
|
||||||
format={() => {
|
format={() => {
|
||||||
return (
|
return (
|
||||||
<span style={{ color: 'var(--ant-color-text)' }}>{percent}%</span>
|
<span style={{ color: 'var(--ant-color-text)' }}>{percent}%</span>
|
||||||
|
|||||||
@@ -4,14 +4,8 @@ import { Tabs } from 'antd';
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import GPUs from './components/gpus';
|
import GPUs from './components/gpus';
|
||||||
import Nodes from './components/nodes';
|
import Nodes from './components/nodes';
|
||||||
import Test from './components/test';
|
|
||||||
|
|
||||||
const items: TabsProps['items'] = [
|
const items: TabsProps['items'] = [
|
||||||
{
|
|
||||||
key: 'test',
|
|
||||||
label: 'Test',
|
|
||||||
children: <Test />
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
key: 'nodes',
|
key: 'nodes',
|
||||||
label: 'Nodes',
|
label: 'Nodes',
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { request } from '@umijs/max';
|
import { request } from '@umijs/max';
|
||||||
import { FormData, ListItem } from '../config/types';
|
import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
|
||||||
|
|
||||||
export const MODELS_API = '/models';
|
export const MODELS_API = '/models';
|
||||||
|
|
||||||
|
export const MODEL_INSTANCE_API = '/model_instances';
|
||||||
|
|
||||||
|
// ===================== Models =====================
|
||||||
export async function queryModelsList(
|
export async function queryModelsList(
|
||||||
params: Global.Pagination & { query?: string }
|
params: Global.Pagination & { query?: string }
|
||||||
) {
|
) {
|
||||||
@@ -31,3 +34,60 @@ export async function updateModel(params: { id: number; data: FormData }) {
|
|||||||
data: params.data
|
data: params.data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function queryModelDetail(id: number) {
|
||||||
|
return request(`${MODELS_API}/${id}`, {
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== Model Instances start =====================
|
||||||
|
|
||||||
|
export async function queryModelInstancesList(
|
||||||
|
params: Global.Pagination & { query?: string; id: number }
|
||||||
|
) {
|
||||||
|
return request<Global.PageResponse<ModelInstanceListItem>>(
|
||||||
|
`${MODELS_API}/${params.id}/instances`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
params
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createModelInstance(params: { data: FormData }) {
|
||||||
|
return request(`${MODEL_INSTANCE_API}`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: params.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteModelInstance(id: number) {
|
||||||
|
return request(`${MODEL_INSTANCE_API}/${id}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateModelInstance(params: {
|
||||||
|
id: number;
|
||||||
|
data: FormData;
|
||||||
|
}) {
|
||||||
|
return request(`${MODEL_INSTANCE_API}/${params.id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
data: params.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function queryModelInstanceDetail(id: number) {
|
||||||
|
return request(`${MODEL_INSTANCE_API}/${id}`, {
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function queryModelInstanceLogs(id: number) {
|
||||||
|
return request(`${MODEL_INSTANCE_API}/${id}/logs`, {
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===================== Model Instances end =====================
|
||||||
|
|||||||
@@ -47,17 +47,14 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
name="huggingface_repo_id"
|
name="huggingface_repo_id"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input label="Huggingface ID" required></SealInput.Input>
|
<SealInput.Input label="Repo ID" required></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{/* <Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_filename"
|
name="huggingface_filename"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: false }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input label="File Name" required></SealInput.Input>
|
||||||
label="Huggingface File Name"
|
</Form.Item>
|
||||||
required
|
|
||||||
></SealInput.Input>
|
|
||||||
</Form.Item> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { StatusMaps } from '@/config';
|
||||||
|
|
||||||
export const modelInstanceCols = [
|
export const modelInstanceCols = [
|
||||||
{
|
{
|
||||||
title: 'Name',
|
title: 'Name',
|
||||||
@@ -29,3 +31,7 @@ export const modelInstanceCols = [
|
|||||||
key: 'Operation'
|
key: 'Operation'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const status: any = {
|
||||||
|
Running: StatusMaps.success
|
||||||
|
};
|
||||||
|
|||||||
@@ -18,3 +18,21 @@ export interface FormData {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ModelInstanceListItem {
|
||||||
|
source: string;
|
||||||
|
huggingface_repo_id: string;
|
||||||
|
huggingface_filename: string;
|
||||||
|
s3_address: string;
|
||||||
|
node_id: number;
|
||||||
|
node_ip: string;
|
||||||
|
pid: number;
|
||||||
|
port: number;
|
||||||
|
state: string;
|
||||||
|
download_progress: number;
|
||||||
|
model_id: number;
|
||||||
|
model_name: string;
|
||||||
|
id: number;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import SealTable from '@/components/seal-table';
|
import SealTable from '@/components/seal-table';
|
||||||
|
import RowChildren from '@/components/seal-table/components/row-children';
|
||||||
import SealColumn from '@/components/seal-table/components/seal-column';
|
import SealColumn from '@/components/seal-table/components/seal-column';
|
||||||
|
import StatusTag from '@/components/status-tag';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import type { PageActionType } from '@/config/types';
|
import type { PageActionType } from '@/config/types';
|
||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import useTableSort from '@/hooks/use-table-sort';
|
import useTableSort from '@/hooks/use-table-sort';
|
||||||
import {
|
import {
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
|
FieldTimeOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
WechatWorkOutlined
|
WechatWorkOutlined
|
||||||
@@ -16,21 +19,28 @@ import { Access, useAccess, useIntl, useNavigate } from '@umijs/max';
|
|||||||
import {
|
import {
|
||||||
App,
|
App,
|
||||||
Button,
|
Button,
|
||||||
|
Col,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
Progress,
|
Progress,
|
||||||
|
Row,
|
||||||
Space,
|
Space,
|
||||||
Table,
|
|
||||||
Tooltip,
|
Tooltip,
|
||||||
message
|
message
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { createModel, deleteModel, queryModelsList } from './apis';
|
import {
|
||||||
|
createModel,
|
||||||
|
deleteModel,
|
||||||
|
deleteModelInstance,
|
||||||
|
queryModelInstancesList,
|
||||||
|
queryModelsList
|
||||||
|
} from './apis';
|
||||||
import AddModal from './components/add-modal';
|
import AddModal from './components/add-modal';
|
||||||
import { FormData, ListItem } from './config/types';
|
import { status } from './config';
|
||||||
const { Column } = Table;
|
import { FormData, ListItem, ModelInstanceListItem } from './config/types';
|
||||||
|
|
||||||
const Models: React.FC = () => {
|
const Models: React.FC = () => {
|
||||||
const { modal } = App.useApp();
|
const { modal } = App.useApp();
|
||||||
@@ -152,7 +162,85 @@ const Models: React.FC = () => {
|
|||||||
|
|
||||||
const handleOpenPlayGround = (row: any) => {
|
const handleOpenPlayGround = (row: any) => {
|
||||||
console.log('handleOpenPlayGround', row);
|
console.log('handleOpenPlayGround', row);
|
||||||
navigate('/playground');
|
navigate(`/playground?model=${row.name}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewLogs = (row: any) => {
|
||||||
|
console.log('handleViewLogs', row);
|
||||||
|
};
|
||||||
|
const handleDeleteInstace = (row: any) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: '',
|
||||||
|
content: 'Are you sure you want to delete the instance?',
|
||||||
|
async onOk() {
|
||||||
|
console.log('OK');
|
||||||
|
await deleteModelInstance(row.id);
|
||||||
|
message.success('successfully!');
|
||||||
|
fetchData();
|
||||||
|
},
|
||||||
|
onCancel() {
|
||||||
|
console.log('Cancel');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModelInstances = async (row: any) => {
|
||||||
|
const params = {
|
||||||
|
id: row.id,
|
||||||
|
page: 1,
|
||||||
|
perPage: 100
|
||||||
|
};
|
||||||
|
const data = await queryModelInstancesList(params);
|
||||||
|
return data.items || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderChildren = (list: any) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{_.map(list, (item: ModelInstanceListItem) => {
|
||||||
|
return (
|
||||||
|
<RowChildren key={item.id}>
|
||||||
|
<Row style={{ width: '100%' }} align="middle">
|
||||||
|
<Col span={4}>
|
||||||
|
{item.node_ip}:{item.port}
|
||||||
|
</Col>
|
||||||
|
<Col span={5}>{item.huggingface_repo_id}</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
{dayjs(item.updated_at).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<StatusTag
|
||||||
|
statusValue={{
|
||||||
|
status: status[item.state] as any,
|
||||||
|
text: item.state
|
||||||
|
}}
|
||||||
|
></StatusTag>
|
||||||
|
</Col>
|
||||||
|
<Col span={7}>
|
||||||
|
<Space>
|
||||||
|
<Tooltip title="Delete">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
danger
|
||||||
|
onClick={() => handleDeleteInstace(item)}
|
||||||
|
icon={<DeleteOutlined></DeleteOutlined>}
|
||||||
|
></Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="View Logs">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => handleViewLogs(item)}
|
||||||
|
icon={<FieldTimeOutlined />}
|
||||||
|
></Button>
|
||||||
|
</Tooltip>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</RowChildren>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// request data
|
// request data
|
||||||
@@ -217,6 +305,8 @@ const Models: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
expandable={true}
|
expandable={true}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
|
loadChildren={getModelInstances}
|
||||||
|
renderChildren={renderChildren}
|
||||||
pagination={{
|
pagination={{
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
pageSize: queryParams.perPage,
|
pageSize: queryParams.perPage,
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { request } from '@umijs/max';
|
||||||
|
|
||||||
|
export const CHAT_API = '/chat/completions';
|
||||||
|
|
||||||
|
export async function execChatCompletions(params: any) {
|
||||||
|
return request(`${CHAT_API}`, {
|
||||||
|
method: 'POST',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -12,24 +12,30 @@ interface ChatFooterProps {
|
|||||||
onClear: () => void;
|
onClear: () => void;
|
||||||
onNewMessage: () => void;
|
onNewMessage: () => void;
|
||||||
onView: () => void;
|
onView: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
feedback?: React.ReactNode;
|
feedback?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
||||||
const { onSubmit, onClear, onNewMessage, onView, feedback } = props;
|
const { onSubmit, onClear, onNewMessage, onView, feedback, disabled } = props;
|
||||||
return (
|
return (
|
||||||
<div className="chat-footer">
|
<div className="chat-footer">
|
||||||
<Row style={{ width: '100%' }}>
|
<Row style={{ width: '100%' }}>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Space size={20}>
|
<Space size={20}>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
onClick={onNewMessage}
|
onClick={onNewMessage}
|
||||||
>
|
>
|
||||||
New Message
|
New Message
|
||||||
</Button>
|
</Button>
|
||||||
<Button icon={<DeleteOutlined></DeleteOutlined>} onClick={onClear}>
|
<Button
|
||||||
|
icon={<DeleteOutlined></DeleteOutlined>}
|
||||||
|
onClick={onClear}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
@@ -37,10 +43,15 @@ const ChatFooter: React.FC<ChatFooterProps> = (props) => {
|
|||||||
<Col span={8}>{feedback}</Col>
|
<Col span={8}>{feedback}</Col>
|
||||||
<Col span={8} style={{ textAlign: 'right' }}>
|
<Col span={8} style={{ textAlign: 'right' }}>
|
||||||
<Space size={20}>
|
<Space size={20}>
|
||||||
<Button icon={<CodeOutlined></CodeOutlined>} onClick={onView}>
|
<Button
|
||||||
|
icon={<CodeOutlined></CodeOutlined>}
|
||||||
|
onClick={onView}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
View
|
View
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={disabled}
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<SaveOutlined></SaveOutlined>}
|
icon={<SaveOutlined></SaveOutlined>}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import TransitionWrapper from '@/components/transition';
|
import TransitionWrapper from '@/components/transition';
|
||||||
import { EyeInvisibleOutlined } from '@ant-design/icons';
|
import { EyeInvisibleOutlined } from '@ant-design/icons';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { Button, Input } from 'antd';
|
import { Button, Input, Spin } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
import { execChatCompletions } from '../apis';
|
||||||
|
import { Roles } from '../config';
|
||||||
import '../style/ground-left.less';
|
import '../style/ground-left.less';
|
||||||
import '../style/system-message-wrap.less';
|
import '../style/system-message-wrap.less';
|
||||||
import ChatFooter from './chat-footer';
|
import ChatFooter from './chat-footer';
|
||||||
@@ -10,37 +13,74 @@ import MessageItem from './message-item';
|
|||||||
import ReferenceParams from './reference-params';
|
import ReferenceParams from './reference-params';
|
||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
const MessageList: React.FC = () => {
|
interface MessageProps {
|
||||||
const [messageList, setMessageList] = useState<any[]>([
|
parameters: any;
|
||||||
|
}
|
||||||
|
const MessageList: React.FC<MessageProps> = (props) => {
|
||||||
|
const { parameters } = props;
|
||||||
|
const [messageList, setMessageList] = useState<
|
||||||
|
{ role: string; content: string }[]
|
||||||
|
>([
|
||||||
{
|
{
|
||||||
role: 'User',
|
role: 'user',
|
||||||
message: 'hello'
|
content: ''
|
||||||
},
|
|
||||||
{
|
|
||||||
role: 'Assistant',
|
|
||||||
message: 'hello, nice to meet you!'
|
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const [systemMessage, setSystemMessage] = useState('');
|
const [systemMessage, setSystemMessage] = useState('');
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
const [activeIndex, setActiveIndex] = useState(-1);
|
const [activeIndex, setActiveIndex] = useState(-1);
|
||||||
|
const [tokenResult, setTokenResult] = useState<any>(null);
|
||||||
const systemRef = useRef<any>(null);
|
const systemRef = useRef<any>(null);
|
||||||
|
|
||||||
const handleSystemMessageChange = (e: any) => {
|
const handleSystemMessageChange = (e: any) => {
|
||||||
setSystemMessage(e.target.value);
|
setSystemMessage(e.target.value);
|
||||||
};
|
};
|
||||||
const handleNewMessage = () => {
|
const handleNewMessage = () => {
|
||||||
console.log('new message');
|
|
||||||
messageList.push({
|
messageList.push({
|
||||||
role: 'User',
|
role: 'user',
|
||||||
message: 'hello'
|
content: ''
|
||||||
});
|
});
|
||||||
setMessageList([...messageList]);
|
setMessageList([...messageList]);
|
||||||
setActiveIndex(messageList.length - 1);
|
setActiveIndex(messageList.length - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const submitMessage = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const chatParams = {
|
||||||
|
messages: systemMessage
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: systemMessage
|
||||||
|
},
|
||||||
|
...messageList
|
||||||
|
]
|
||||||
|
: [...messageList],
|
||||||
|
...parameters
|
||||||
|
};
|
||||||
|
const data = await execChatCompletions(chatParams);
|
||||||
|
const assistant = _.get(data, ['choices', '0', 'message']);
|
||||||
|
setTokenResult({
|
||||||
|
...data.usage
|
||||||
|
});
|
||||||
|
setMessageList([
|
||||||
|
...messageList,
|
||||||
|
{
|
||||||
|
role: Roles.Assistant,
|
||||||
|
content: assistant.content
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
console.log('clear');
|
setMessageList([]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleView = () => {
|
const handleView = () => {
|
||||||
@@ -49,6 +89,7 @@ const MessageList: React.FC = () => {
|
|||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
console.log('submit');
|
console.log('submit');
|
||||||
|
submitMessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseViewCode = () => {
|
const handleCloseViewCode = () => {
|
||||||
@@ -60,6 +101,15 @@ const MessageList: React.FC = () => {
|
|||||||
setMessageList([...messageList]);
|
setMessageList([...messageList]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUpdateMessage = (
|
||||||
|
index: number,
|
||||||
|
message: { role: string; content: string }
|
||||||
|
) => {
|
||||||
|
messageList[index] = message;
|
||||||
|
console.log('updatemessage========', index, message);
|
||||||
|
setMessageList([...messageList]);
|
||||||
|
};
|
||||||
|
|
||||||
const renderLabel = () => {
|
const renderLabel = () => {
|
||||||
return (
|
return (
|
||||||
<div className="system-message-wrap ">
|
<div className="system-message-wrap ">
|
||||||
@@ -94,13 +144,27 @@ const MessageList: React.FC = () => {
|
|||||||
return (
|
return (
|
||||||
<MessageItem
|
<MessageItem
|
||||||
key={index}
|
key={index}
|
||||||
role={item.role}
|
|
||||||
isFocus={index === activeIndex}
|
isFocus={index === activeIndex}
|
||||||
|
islast={index === messageList.length - 1}
|
||||||
|
loading={loading}
|
||||||
onDelete={() => handleDelete(index)}
|
onDelete={() => handleDelete(index)}
|
||||||
message={item.message}
|
updateMessage={(message: { role: string; content: string }) =>
|
||||||
|
handleUpdateMessage(index, message)
|
||||||
|
}
|
||||||
|
message={item}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
{loading && (
|
||||||
|
<Spin>
|
||||||
|
<MessageItem
|
||||||
|
message={{ role: Roles.Assistant, content: '' }}
|
||||||
|
isFocus={false}
|
||||||
|
onDelete={() => {}}
|
||||||
|
updateMessage={() => {}}
|
||||||
|
/>
|
||||||
|
</Spin>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
<div className="ground-left-footer">
|
<div className="ground-left-footer">
|
||||||
@@ -109,7 +173,8 @@ const MessageList: React.FC = () => {
|
|||||||
onNewMessage={handleNewMessage}
|
onNewMessage={handleNewMessage}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onView={handleView}
|
onView={handleView}
|
||||||
feedback={<ReferenceParams></ReferenceParams>}
|
disabled={loading}
|
||||||
|
feedback={<ReferenceParams usage={tokenResult}></ReferenceParams>}
|
||||||
></ChatFooter>
|
></ChatFooter>
|
||||||
</div>
|
</div>
|
||||||
<ViewCodeModal
|
<ViewCodeModal
|
||||||
|
|||||||
@@ -1,17 +1,26 @@
|
|||||||
import { MinusCircleOutlined } from '@ant-design/icons';
|
import { MinusCircleOutlined } from '@ant-design/icons';
|
||||||
import { Button, Input } from 'antd';
|
import { Button, Input } from 'antd';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import _ from 'lodash';
|
||||||
|
import { memo, useEffect, useRef, useState } from 'react';
|
||||||
import { Roles } from '../config';
|
import { Roles } from '../config';
|
||||||
import '../style/message-item.less';
|
import '../style/message-item.less';
|
||||||
|
|
||||||
const MessageContent: React.FC<{
|
const MessageItem: React.FC<{
|
||||||
message: string;
|
message: {
|
||||||
role: string;
|
role: string;
|
||||||
|
content: string;
|
||||||
|
};
|
||||||
|
loading?: boolean;
|
||||||
|
islast?: boolean;
|
||||||
|
updateMessage: (message: { role: string; content: string }) => void;
|
||||||
isFocus: boolean;
|
isFocus: boolean;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
}> = ({ message, role, isFocus, onDelete }) => {
|
}> = ({ message, isFocus, onDelete, updateMessage, loading, islast }) => {
|
||||||
const [roleType, setRoleType] = useState(role);
|
const [roleType, setRoleType] = useState(message.role);
|
||||||
const [messageContent, setMessageContent] = useState(message);
|
const [isTyping, setIsTyping] = useState(false);
|
||||||
|
const [messageContent, setMessageContent] = useState(message.content);
|
||||||
|
const isInitialRender = useRef(true);
|
||||||
|
const [isAnimating, setIsAnimating] = useState(false);
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -20,17 +29,49 @@ const MessageContent: React.FC<{
|
|||||||
}
|
}
|
||||||
}, [isFocus]);
|
}, [isFocus]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isTyping) return;
|
||||||
|
let index = 0;
|
||||||
|
const text = message.content;
|
||||||
|
if (!text.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setMessageContent('');
|
||||||
|
setIsAnimating(true);
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
setMessageContent((prev) => prev + text[index]);
|
||||||
|
index += 1;
|
||||||
|
if (index === text.length) {
|
||||||
|
setIsAnimating(false);
|
||||||
|
clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
}, 20);
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, [message.content, isTyping]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isAnimating && !isInitialRender.current) {
|
||||||
|
updateMessage({ role: roleType, content: messageContent });
|
||||||
|
} else {
|
||||||
|
isInitialRender.current = false;
|
||||||
|
}
|
||||||
|
}, [roleType, messageContent]);
|
||||||
|
|
||||||
const handleMessageChange = (e: any) => {
|
const handleMessageChange = (e: any) => {
|
||||||
|
setIsTyping(true);
|
||||||
setMessageContent(e.target.value);
|
setMessageContent(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBlur = () => {
|
||||||
|
setIsTyping(true);
|
||||||
|
};
|
||||||
|
|
||||||
const handleRoleChange = () => {
|
const handleRoleChange = () => {
|
||||||
if (roleType === Roles.User) {
|
setRoleType((prevRoleType) => {
|
||||||
setRoleType(Roles.Assistant);
|
const newRoleType =
|
||||||
}
|
prevRoleType === Roles.User ? Roles.Assistant : Roles.User;
|
||||||
if (roleType === Roles.Assistant) {
|
return newRoleType;
|
||||||
setRoleType(Roles.User);
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
@@ -40,7 +81,7 @@ const MessageContent: React.FC<{
|
|||||||
<div className="message-item">
|
<div className="message-item">
|
||||||
<div className="role-type">
|
<div className="role-type">
|
||||||
<Button onClick={handleRoleChange} type="text">
|
<Button onClick={handleRoleChange} type="text">
|
||||||
{roleType}
|
{_.upperFirst(roleType)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="message-content-input">
|
<div className="message-content-input">
|
||||||
@@ -51,6 +92,7 @@ const MessageContent: React.FC<{
|
|||||||
autoSize={true}
|
autoSize={true}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
onChange={handleMessageChange}
|
onChange={handleMessageChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
></Input.TextArea>
|
></Input.TextArea>
|
||||||
</div>
|
</div>
|
||||||
<div className="delete-btn">
|
<div className="delete-btn">
|
||||||
@@ -66,4 +108,4 @@ const MessageContent: React.FC<{
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MessageContent;
|
export default memo(MessageItem);
|
||||||
|
|||||||
@@ -2,39 +2,85 @@ import FieldWrapper from '@/components/seal-form/field-wrapper';
|
|||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import SealSelect from '@/components/seal-form/seal-select';
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import { INPUT_WIDTH } from '@/constants';
|
import { INPUT_WIDTH } from '@/constants';
|
||||||
|
import { queryModelsList } from '@/pages/llmodels/apis';
|
||||||
import { Form, Slider } from 'antd';
|
import { Form, Slider } from 'antd';
|
||||||
import { useState } from 'react';
|
import _ from 'lodash';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
type ParamsSettingsFormProps = {
|
||||||
|
seed?: number;
|
||||||
|
stop?: number;
|
||||||
|
temperature?: number;
|
||||||
|
top_p?: number;
|
||||||
|
model?: string;
|
||||||
|
max_tokens?: number;
|
||||||
|
};
|
||||||
|
|
||||||
type ParamsSettingsProps = {
|
type ParamsSettingsProps = {
|
||||||
seed?: number;
|
onClose?: () => void;
|
||||||
stopSequence?: number;
|
selectedModel?: string;
|
||||||
temperature?: number;
|
params?: ParamsSettingsFormProps;
|
||||||
topP?: number;
|
setParams: (params: any) => void;
|
||||||
model?: string;
|
|
||||||
maxTokens?: number;
|
|
||||||
};
|
};
|
||||||
const dataList = [
|
// const dataList = [
|
||||||
{ value: 'llama3:latest', label: 'llama3:latest' },
|
// { value: 'llama3:latest', label: 'llama3:latest' },
|
||||||
{ value: 'wangfuyun/AnimateLCM', label: 'wangfuyun/AnimateLCM' },
|
// { value: 'wangfuyun/AnimateLCM', label: 'wangfuyun/AnimateLCM' },
|
||||||
{ value: 'Revanthraja/Text_to_Vision', label: 'Revanthraja/Text_to_Vision' }
|
// { value: 'Revanthraja/Text_to_Vision', label: 'Revanthraja/Text_to_Vision' }
|
||||||
];
|
// ];
|
||||||
|
|
||||||
const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
const ParamsSettings: React.FC<ParamsSettingsProps> = ({
|
||||||
const [ModelList, setModelList] = useState(dataList);
|
onClose,
|
||||||
|
selectedModel,
|
||||||
|
setParams
|
||||||
|
}) => {
|
||||||
|
const [ModelList, setModelList] = useState([]);
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
seed: 1,
|
seed: null,
|
||||||
stopSequence: 1,
|
stop: null,
|
||||||
temperature: 1,
|
temperature: 1,
|
||||||
topK: 1,
|
top_p: 1,
|
||||||
topP: 1,
|
max_tokens: 1024
|
||||||
repeatPenalty: 1,
|
|
||||||
repeatLastN: 1,
|
|
||||||
tfsZ: 1,
|
|
||||||
contextLength: 256,
|
|
||||||
maxTokens: 256
|
|
||||||
};
|
};
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getModelList = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
page: 1,
|
||||||
|
perPage: 100
|
||||||
|
};
|
||||||
|
const res = await queryModelsList(params);
|
||||||
|
const list = _.map(res.items || [], (item: any) => {
|
||||||
|
return {
|
||||||
|
value: item.name,
|
||||||
|
label: item.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setModelList(list);
|
||||||
|
form.setFieldsValue({
|
||||||
|
model: selectedModel || _.get(list, '[0].value'),
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
setParams({
|
||||||
|
model: selectedModel || _.get(list, '[0].value'),
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
setModelList([]);
|
||||||
|
form.setFieldsValue({
|
||||||
|
model: selectedModel || '',
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
setParams({
|
||||||
|
model: selectedModel || '',
|
||||||
|
...initialValues
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getModelList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleOnFinish = (values: any) => {
|
const handleOnFinish = (values: any) => {
|
||||||
console.log('handleOnFinish', values);
|
console.log('handleOnFinish', values);
|
||||||
};
|
};
|
||||||
@@ -45,61 +91,79 @@ const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
|||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
onClose();
|
onClose?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleValuesChange = (changedValues: any, allValues: any) => {
|
||||||
|
console.log('handleValuesChange', changedValues, allValues);
|
||||||
|
setParams?.(allValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
name="modelparams"
|
name="modelparams"
|
||||||
form={form}
|
form={form}
|
||||||
|
onValuesChange={handleValuesChange}
|
||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onFinishFailed={handleOnFinishFailed}
|
onFinishFailed={handleOnFinishFailed}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="m-b-20 m-l-10">Model</h3>
|
<h3 className="m-b-20 m-l-10">Model</h3>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="model"
|
name="model"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealSelect options={ModelList} label="Model"></SealSelect>
|
<SealSelect options={ModelList} label="Model"></SealSelect>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<h3 className="m-b-20 m-l-10">Parameters</h3>
|
<h3 className="m-b-20 m-l-10">Parameters</h3>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="temperature"
|
name="temperature"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<FieldWrapper label="Temperature">
|
<FieldWrapper label="Temperature">
|
||||||
<Slider defaultValue={50}></Slider>
|
<Slider
|
||||||
|
defaultValue={1}
|
||||||
|
max={2}
|
||||||
|
step={0.1}
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
tooltip={{ open: true }}
|
||||||
|
></Slider>
|
||||||
</FieldWrapper>
|
</FieldWrapper>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="maxTokens"
|
name="max_tokens"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Number
|
||||||
label="Max Tokens"
|
label="Max Tokens"
|
||||||
style={{ width: INPUT_WIDTH.mini }}
|
style={{ width: INPUT_WIDTH.mini }}
|
||||||
></SealInput.Input>
|
></SealInput.Number>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="topP"
|
name="top_p"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<FieldWrapper label="Top P">
|
<FieldWrapper label="Top P">
|
||||||
<Slider defaultValue={50}></Slider>
|
<Slider
|
||||||
|
defaultValue={1}
|
||||||
|
max={1}
|
||||||
|
step={0.1}
|
||||||
|
style={{ marginBottom: 0 }}
|
||||||
|
tooltip={{ open: true }}
|
||||||
|
></Slider>
|
||||||
</FieldWrapper>
|
</FieldWrapper>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="seed"
|
name="seed"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Number
|
||||||
label="Seed"
|
label="Seed"
|
||||||
style={{ width: INPUT_WIDTH.mini }}
|
style={{ width: INPUT_WIDTH.mini }}
|
||||||
></SealInput.Input>
|
></SealInput.Number>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<ParamsSettingsProps>
|
<Form.Item<ParamsSettingsFormProps>
|
||||||
name="stopSequence"
|
name="stop"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
|
|||||||
@@ -1,11 +1,31 @@
|
|||||||
|
import { Space, Tooltip } from 'antd';
|
||||||
import '../style/reference-params.less';
|
import '../style/reference-params.less';
|
||||||
|
|
||||||
const ReferenceParams = () => {
|
interface ReferenceParamsProps {
|
||||||
|
usage: {
|
||||||
|
completion_tokens: number;
|
||||||
|
prompt_tokens: number;
|
||||||
|
total_tokens: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ReferenceParams = (props: ReferenceParamsProps) => {
|
||||||
|
const { usage } = props;
|
||||||
|
if (!usage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div className="reference-params">
|
<div className="reference-params">
|
||||||
<span>Inference: 597 ms</span>
|
<Tooltip
|
||||||
<span style={{ padding: '10px' }}></span>
|
title={
|
||||||
<span>Tokens/s: 561</span>
|
<Space>
|
||||||
|
<span>Completion: {usage.completion_tokens}</span>
|
||||||
|
<span>Prompt: {usage.prompt_tokens}</span>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span>Token Usage: {usage.total_tokens}</span>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export const Roles = {
|
export const Roles = {
|
||||||
User: 'User',
|
User: 'user',
|
||||||
Assistant: 'Assistant'
|
Assistant: 'assistant'
|
||||||
};
|
};
|
||||||
export const playGroundRoles = [
|
export const playGroundRoles = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,24 +1,22 @@
|
|||||||
|
import { useSearchParams } from '@umijs/max';
|
||||||
import { Divider } from 'antd';
|
import { Divider } from 'antd';
|
||||||
import { useEffect, useState } from 'react';
|
import { useState } from 'react';
|
||||||
import GroundLeft from './components/ground-left';
|
import GroundLeft from './components/ground-left';
|
||||||
import ParamsSettings from './components/params-settings';
|
import ParamsSettings from './components/params-settings';
|
||||||
import './style/play-ground.less';
|
import './style/play-ground.less';
|
||||||
|
|
||||||
const Playground: React.FC = () => {
|
const Playground: React.FC = () => {
|
||||||
const [messageList, setMessageList] = useState<any[]>([]);
|
const [searchParams] = useSearchParams();
|
||||||
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
||||||
const [showPopover, setShowPopover] = useState(false);
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
|
const selectModel = searchParams.get('model') || '';
|
||||||
|
const [params, setParams] = useState({});
|
||||||
|
|
||||||
|
console.log('query======', searchParams, selectModel);
|
||||||
const handleSelectChange = (value: string) => {
|
const handleSelectChange = (value: string) => {
|
||||||
setSelectedModel(value);
|
setSelectedModel(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMessageList = () => {
|
|
||||||
// fetch message list from server
|
|
||||||
console.log('getModelList');
|
|
||||||
setMessageList(['1']);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTogglePopover = () => {
|
const handleTogglePopover = () => {
|
||||||
setShowPopover(!showPopover);
|
setShowPopover(!showPopover);
|
||||||
};
|
};
|
||||||
@@ -27,20 +25,20 @@ const Playground: React.FC = () => {
|
|||||||
setShowPopover(false);
|
setShowPopover(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
getMessageList();
|
|
||||||
}, [selectedModel]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="play-ground">
|
<div className="play-ground">
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
<GroundLeft></GroundLeft>
|
<GroundLeft parameters={params}></GroundLeft>
|
||||||
</div>
|
</div>
|
||||||
<div className="divider-line">
|
<div className="divider-line">
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
</div>
|
</div>
|
||||||
<div className="params">
|
<div className="params">
|
||||||
<ParamsSettings onClose={handleClosePopover} />
|
<ParamsSettings
|
||||||
|
onClose={handleClosePopover}
|
||||||
|
setParams={setParams}
|
||||||
|
selectedModel={selectModel}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user