chore: playground api request

main
jialin 2 years ago
parent 405d95c81f
commit c9ea96e078

@ -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 { Button, Checkbox, Col, Row } from 'antd';
import { Button, Checkbox, Col, Empty, Row, Spin } from 'antd';
import classNames from 'classnames';
import _ from 'lodash';
import React, { useEffect, useState } from 'react';
@ -17,11 +17,15 @@ const TableRow: React.FC<
rowSelection,
rowKey,
columns,
onExpand
onExpand,
renderChildren,
loadChildren
} = props;
const [expanded, setExpanded] = useState(false);
const [checked, setChecked] = useState(false);
const [childrenData, setChildrenData] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (rowSelection) {
@ -34,9 +38,18 @@ const TableRow: React.FC<
}
}, [rowSelection]);
const handleRowExpand = () => {
setExpanded(!expanded);
onExpand?.(!expanded, record);
const handleRowExpand = async () => {
try {
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) => {
@ -126,7 +139,13 @@ const TableRow: React.FC<
</div>
{expanded && (
<div className="expanded-row">
<div className="expanded-row-content">rowchildren</div>
<Spin spinning={loading}>
{childrenData.length ? (
renderChildren?.(childrenData)
) : (
<Empty></Empty>
)}
</Spin>
</div>
)}
</div>

@ -8,8 +8,16 @@ import './styles/index.less';
import { SealColumnProps, SealTableProps } from './types';
const SealTable: React.FC<SealTableProps> = (props) => {
const { children, rowKey, onExpand, loading, expandable, rowSelection } =
props;
const {
children,
rowKey,
onExpand,
loading,
expandable,
rowSelection,
renderChildren,
loadChildren
} = props;
const [selectAll, setSelectAll] = useState(false);
const [indeterminate, setIndeterminate] = useState(false);
@ -121,6 +129,8 @@ const SealTable: React.FC<SealTableProps> = (props) => {
rowSelection={rowSelection}
expandable={expandable}
rowKey={rowKey}
renderChildren={renderChildren}
loadChildren={loadChildren}
onExpand={onExpand}
></TableRow>
);

@ -22,7 +22,7 @@
}
.expanded-row {
background-color: var(--color-white-1);
padding: 16px 20px;
padding: 16px 16px;
border: 1px solid var(--color-fill-1);
border-top: 0;
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[];
loading?: boolean;
onExpand?: (expanded: boolean, record: any) => void;
renderChildren?: (data: any) => React.ReactNode;
loadChildren?: (record: any) => Promise<any[]>;
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;

@ -1,7 +1,7 @@
declare namespace Global {
interface Pagination {
page: number;
perPage: number;
perPage?: number;
watch?: boolean;
}
interface PageResponse<T> {

@ -29,3 +29,11 @@ export const StatusColorMap: Record<StatusType, { text: string; bg: string }> =
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"
key="GPU"
render={(text, record: ListItem) => {
return <RenderProgress percent={0}></RenderProgress>;
return (
<RenderProgress
percent={_.get(record, [
'status',
'gpu',
'0',
'core_utilization_rate'
])}
></RenderProgress>
);
}}
/>
<Column
title="VRAM"
dataIndex="GRAM"
dataIndex="VRAM"
key="VRAM"
render={(text, record: ListItem) => {
return <RenderProgress percent={0}></RenderProgress>;

@ -3,27 +3,7 @@ import { memo, useMemo } from 'react';
const RenderProgress = memo((props: { percent: number }) => {
const { percent } = props;
// const { record, dataIndex } = props;
// 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;
console.log('percent====', percent);
const strokeColor = useMemo(() => {
if (percent <= 50) {
return 'var(--ant-color-primary)';
@ -35,7 +15,7 @@ const RenderProgress = memo((props: { percent: number }) => {
}, [percent]);
return (
<Progress
steps={5}
steps={10}
format={() => {
return (
<span style={{ color: 'var(--ant-color-text)' }}>{percent}%</span>

@ -4,14 +4,8 @@ import { Tabs } from 'antd';
import { useState } from 'react';
import GPUs from './components/gpus';
import Nodes from './components/nodes';
import Test from './components/test';
const items: TabsProps['items'] = [
{
key: 'test',
label: 'Test',
children: <Test />
},
{
key: 'nodes',
label: 'Nodes',

@ -1,8 +1,11 @@
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 MODEL_INSTANCE_API = '/model_instances';
// ===================== Models =====================
export async function queryModelsList(
params: Global.Pagination & { query?: string }
) {
@ -31,3 +34,60 @@ export async function updateModel(params: { id: number; data: FormData }) {
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"
rules={[{ required: true }]}
>
<SealInput.Input label="Huggingface ID" required></SealInput.Input>
<SealInput.Input label="Repo ID" required></SealInput.Input>
</Form.Item>
{/* <Form.Item<FormData>
<Form.Item<FormData>
name="huggingface_filename"
rules={[{ required: true }]}
rules={[{ required: false }]}
>
<SealInput.Input
label="Huggingface File Name"
required
></SealInput.Input>
</Form.Item> */}
<SealInput.Input label="File Name" required></SealInput.Input>
</Form.Item>
</>
);
};

@ -1,3 +1,5 @@
import { StatusMaps } from '@/config';
export const modelInstanceCols = [
{
title: 'Name',
@ -29,3 +31,7 @@ export const modelInstanceCols = [
key: 'Operation'
}
];
export const status: any = {
Running: StatusMaps.success
};

@ -18,3 +18,21 @@ export interface FormData {
name: 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 SealTable from '@/components/seal-table';
import RowChildren from '@/components/seal-table/components/row-children';
import SealColumn from '@/components/seal-table/components/seal-column';
import StatusTag from '@/components/status-tag';
import { PageAction } from '@/config';
import type { PageActionType } from '@/config/types';
import useTableRowSelection from '@/hooks/use-table-row-selection';
import useTableSort from '@/hooks/use-table-sort';
import {
DeleteOutlined,
FieldTimeOutlined,
PlusOutlined,
SyncOutlined,
WechatWorkOutlined
@ -16,21 +19,28 @@ import { Access, useAccess, useIntl, useNavigate } from '@umijs/max';
import {
App,
Button,
Col,
Input,
Modal,
Progress,
Row,
Space,
Table,
Tooltip,
message
} from 'antd';
import dayjs from 'dayjs';
import _ from 'lodash';
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 { FormData, ListItem } from './config/types';
const { Column } = Table;
import { status } from './config';
import { FormData, ListItem, ModelInstanceListItem } from './config/types';
const Models: React.FC = () => {
const { modal } = App.useApp();
@ -152,7 +162,85 @@ const Models: React.FC = () => {
const handleOpenPlayGround = (row: any) => {
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
@ -217,6 +305,8 @@ const Models: React.FC = () => {
rowKey="id"
expandable={true}
onChange={handleTableChange}
loadChildren={getModelInstances}
renderChildren={renderChildren}
pagination={{
showSizeChanger: true,
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;
onNewMessage: () => void;
onView: () => void;
disabled?: boolean;
feedback?: React.ReactNode;
}
const ChatFooter: React.FC<ChatFooterProps> = (props) => {
const { onSubmit, onClear, onNewMessage, onView, feedback } = props;
const { onSubmit, onClear, onNewMessage, onView, feedback, disabled } = props;
return (
<div className="chat-footer">
<Row style={{ width: '100%' }}>
<Col span={8}>
<Space size={20}>
<Button
disabled={disabled}
type="primary"
icon={<PlusOutlined />}
onClick={onNewMessage}
>
New Message
</Button>
<Button icon={<DeleteOutlined></DeleteOutlined>} onClick={onClear}>
<Button
icon={<DeleteOutlined></DeleteOutlined>}
onClick={onClear}
disabled={disabled}
>
Clear
</Button>
</Space>
@ -37,10 +43,15 @@ const ChatFooter: React.FC<ChatFooterProps> = (props) => {
<Col span={8}>{feedback}</Col>
<Col span={8} style={{ textAlign: 'right' }}>
<Space size={20}>
<Button icon={<CodeOutlined></CodeOutlined>} onClick={onView}>
<Button
icon={<CodeOutlined></CodeOutlined>}
onClick={onView}
disabled={disabled}
>
View
</Button>
<Button
disabled={disabled}
type="primary"
icon={<SaveOutlined></SaveOutlined>}
onClick={onSubmit}

@ -1,8 +1,11 @@
import TransitionWrapper from '@/components/transition';
import { EyeInvisibleOutlined } from '@ant-design/icons';
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 { execChatCompletions } from '../apis';
import { Roles } from '../config';
import '../style/ground-left.less';
import '../style/system-message-wrap.less';
import ChatFooter from './chat-footer';
@ -10,37 +13,74 @@ import MessageItem from './message-item';
import ReferenceParams from './reference-params';
import ViewCodeModal from './view-code-modal';
const MessageList: React.FC = () => {
const [messageList, setMessageList] = useState<any[]>([
interface MessageProps {
parameters: any;
}
const MessageList: React.FC<MessageProps> = (props) => {
const { parameters } = props;
const [messageList, setMessageList] = useState<
{ role: string; content: string }[]
>([
{
role: 'User',
message: 'hello'
},
{
role: 'Assistant',
message: 'hello, nice to meet you!'
role: 'user',
content: ''
}
]);
const [systemMessage, setSystemMessage] = useState('');
const [show, setShow] = useState(false);
const [loading, setLoading] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const [tokenResult, setTokenResult] = useState<any>(null);
const systemRef = useRef<any>(null);
const handleSystemMessageChange = (e: any) => {
setSystemMessage(e.target.value);
};
const handleNewMessage = () => {
console.log('new message');
messageList.push({
role: 'User',
message: 'hello'
role: 'user',
content: ''
});
setMessageList([...messageList]);
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 = () => {
console.log('clear');
setMessageList([]);
};
const handleView = () => {
@ -49,6 +89,7 @@ const MessageList: React.FC = () => {
const handleSubmit = () => {
console.log('submit');
submitMessage();
};
const handleCloseViewCode = () => {
@ -60,6 +101,15 @@ const MessageList: React.FC = () => {
setMessageList([...messageList]);
};
const handleUpdateMessage = (
index: number,
message: { role: string; content: string }
) => {
messageList[index] = message;
console.log('updatemessage========', index, message);
setMessageList([...messageList]);
};
const renderLabel = () => {
return (
<div className="system-message-wrap ">
@ -94,13 +144,27 @@ const MessageList: React.FC = () => {
return (
<MessageItem
key={index}
role={item.role}
isFocus={index === activeIndex}
islast={index === messageList.length - 1}
loading={loading}
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>
</PageContainer>
<div className="ground-left-footer">
@ -109,7 +173,8 @@ const MessageList: React.FC = () => {
onNewMessage={handleNewMessage}
onSubmit={handleSubmit}
onView={handleView}
feedback={<ReferenceParams></ReferenceParams>}
disabled={loading}
feedback={<ReferenceParams usage={tokenResult}></ReferenceParams>}
></ChatFooter>
</div>
<ViewCodeModal

@ -1,17 +1,26 @@
import { MinusCircleOutlined } from '@ant-design/icons';
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 '../style/message-item.less';
const MessageContent: React.FC<{
message: string;
role: string;
const MessageItem: React.FC<{
message: {
role: string;
content: string;
};
loading?: boolean;
islast?: boolean;
updateMessage: (message: { role: string; content: string }) => void;
isFocus: boolean;
onDelete: () => void;
}> = ({ message, role, isFocus, onDelete }) => {
const [roleType, setRoleType] = useState(role);
const [messageContent, setMessageContent] = useState(message);
}> = ({ message, isFocus, onDelete, updateMessage, loading, islast }) => {
const [roleType, setRoleType] = useState(message.role);
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);
useEffect(() => {
@ -20,17 +29,49 @@ const MessageContent: React.FC<{
}
}, [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) => {
setIsTyping(true);
setMessageContent(e.target.value);
};
const handleBlur = () => {
setIsTyping(true);
};
const handleRoleChange = () => {
if (roleType === Roles.User) {
setRoleType(Roles.Assistant);
}
if (roleType === Roles.Assistant) {
setRoleType(Roles.User);
}
setRoleType((prevRoleType) => {
const newRoleType =
prevRoleType === Roles.User ? Roles.Assistant : Roles.User;
return newRoleType;
});
};
const handleDelete = () => {
@ -40,7 +81,7 @@ const MessageContent: React.FC<{
<div className="message-item">
<div className="role-type">
<Button onClick={handleRoleChange} type="text">
{roleType}
{_.upperFirst(roleType)}
</Button>
</div>
<div className="message-content-input">
@ -51,6 +92,7 @@ const MessageContent: React.FC<{
autoSize={true}
variant="filled"
onChange={handleMessageChange}
onBlur={handleBlur}
></Input.TextArea>
</div>
<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 SealSelect from '@/components/seal-form/seal-select';
import { INPUT_WIDTH } from '@/constants';
import { queryModelsList } from '@/pages/llmodels/apis';
import { Form, Slider } from 'antd';
import { useState } from 'react';
import _ from 'lodash';
import { useEffect, useState } from 'react';
type ParamsSettingsProps = {
type ParamsSettingsFormProps = {
seed?: number;
stopSequence?: number;
stop?: number;
temperature?: number;
topP?: number;
top_p?: number;
model?: string;
maxTokens?: number;
max_tokens?: number;
};
type ParamsSettingsProps = {
onClose?: () => void;
selectedModel?: string;
params?: ParamsSettingsFormProps;
setParams: (params: any) => void;
};
const dataList = [
{ value: 'llama3:latest', label: 'llama3:latest' },
{ value: 'wangfuyun/AnimateLCM', label: 'wangfuyun/AnimateLCM' },
{ value: 'Revanthraja/Text_to_Vision', label: 'Revanthraja/Text_to_Vision' }
];
// const dataList = [
// { value: 'llama3:latest', label: 'llama3:latest' },
// { value: 'wangfuyun/AnimateLCM', label: 'wangfuyun/AnimateLCM' },
// { value: 'Revanthraja/Text_to_Vision', label: 'Revanthraja/Text_to_Vision' }
// ];
const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
const [ModelList, setModelList] = useState(dataList);
const ParamsSettings: React.FC<ParamsSettingsProps> = ({
onClose,
selectedModel,
setParams
}) => {
const [ModelList, setModelList] = useState([]);
const initialValues = {
seed: 1,
stopSequence: 1,
seed: null,
stop: null,
temperature: 1,
topK: 1,
topP: 1,
repeatPenalty: 1,
repeatLastN: 1,
tfsZ: 1,
contextLength: 256,
maxTokens: 256
top_p: 1,
max_tokens: 1024
};
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) => {
console.log('handleOnFinish', values);
};
@ -45,61 +91,79 @@ const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
const handleCancel = () => {
form.resetFields();
onClose();
onClose?.();
};
const handleValuesChange = (changedValues: any, allValues: any) => {
console.log('handleValuesChange', changedValues, allValues);
setParams?.(allValues);
};
return (
<Form
name="modelparams"
form={form}
onValuesChange={handleValuesChange}
onFinish={handleOnFinish}
onFinishFailed={handleOnFinishFailed}
>
<div>
<h3 className="m-b-20 m-l-10">Model</h3>
<Form.Item<ParamsSettingsProps>
<Form.Item<ParamsSettingsFormProps>
name="model"
rules={[{ required: true }]}
>
<SealSelect options={ModelList} label="Model"></SealSelect>
</Form.Item>
<h3 className="m-b-20 m-l-10">Parameters</h3>
<Form.Item<ParamsSettingsProps>
<Form.Item<ParamsSettingsFormProps>
name="temperature"
rules={[{ required: true }]}
>
<FieldWrapper label="Temperature">
<Slider defaultValue={50}></Slider>
<Slider
defaultValue={1}
max={2}
step={0.1}
style={{ marginBottom: 0 }}
tooltip={{ open: true }}
></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="maxTokens"
<Form.Item<ParamsSettingsFormProps>
name="max_tokens"
rules={[{ required: true }]}
>
<SealInput.Input
<SealInput.Number
label="Max Tokens"
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
></SealInput.Number>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="topP"
<Form.Item<ParamsSettingsFormProps>
name="top_p"
rules={[{ required: true }]}
>
<FieldWrapper label="Top P">
<Slider defaultValue={50}></Slider>
<Slider
defaultValue={1}
max={1}
step={0.1}
style={{ marginBottom: 0 }}
tooltip={{ open: true }}
></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsProps>
<Form.Item<ParamsSettingsFormProps>
name="seed"
rules={[{ required: true }]}
>
<SealInput.Input
<SealInput.Number
label="Seed"
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
></SealInput.Number>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="stopSequence"
<Form.Item<ParamsSettingsFormProps>
name="stop"
rules={[{ required: true }]}
>
<SealInput.Input

@ -1,11 +1,31 @@
import { Space, Tooltip } from 'antd';
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 (
<div className="reference-params">
<span>Inference: 597 ms</span>
<span style={{ padding: '10px' }}></span>
<span>Tokens/s: 561</span>
<Tooltip
title={
<Space>
<span>Completion: {usage.completion_tokens}</span>
<span>Prompt: {usage.prompt_tokens}</span>
</Space>
}
>
<span>Token Usage: {usage.total_tokens}</span>
</Tooltip>
</div>
);
};

@ -1,6 +1,6 @@
export const Roles = {
User: 'User',
Assistant: 'Assistant'
User: 'user',
Assistant: 'assistant'
};
export const playGroundRoles = [
{

@ -1,24 +1,22 @@
import { useSearchParams } from '@umijs/max';
import { Divider } from 'antd';
import { useEffect, useState } from 'react';
import { useState } from 'react';
import GroundLeft from './components/ground-left';
import ParamsSettings from './components/params-settings';
import './style/play-ground.less';
const Playground: React.FC = () => {
const [messageList, setMessageList] = useState<any[]>([]);
const [searchParams] = useSearchParams();
const [selectedModel, setSelectedModel] = useState('llama3:latest');
const [showPopover, setShowPopover] = useState(false);
const selectModel = searchParams.get('model') || '';
const [params, setParams] = useState({});
console.log('query======', searchParams, selectModel);
const handleSelectChange = (value: string) => {
setSelectedModel(value);
};
const getMessageList = () => {
// fetch message list from server
console.log('getModelList');
setMessageList(['1']);
};
const handleTogglePopover = () => {
setShowPopover(!showPopover);
};
@ -27,20 +25,20 @@ const Playground: React.FC = () => {
setShowPopover(false);
};
useEffect(() => {
getMessageList();
}, [selectedModel]);
return (
<div className="play-ground">
<div className="chat">
<GroundLeft></GroundLeft>
<GroundLeft parameters={params}></GroundLeft>
</div>
<div className="divider-line">
<Divider type="vertical" />
</div>
<div className="params">
<ParamsSettings onClose={handleClosePopover} />
<ParamsSettings
onClose={handleClosePopover}
setParams={setParams}
selectedModel={selectModel}
/>
</div>
</div>
);

Loading…
Cancel
Save