chore: playground layout

This commit is contained in:
jialin
2024-05-28 19:22:06 +08:00
parent 3120f5ee3a
commit a99b58fbb4
26 changed files with 444 additions and 189 deletions
@@ -0,0 +1,57 @@
import {
CodeOutlined,
DeleteOutlined,
PlusOutlined,
SaveOutlined
} from '@ant-design/icons';
import { Button, Col, Row, Space } from 'antd';
import '../style/chat-footer.less';
interface ChatFooterProps {
onSubmit: () => void;
onClear: () => void;
onNewMessage: () => void;
onView: () => void;
feedback?: React.ReactNode;
}
const ChatFooter: React.FC<ChatFooterProps> = (props) => {
const { onSubmit, onClear, onNewMessage, onView, feedback } = props;
return (
<div className="chat-footer">
<Row style={{ width: '100%' }}>
<Col span={8}>
<Space size={20}>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={onNewMessage}
>
New Message
</Button>
<Button icon={<DeleteOutlined></DeleteOutlined>} onClick={onClear}>
Clear
</Button>
</Space>
</Col>
<Col span={8}>{feedback}</Col>
<Col span={8} style={{ textAlign: 'right' }}>
<Space size={20}>
<Button icon={<CodeOutlined></CodeOutlined>} onClick={onView}>
View
</Button>
<Button
type="primary"
icon={<SaveOutlined></SaveOutlined>}
onClick={onSubmit}
>
Submit
</Button>
</Space>
</Col>
</Row>
</div>
);
};
export default ChatFooter;
@@ -1,68 +0,0 @@
.chatEmpty {
display: flex;
justify-content: center;
align-items: center;
margin-top: 200px;
flex-direction: column;
.logo {
height: 60px;
width: 60px;
margin-block: 20px;
img {
width: 100%;
height: 100%;
}
}
.tips {
margin-top: 20px;
}
}
.chatContent {
width: max(50%, 500px);
}
.chatMessageItem {
margin-bottom: 12px;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
padding-inline: 44px 16px;
.name {
padding-block: 8px 16px;
}
.content {
padding: 8px 12px;
border-radius: var(--border-radius-base);
background-color: var(--color-fill-3);
font-size: var(--font-size-base);
}
.contentWrap {
position: relative;
padding-right: 45px;
&:hover .edit {
display: block;
}
.edit {
display: none;
position: absolute;
top: -10px;
right: 0;
padding: 8px;
}
}
.img {
position: absolute;
top: 0;
left: 0;
width: 32px;
height: 32px;
border-radius: 50%;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
}
@@ -7,7 +7,7 @@ import {
SyncOutlined
} from '@ant-design/icons';
import { Button, Space, Tooltip } from 'antd';
import chatStyle from './chat-style.less';
import chatStyle from '../style/chat-style.less';
import ChatEmpty from './chatEmpty';
export type ChatContentProps = {
@@ -1,5 +1,5 @@
import Logo from '@/assets/images/logo.png';
import chatStyle from './chat-style.less';
import chatStyle from '../style/chat-style.less';
const ChatEmpty: React.FC = () => {
return (
@@ -0,0 +1,78 @@
import { PageContainer } from '@ant-design/pro-components';
import { useState } from 'react';
import '../style/ground-left.less';
import ChatFooter from './chat-footer';
import MessageItem from './message-item';
import ReferenceParams from './reference-params';
const MessageList: React.FC = () => {
const [messageList, setMessageList] = useState<any[]>([
{
role: 'User',
message: 'hello'
},
{
role: 'Assistant',
message: 'hello, nice to meet you!'
}
]);
const [activeIndex, setActiveIndex] = useState(-1);
const handleNewMessage = () => {
console.log('new message');
messageList.push({
role: 'User',
message: 'hello'
});
setMessageList([...messageList]);
setActiveIndex(messageList.length - 1);
};
const handleClear = () => {
console.log('clear');
};
const handleView = () => {
console.log('view');
};
const handleSubmit = () => {
console.log('submit');
};
const handleDelete = (index: number) => {
messageList.splice(index, 1);
setMessageList([...messageList]);
};
return (
<div className="ground-left">
<PageContainer title={false} className="message-list-wrap">
<div>
{messageList.map((item, index) => {
return (
<MessageItem
key={index}
role={item.role}
isFocus={index === activeIndex}
onDelete={() => handleDelete(index)}
message={item.message}
/>
);
})}
</div>
</PageContainer>
<div className="ground-left-footer">
<ChatFooter
onClear={handleClear}
onNewMessage={handleNewMessage}
onSubmit={handleSubmit}
onView={handleView}
feedback={<ReferenceParams></ReferenceParams>}
></ChatFooter>
</div>
</div>
);
};
export default MessageList;
@@ -1,63 +0,0 @@
.ant-pro-footer-bar {
padding-block: 20px;
padding-bottom: 30px;
border: none;
.ant-pro-footer-bar-right {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.messageInput {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: max(50%, 500px);
background-color: var(--color-fill-1);
border-radius: 30px;
padding-right: 50px;
border: 1px solid transparent;
transition: all 0.2s ease;
&:focus-within {
border-color: var(--ant-input-active-border-color);
box-shadow: var(--ant-input-active-shadow);
background-color: var(--color-white-1);
transition: all 0.2s ease;
&:hover {
background-color: var(--color-white-1);
}
}
&:hover {
background: var(--ant-color-fill-secondary);
transition: background 0.2s ease;
}
textarea {
padding: 16px;
border-radius: 30px;
background-color: transparent;
}
textarea::-webkit-scrollbar {
width: 8px;
}
textarea::-webkit-scrollbar-track {
background-color: #f1f1f1;
}
textarea::-webkit-scrollbar-thumb {
background-color: #d9d9d9;
border-radius: 6px;
}
.send-btn {
position: absolute;
right: 10px;
bottom: 11px;
display: flex;
justify-content: center;
align-items: center;
transform: rotate(-30deg);
}
}
@@ -0,0 +1,69 @@
import { MinusCircleOutlined } from '@ant-design/icons';
import { Button, Input } from 'antd';
import { useEffect, useRef, useState } from 'react';
import { Roles } from '../config';
import '../style/message-item.less';
const MessageContent: React.FC<{
message: string;
role: string;
isFocus: boolean;
onDelete: () => void;
}> = ({ message, role, isFocus, onDelete }) => {
const [roleType, setRoleType] = useState(role);
const [messageContent, setMessageContent] = useState(message);
const inputRef = useRef<any>(null);
useEffect(() => {
if (inputRef.current && isFocus) {
inputRef.current.focus();
}
}, [isFocus]);
const handleMessageChange = (e: any) => {
setMessageContent(e.target.value);
};
const handleRoleChange = () => {
if (roleType === Roles.User) {
setRoleType(Roles.Assistant);
}
if (roleType === Roles.Assistant) {
setRoleType(Roles.User);
}
};
const handleDelete = () => {
onDelete();
};
return (
<div className="message-item">
<div className="role-type">
<Button onClick={handleRoleChange} type="text">
{roleType}
</Button>
</div>
<div className="message-content-input">
<Input.TextArea
ref={inputRef}
style={{ paddingBlock: '12px' }}
value={messageContent}
autoSize={true}
variant="filled"
onChange={handleMessageChange}
></Input.TextArea>
</div>
<div className="delete-btn">
<Button
type="text"
shape="circle"
style={{ color: 'var(--ant-color-primary' }}
onClick={handleDelete}
icon={<MinusCircleOutlined />}
></Button>
</div>
</div>
);
};
export default MessageContent;
@@ -1,7 +1,7 @@
import { SendOutlined } from '@ant-design/icons';
import { Button, Input } from 'antd';
import { useState } from 'react';
import './message-input.less';
import '../style/message-input.less';
const MessageInput: React.FC = () => {
const { TextArea } = Input;
@@ -1,22 +1,26 @@
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 { Button, Form, Select, Space } from 'antd';
import { Form, Slider } from 'antd';
import { useState } from 'react';
type ParamsSettingsProps = {
seed?: number;
stopSequence?: number;
temperature?: number;
topK?: number;
topP?: number;
repeatPenalty?: number;
repeatLastN?: number;
tfsZ?: number;
contextLength?: number;
model?: string;
maxTokens?: number;
};
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 initialValues = {
seed: 1,
stopSequence: 1,
@@ -51,134 +55,60 @@ const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
onFinish={handleOnFinish}
onFinishFailed={handleOnFinishFailed}
>
<div
style={{
maxHeight: '450px',
overflow: 'auto',
paddingRight: 'var(--ant-popover-inner-padding)'
}}
>
<div>
<h3 className="m-b-20 m-l-10">Model</h3>
<Form.Item<ParamsSettingsProps>
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>
name="temperature"
rules={[{ required: true }]}
>
<SealInput.Input
label="Temperature"
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="maxTokens"
rules={[{ required: true }]}
>
<SealInput.Input
label="Max Tokens"
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="topP"
rules={[{ required: true }]}
>
<FieldWrapper label="TopP">
<Slider defaultValue={50}></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="seed"
rules={[{ required: true }]}
>
<SealInput.Input
label="Seed"
style={{ width: INPUT_WIDTH.default }}
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="select"
rules={[{ required: true }]}
>
<SealSelect label="Select" style={{ width: INPUT_WIDTH.default }}>
<Select.Option value={1}>1</Select.Option>
<Select.Option value={2}>2</Select.Option>
<Select.Option value={3}>3</Select.Option>
</SealSelect>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="stopSequence"
rules={[{ required: true }]}
>
<SealInput.Input
label="Stop Sequence"
style={{ width: INPUT_WIDTH.default }}
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="temperature"
rules={[{ required: true }]}
>
<SealInput.Input
label="Temperature"
style={{ width: INPUT_WIDTH.default }}
disabled={true}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="topK"
rules={[{ required: true }]}
>
<SealInput.Input
label="TopK"
style={{ width: INPUT_WIDTH.default }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="topP"
rules={[{ required: true }]}
>
<SealInput.Input
label="TopP"
style={{ width: INPUT_WIDTH.default }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="repeatPenalty"
rules={[{ required: true }]}
>
<SealInput.Input
label="Repeat Penalty"
style={{ width: INPUT_WIDTH.default }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="repeatLastN"
rules={[{ required: true }]}
>
<SealInput.Search
label="Repeat Last N"
style={{ width: INPUT_WIDTH.default }}
disabled={true}
></SealInput.Search>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="tfsZ"
rules={[{ required: true }]}
>
<SealInput.Input
label="TFSZ"
style={{ width: INPUT_WIDTH.default }}
></SealInput.Input>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="contextLength"
rules={[{ required: true }]}
>
<SealInput.Number
label="Context Length"
style={{ width: INPUT_WIDTH.default }}
></SealInput.Number>
</Form.Item>
<Form.Item<ParamsSettingsProps>
name="maxTokens"
rules={[{ required: true }]}
>
<SealInput.TextArea
label="Max Tokens"
style={{ width: INPUT_WIDTH.default }}
></SealInput.TextArea>
</Form.Item>
</div>
<Form.Item noStyle>
<Space
size={20}
align="end"
style={{
width: '100%',
display: 'flex',
justifyContent: 'end',
paddingRight: 'var(--ant-popover-inner-padding)',
paddingTop: 'var(--ant-popover-inner-padding)'
}}
>
<Button onClick={handleCancel}>Cancel</Button>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Space>
</Form.Item>
</Form>
);
};
@@ -0,0 +1,13 @@
import '../style/reference-params.less';
const ReferenceParams = () => {
return (
<div className="reference-params">
<span>Inference: 597 ms</span>
<span style={{ padding: '10px' }}></span>
<span>Tokens/s: 561</span>
</div>
);
};
export default ReferenceParams;