chore: playground layout
This commit is contained in:
@@ -22,6 +22,7 @@ export default defineConfig({
|
|||||||
token: {
|
token: {
|
||||||
colorPrimary: '#2fbf85',
|
colorPrimary: '#2fbf85',
|
||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
|
fontSize: 12,
|
||||||
motion: true
|
motion: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.m-b-20 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.m-l-10 {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import useCopyToClipboard from '@/hooks/use-copy-to-clipboard';
|
||||||
|
import { CheckCircleFilled, CopyOutlined } from '@ant-design/icons';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
|
||||||
|
type CopyButtonProps = {
|
||||||
|
text: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
size?: 'small' | 'middle' | 'large';
|
||||||
|
};
|
||||||
|
|
||||||
|
const CopyButton: React.FC<CopyButtonProps> = ({
|
||||||
|
text,
|
||||||
|
disabled,
|
||||||
|
size = 'middle'
|
||||||
|
}) => {
|
||||||
|
const { copied, copyToClipboard } = useCopyToClipboard();
|
||||||
|
|
||||||
|
const handleCopy = async (e: any) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
await copyToClipboard(text);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
shape="circle"
|
||||||
|
size={size}
|
||||||
|
onClick={handleCopy}
|
||||||
|
disabled={!!disabled}
|
||||||
|
>
|
||||||
|
{copied ? (
|
||||||
|
<CheckCircleFilled
|
||||||
|
style={{ color: 'var(--ant-color-primary)', fontSize: '14px' }}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<CopyOutlined
|
||||||
|
style={{ color: 'var(--ant-color-primary)', fontSize: '14px' }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CopyButton;
|
||||||
@@ -9,7 +9,6 @@ interface NoteInfoProps {
|
|||||||
description?: React.ReactNode;
|
description?: React.ReactNode;
|
||||||
}
|
}
|
||||||
const NoteInfo: React.FC<NoteInfoProps> = (props) => {
|
const NoteInfo: React.FC<NoteInfoProps> = (props) => {
|
||||||
console.log('props+++++++++', props);
|
|
||||||
const { required, description, label } = props || {};
|
const { required, description, label } = props || {};
|
||||||
return (
|
return (
|
||||||
<span className="label-text">
|
<span className="label-text">
|
||||||
|
|||||||
@@ -167,4 +167,7 @@
|
|||||||
top: -20px;
|
top: -20px;
|
||||||
height: @wrapheight - 2px;
|
height: @wrapheight - 2px;
|
||||||
}
|
}
|
||||||
|
:global(.ant-input-group-addon) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
export const DEFAULT_NAME = 'Umi Max';
|
export const DEFAULT_NAME = 'seal';
|
||||||
|
|
||||||
export const INPUT_WIDTH = {
|
export const INPUT_WIDTH = {
|
||||||
default: 500,
|
default: 500,
|
||||||
large: 600,
|
large: 600,
|
||||||
small: 400
|
small: 400,
|
||||||
|
mini: 300
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-7
@@ -71,12 +71,6 @@ html {
|
|||||||
--ant-modal-footer-margin-top: 30px;
|
--ant-modal-footer-margin-top: 30px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.css-var-ru.ant-btn {
|
|
||||||
--ant-button-content-font-size-lg: 13px;
|
|
||||||
--ant-button-content-font-size: 12px;
|
|
||||||
--ant-button-content-font-size-sm: 12px;
|
|
||||||
--ant-modal-content-padding: 24px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.css-var-rf.ant-menu-css-var,
|
.css-var-rf.ant-menu-css-var,
|
||||||
.css-var-ri.ant-menu-css-var,
|
.css-var-ri.ant-menu-css-var,
|
||||||
@@ -236,5 +230,5 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ======== menu style end ============
|
// ======== menu style end ============
|
||||||
|
@import url('src/assets/styles/common.less');
|
||||||
@import url('src/assets/styles/menu.less');
|
@import url('src/assets/styles/menu.less');
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
const useCopyToClipboard = () => {
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
const copyToClipboard = useCallback(async (text: string) => {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard) {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setCopied(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { copied, copyToClipboard };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useCopyToClipboard;
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import CopyButton from '@/components/copy-button';
|
||||||
import ModalFooter from '@/components/modal-footer';
|
import ModalFooter from '@/components/modal-footer';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { CopyOutlined, SyncOutlined } from '@ant-design/icons';
|
import { SyncOutlined } from '@ant-design/icons';
|
||||||
import { Form, Modal } from 'antd';
|
import { Form, Modal } from 'antd';
|
||||||
|
|
||||||
type AddModalProps = {
|
type AddModalProps = {
|
||||||
@@ -27,9 +28,6 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
const RenderCopyButton = () => {
|
|
||||||
return <CopyOutlined></CopyOutlined>;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -52,7 +50,9 @@ const AddModal: React.FC<AddModalProps> = ({
|
|||||||
<Form.Item name="secretkey" rules={[{ required: true }]}>
|
<Form.Item name="secretkey" rules={[{ required: true }]}>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
label="Secret Key"
|
label="Secret Key"
|
||||||
addonAfter={<RenderCopyButton></RenderCopyButton>}
|
addonAfter={
|
||||||
|
<CopyButton text={form.getFieldValue('secretKey')}></CopyButton>
|
||||||
|
}
|
||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
SyncOutlined
|
SyncOutlined
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Button, Space, Tooltip } from 'antd';
|
import { Button, Space, Tooltip } from 'antd';
|
||||||
import chatStyle from './chat-style.less';
|
import chatStyle from '../style/chat-style.less';
|
||||||
import ChatEmpty from './chatEmpty';
|
import ChatEmpty from './chatEmpty';
|
||||||
|
|
||||||
export type ChatContentProps = {
|
export type ChatContentProps = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Logo from '@/assets/images/logo.png';
|
import Logo from '@/assets/images/logo.png';
|
||||||
import chatStyle from './chat-style.less';
|
import chatStyle from '../style/chat-style.less';
|
||||||
|
|
||||||
const ChatEmpty: React.FC = () => {
|
const ChatEmpty: React.FC = () => {
|
||||||
return (
|
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;
|
||||||
@@ -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 { SendOutlined } from '@ant-design/icons';
|
||||||
import { Button, Input } from 'antd';
|
import { Button, Input } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import './message-input.less';
|
import '../style/message-input.less';
|
||||||
|
|
||||||
const MessageInput: React.FC = () => {
|
const MessageInput: React.FC = () => {
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
|
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 { Button, Form, Select, Space } from 'antd';
|
import { Form, Slider } from 'antd';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
type ParamsSettingsProps = {
|
type ParamsSettingsProps = {
|
||||||
seed?: number;
|
seed?: number;
|
||||||
stopSequence?: number;
|
stopSequence?: number;
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
topK?: number;
|
|
||||||
topP?: number;
|
topP?: number;
|
||||||
repeatPenalty?: number;
|
model?: string;
|
||||||
repeatLastN?: number;
|
|
||||||
tfsZ?: number;
|
|
||||||
contextLength?: number;
|
|
||||||
maxTokens?: number;
|
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 ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
||||||
|
const [ModelList, setModelList] = useState(dataList);
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
seed: 1,
|
seed: 1,
|
||||||
stopSequence: 1,
|
stopSequence: 1,
|
||||||
@@ -51,134 +55,60 @@ const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
|||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onFinishFailed={handleOnFinishFailed}
|
onFinishFailed={handleOnFinishFailed}
|
||||||
>
|
>
|
||||||
<div
|
<div>
|
||||||
style={{
|
<h3 className="m-b-20 m-l-10">Model</h3>
|
||||||
maxHeight: '450px',
|
<Form.Item<ParamsSettingsProps>
|
||||||
overflow: 'auto',
|
name="model"
|
||||||
paddingRight: 'var(--ant-popover-inner-padding)'
|
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>
|
<Form.Item<ParamsSettingsProps>
|
||||||
name="seed"
|
name="seed"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
label="Seed"
|
label="Seed"
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
style={{ width: INPUT_WIDTH.mini }}
|
||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</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>
|
<Form.Item<ParamsSettingsProps>
|
||||||
name="stopSequence"
|
name="stopSequence"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<SealInput.Input
|
||||||
label="Stop Sequence"
|
label="Stop Sequence"
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
style={{ width: INPUT_WIDTH.mini }}
|
||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</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>
|
</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>
|
</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;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
export const Roles = {
|
||||||
|
User: 'User',
|
||||||
|
Assistant: 'Assistant'
|
||||||
|
};
|
||||||
|
export const playGroundRoles = [
|
||||||
|
{
|
||||||
|
key: 'user',
|
||||||
|
label: 'User'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'assistant',
|
||||||
|
label: 'Assistant'
|
||||||
|
}
|
||||||
|
];
|
||||||
@@ -1,19 +1,10 @@
|
|||||||
import { ControlOutlined } from '@ant-design/icons';
|
import { Divider } from 'antd';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { Button, Popover, Select, Space } from 'antd';
|
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import ChatContent from './components/chatContent';
|
import GroundLeft from './components/ground-left';
|
||||||
import MessageInput from './components/messageInput';
|
|
||||||
import ParamsSettings from './components/params-settings';
|
import ParamsSettings from './components/params-settings';
|
||||||
|
import './style/play-ground.less';
|
||||||
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 Playground: React.FC = () => {
|
const Playground: React.FC = () => {
|
||||||
const [ModelList, setModelList] = useState(dataList);
|
|
||||||
const [messageList, setMessageList] = useState<any[]>([]);
|
const [messageList, setMessageList] = useState<any[]>([]);
|
||||||
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
||||||
const [showPopover, setShowPopover] = useState(false);
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
@@ -41,49 +32,17 @@ const Playground: React.FC = () => {
|
|||||||
}, [selectedModel]);
|
}, [selectedModel]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer
|
<div className="play-ground">
|
||||||
title={false}
|
<div className="chat">
|
||||||
extra={[
|
<GroundLeft></GroundLeft>
|
||||||
<Space size={20} key="space">
|
|
||||||
<Select
|
|
||||||
showSearch
|
|
||||||
options={ModelList}
|
|
||||||
style={{ width: 300 }}
|
|
||||||
value={selectedModel}
|
|
||||||
onChange={handleSelectChange}
|
|
||||||
variant="filled"
|
|
||||||
key="model-select"
|
|
||||||
></Select>
|
|
||||||
<Popover
|
|
||||||
content={
|
|
||||||
<ParamsSettings onClose={handleClosePopover}></ParamsSettings>
|
|
||||||
}
|
|
||||||
destroyTooltipOnHide={true}
|
|
||||||
title="Params Settings"
|
|
||||||
trigger="click"
|
|
||||||
arrow={false}
|
|
||||||
open={showPopover}
|
|
||||||
overlayStyle={{ top: 70 }}
|
|
||||||
overlayInnerStyle={{ paddingRight: 0 }}
|
|
||||||
placement="bottomRight"
|
|
||||||
key="popover"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
onClick={handleTogglePopover}
|
|
||||||
type="primary"
|
|
||||||
shape="circle"
|
|
||||||
key="button"
|
|
||||||
icon={<ControlOutlined />}
|
|
||||||
></Button>
|
|
||||||
</Popover>
|
|
||||||
</Space>
|
|
||||||
]}
|
|
||||||
footer={[<MessageInput key="message" />]}
|
|
||||||
>
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
|
||||||
<ChatContent messageList={messageList}></ChatContent>
|
|
||||||
</div>
|
</div>
|
||||||
</PageContainer>
|
<div className="divider-line">
|
||||||
|
<Divider type="vertical" />
|
||||||
|
</div>
|
||||||
|
<div className="params">
|
||||||
|
<ParamsSettings onClose={handleClosePopover} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.chat-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-inline: 26px;
|
||||||
|
height: 100px;
|
||||||
|
// box-shadow: 0px -1px 2px 0px var(--ant-color-border);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.ground-left {
|
||||||
|
position: relative;
|
||||||
|
height: 100vh;
|
||||||
|
padding-bottom: 120px;
|
||||||
|
.message-list-wrap {
|
||||||
|
max-height: calc(100vh - 152px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.ground-left-footer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
.message-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
.role-type {
|
||||||
|
margin-right: 12px;
|
||||||
|
.ant-btn {
|
||||||
|
text-align: left;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.message-content-input {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
.play-ground {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
.chat {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.params {
|
||||||
|
// width: 465px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.divider-line {
|
||||||
|
width: 1px;
|
||||||
|
.ant-divider {
|
||||||
|
margin: 0;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.reference-params {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 40px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--ant-orange);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user