fix: ux bug

This commit is contained in:
jialin
2024-07-02 17:30:03 +08:00
parent 49efbd1a7f
commit 316019586f
19 changed files with 102 additions and 133 deletions
+10
View File
@@ -14,6 +14,16 @@ export default {
iconSize: 16, iconSize: 16,
iconMarginInlineEnd: 12, iconMarginInlineEnd: 12,
itemHeight: 44 itemHeight: 44
},
Progress: {
lineBorderRadius: 4
},
Slider: {
handleSize: 8,
handleSizeHover: 10
// handleColor: '#007BFF'
// trackBg: '#007BFF',
// trackHoverBg: '#007BFF'
} }
}, },
token: { token: {
+1 -1
View File
@@ -30,7 +30,7 @@ const LineChart: React.FC<LineChartProps> = (props) => {
yField: yField || 'value', yField: yField || 'value',
autoFit: true, autoFit: true,
slider, slider,
shapeField: 'smooth', // shapeField: 'smooth',
axis: { axis: {
x: { x: {
textStyle: { textStyle: {
@@ -5,7 +5,6 @@
height: 54px; height: 54px;
padding: 0 16px; padding: 0 16px;
border-radius: var(--ant-table-header-border-radius); border-radius: var(--ant-table-header-border-radius);
background-color: var(--color-fill-1);
transition: all 0.2s ease; transition: all 0.2s ease;
&:hover { &:hover {
+1 -1
View File
@@ -12,7 +12,7 @@
overflow: hidden; overflow: hidden;
&.download { &.download {
background-color: rgb(47 191 133 / 30%); background-color: var(--ant-blue-2);
} }
.download { .download {
+9 -1
View File
@@ -13,11 +13,18 @@ interface TransitionWrapProps {
header?: React.ReactNode; header?: React.ReactNode;
variant?: 'bordered' | 'filled'; variant?: 'bordered' | 'filled';
children: React.ReactNode; children: React.ReactNode;
setCollapsed?: (val: boolean) => void;
ref?: any; ref?: any;
} }
const TransitionWrapper: React.FC<TransitionWrapProps> = forwardRef( const TransitionWrapper: React.FC<TransitionWrapProps> = forwardRef(
(props, ref) => { (props, ref) => {
const { minHeight = 50, header, variant = 'bordered', children } = props; const {
minHeight = 50,
header,
variant = 'bordered',
children,
setCollapsed
} = props;
const [isOpen, setIsOpen] = useState(true); const [isOpen, setIsOpen] = useState(true);
const [height, setHeight] = useState(0); const [height, setHeight] = useState(0);
const contentRef = useRef(null); const contentRef = useRef(null);
@@ -32,6 +39,7 @@ const TransitionWrapper: React.FC<TransitionWrapProps> = forwardRef(
const toggleOpen = () => { const toggleOpen = () => {
setIsOpen(!isOpen); setIsOpen(!isOpen);
setCollapsed?.(!isOpen);
}; };
const setHeightByContent = () => { const setHeightByContent = () => {
+4
View File
@@ -131,6 +131,10 @@ body * {
} }
body { body {
.ant-modal-confirm-title {
display: none;
}
.ant-checkbox { .ant-checkbox {
.ant-checkbox-inner { .ant-checkbox-inner {
border-radius: var(--checkbox-border-radius) !important; border-radius: var(--checkbox-border-radius) !important;
+2 -1
View File
@@ -13,5 +13,6 @@ export default {
'playground.completion': 'Completion', 'playground.completion': 'Completion',
'playground.prompt': 'Prompt', 'playground.prompt': 'Prompt',
'playground.tokenusage': 'Token Usage', 'playground.tokenusage': 'Token Usage',
'models.openinplayground': 'Open in Playground' 'models.openinplayground': 'Open in Playground',
'playground.tokenoutput': 'Output'
}; };
+3 -1
View File
@@ -12,5 +12,7 @@ export default {
'你可以使用以下代码将当前的提示和设置集成到你的应用程序中。', '你可以使用以下代码将当前的提示和设置集成到你的应用程序中。',
'playground.completion': '补全', 'playground.completion': '补全',
'playground.prompt': '提示', 'playground.prompt': '提示',
'playground.tokenusage': 'Token 使用量' 'playground.tokenusage': 'Token 使用量',
'models.openinplayground': '试验场打开',
'playground.tokenoutput': '输出'
}; };
@@ -25,13 +25,13 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
closeIcon={true} closeIcon={true}
maskClosable={false} maskClosable={false}
keyboard={false} keyboard={false}
width={600} width={'max(50%, 600px)'}
style={{ top: '80px' }} style={{ top: '80px' }}
footer={null} footer={null}
> >
<LogsViewer <LogsViewer
content={content} content={content}
height={400} height={500}
url={url} url={url}
params={{ params={{
follow: false follow: false
+5 -80
View File
@@ -9,12 +9,10 @@ import type { PageActionType } from '@/config/types';
import useSetChunkRequest, { import useSetChunkRequest, {
createAxiosToken createAxiosToken
} from '@/hooks/use-chunk-request'; } from '@/hooks/use-chunk-request';
import useEventSource from '@/hooks/use-event-source';
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 useUpdateChunkedList from '@/hooks/use-update-chunk-list'; import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
import { handleBatchRequest } from '@/utils'; import { handleBatchRequest } from '@/utils';
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
import { import {
DeleteOutlined, DeleteOutlined,
EditOutlined, EditOutlined,
@@ -33,7 +31,6 @@ import {
MODELS_API, MODELS_API,
MODEL_INSTANCE_API, MODEL_INSTANCE_API,
createModel, createModel,
createModelInstance,
deleteModel, deleteModel,
deleteModelInstance, deleteModelInstance,
queryModelInstancesList, queryModelInstancesList,
@@ -55,7 +52,6 @@ const Models: React.FC = () => {
const { sortOrder, setSortOrder } = useTableSort({ const { sortOrder, setSortOrder } = useTableSort({
defaultSortOrder: 'descend' defaultSortOrder: 'descend'
}); });
const { createEventSourceConnection, eventSourceRef } = useEventSource();
const [logContent, setLogContent] = useState(''); const [logContent, setLogContent] = useState('');
const [openLogModal, setOpenLogModal] = useState(false); const [openLogModal, setOpenLogModal] = useState(false);
const [hoverChildIndex, setHoverChildIndex] = useState<string | number>(-1); const [hoverChildIndex, setHoverChildIndex] = useState<string | number>(-1);
@@ -137,14 +133,6 @@ const Models: React.FC = () => {
} }
}; };
// update data by polling
const fetchDataByPolling = () => {
clearInterval(timer.current);
timer.current = setInterval(() => {
fetchData(true);
}, 5000);
};
const handleShowSizeChange = (page: number, size: number) => { const handleShowSizeChange = (page: number, size: number) => {
console.log(page, size); console.log(page, size);
setQueryParams({ setQueryParams({
@@ -194,38 +182,6 @@ const Models: React.FC = () => {
} }
}; };
const createModelsDataByFetch = async () => {
const result = await fetchChunkedData({
params: {
..._.pickBy(queryParams, (val: any) => !!val),
watch: true
},
method: 'GET',
url: `/v1${MODELS_API}`
});
if (!result) {
return;
}
const { reader, decoder } = result;
await readStreamData(reader, decoder, (data: any) => {
console.log('streamData=========', data);
});
};
const createModelEvent = () => {
createEventSourceConnection({
url: `v1${MODELS_API}`,
params: {
..._.pickBy(queryParams, (val: any) => !!val),
watch: true
},
onmessage: (data: any) => {
console.log('event source message: ', data);
}
});
};
const handleSearch = (e: any) => { const handleSearch = (e: any) => {
fetchData(); fetchData();
}; };
@@ -303,44 +259,9 @@ const Models: React.FC = () => {
navigate(`/playground?model=${row.name}`); navigate(`/playground?model=${row.name}`);
}; };
const handleDeployInstance = async (row: any) => {
try {
const data = {
model_id: row.id,
model_name: row.name,
huggingface_repo_id: row.huggingface_repo_id,
huggingface_filename: row.huggingface_filename,
source: row.source
};
await createModelInstance({ data });
message.success(intl.formatMessage({ id: 'common.message.success' }));
} catch (error) {}
};
const handleStreamData = (data: any) => {
setLogContent(data);
};
const handleViewLogs = async (row: any) => { const handleViewLogs = async (row: any) => {
try { try {
// const result = await fetchChunkedData({
// url: `/v1${MODEL_INSTANCE_API}/${row.id}/logs`,
// params: {
// follow: false
// },
// method: 'GET'
// });
// if (!result) {
// setLogContent('');
// } else {
// const { reader, decoder } = result;
// await readStreamData(reader, decoder, (chunk: any) => {
// handleStreamData(chunk);
// });
// }
setCurrentInstanceUrl(`${MODEL_INSTANCE_API}/${row.id}/logs`); setCurrentInstanceUrl(`${MODEL_INSTANCE_API}/${row.id}/logs`);
setOpenLogModal(true); setOpenLogModal(true);
} catch (error) { } catch (error) {
console.log('error:', error); console.log('error:', error);
@@ -433,7 +354,9 @@ const Models: React.FC = () => {
onMouseLeave={handleOnMouseLeave} onMouseLeave={handleOnMouseLeave}
style={{ borderRadius: 'var(--ant-table-header-border-radius)' }} style={{ borderRadius: 'var(--ant-table-header-border-radius)' }}
className={ className={
item.download_progress !== 100 ? 'skeleton-loading' : '' item.download_progress !== 100 && item.state !== 'Running'
? 'skeleton-loading'
: ''
} }
> >
<RowChildren key={`${item.id}_row`}> <RowChildren key={`${item.id}_row`}>
@@ -444,6 +367,7 @@ const Models: React.FC = () => {
</Col> </Col>
<Col span={4}> <Col span={4}>
<span style={{ paddingLeft: '22px' }}>
{item.state && ( {item.state && (
<StatusTag <StatusTag
download={ download={
@@ -457,6 +381,7 @@ const Models: React.FC = () => {
}} }}
></StatusTag> ></StatusTag>
)} )}
</span>
</Col> </Col>
<Col span={5}> <Col span={5}>
<span style={{ paddingLeft: 36 }}> <span style={{ paddingLeft: 36 }}>
@@ -1,7 +1,7 @@
import TransitionWrapper from '@/components/transition'; import TransitionWrapper from '@/components/transition';
import HotKeys from '@/config/hotkeys'; import HotKeys from '@/config/hotkeys';
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data'; import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
import { EyeInvisibleOutlined } from '@ant-design/icons'; import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Input, Spin } from 'antd'; import { Button, Input, Spin } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
@@ -39,6 +39,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
const intl = useIntl(); const intl = useIntl();
const [systemMessage, setSystemMessage] = useState(''); const [systemMessage, setSystemMessage] = useState('');
const [collapsed, setCollapsed] = useState(true);
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1); const [activeIndex, setActiveIndex] = useState(-1);
@@ -56,7 +57,8 @@ const MessageList: React.FC<MessageProps> = (props) => {
}; };
const handleNewMessage = () => { const handleNewMessage = () => {
messageList.push({ messageList.push({
role: 'user', role:
_.last(messageList)?.role === Roles.User ? Roles.Assistant : Roles.User,
content: '', content: '',
uid: messageId.current + 1 uid: messageId.current + 1
}); });
@@ -95,7 +97,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
messages: systemMessage messages: systemMessage
? [ ? [
{ {
role: 'system', role: Roles.System,
content: systemMessage content: systemMessage
}, },
...messageList ...messageList
@@ -124,7 +126,8 @@ const MessageList: React.FC<MessageProps> = (props) => {
} }
}; };
const handleClear = () => { const handleClear = () => {
setMessageList([]); const headItem = _.get(messageList, '0');
setMessageList(headItem ? [headItem] : []);
}; };
const handleView = () => { const handleView = () => {
@@ -156,7 +159,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
{intl.formatMessage({ id: 'playground.system' })} {intl.formatMessage({ id: 'playground.system' })}
</span> </span>
<Button type="primary" size="small"> <Button type="primary" size="small">
<EyeInvisibleOutlined /> {collapsed ? <EyeInvisibleOutlined /> : <EyeOutlined />}
</Button> </Button>
</div> </div>
); );
@@ -189,6 +192,7 @@ const MessageList: React.FC<MessageProps> = (props) => {
<TransitionWrapper <TransitionWrapper
header={renderLabel()} header={renderLabel()}
variant="filled" variant="filled"
setCollapsed={setCollapsed}
ref={systemRef} ref={systemRef}
> >
<Input.TextArea <Input.TextArea
@@ -1,7 +1,8 @@
import CopyButton from '@/components/copy-button';
import HotKeys from '@/config/hotkeys'; import HotKeys from '@/config/hotkeys';
import { MinusCircleOutlined } from '@ant-design/icons'; import { MinusCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Input } from 'antd'; import { Button, Input, Space } from 'antd';
import { memo, useEffect, useRef, useState } from 'react'; import { memo, useEffect, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook'; import { useHotkeys } from 'react-hotkeys-hook';
import { Roles } from '../config'; import { Roles } from '../config';
@@ -129,6 +130,10 @@ const MessageItem: React.FC<{
></Input.TextArea> ></Input.TextArea>
</div> </div>
<div className="delete-btn"> <div className="delete-btn">
<Space size={5}>
{messageContent && (
<CopyButton text={messageContent} size="small"></CopyButton>
)}
<Button <Button
type="text" type="text"
shape="circle" shape="circle"
@@ -137,6 +142,7 @@ const MessageItem: React.FC<{
onClick={handleDelete} onClick={handleDelete}
icon={<MinusCircleOutlined />} icon={<MinusCircleOutlined />}
></Button> ></Button>
</Space>
</div> </div>
</div> </div>
); );
@@ -162,14 +162,14 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
field: 'temperature', field: 'temperature',
label: 'Temperature' label: 'Temperature'
})} })}
style={{ paddingLeft: 0 }} style={{ paddingInline: 0 }}
variant="borderless" variant="borderless"
> >
<Slider <Slider
defaultValue={1} defaultValue={1}
max={2} max={2}
step={0.1} step={0.1}
style={{ marginBottom: 0 }} style={{ marginBottom: 0, marginTop: 16 }}
tooltip={{ open: false }} tooltip={{ open: false }}
value={form.getFieldValue('temperature') || undefined} value={form.getFieldValue('temperature') || undefined}
onChange={(val) => handleFieldValueChange(val, 'temperature')} onChange={(val) => handleFieldValueChange(val, 'temperature')}
@@ -185,14 +185,14 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
field: 'max_tokens', field: 'max_tokens',
label: 'Max Tokens' label: 'Max Tokens'
})} })}
style={{ paddingLeft: 0 }} style={{ paddingInline: 0 }}
variant="borderless" variant="borderless"
> >
<Slider <Slider
defaultValue={1024} defaultValue={1024}
max={16384} max={16384}
step={1} step={1}
style={{ marginBottom: 0 }} style={{ marginBottom: 0, marginTop: 16 }}
tooltip={{ open: false }} tooltip={{ open: false }}
value={form.getFieldValue('max_tokens') || undefined} value={form.getFieldValue('max_tokens') || undefined}
onChange={(val) => handleFieldValueChange(val, 'max_tokens')} onChange={(val) => handleFieldValueChange(val, 'max_tokens')}
@@ -208,14 +208,14 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
field: 'top_p', field: 'top_p',
label: 'Top P' label: 'Top P'
})} })}
style={{ paddingLeft: 0 }} style={{ paddingInline: 0 }}
variant="borderless" variant="borderless"
> >
<Slider <Slider
defaultValue={1} defaultValue={1}
max={1} max={1}
step={0.1} step={0.1}
style={{ marginBottom: 0 }} style={{ marginBottom: 0, marginTop: 16 }}
tooltip={{ open: false }} tooltip={{ open: false }}
value={form.getFieldValue('top_p') || undefined} value={form.getFieldValue('top_p') || undefined}
onChange={(val) => handleFieldValueChange(val, 'top_p')} onChange={(val) => handleFieldValueChange(val, 'top_p')}
@@ -231,7 +231,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
field: 'seed', field: 'seed',
label: 'Seed' label: 'Seed'
})} })}
style={{ paddingLeft: 0 }} style={{ paddingInline: 0 }}
variant="borderless" variant="borderless"
> >
<Slider <Slider
@@ -240,13 +240,9 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = ({
tooltip={{ open: false }} tooltip={{ open: false }}
value={form.getFieldValue('seed') || undefined} value={form.getFieldValue('seed') || undefined}
onChange={(val) => handleFieldValueChange(val, 'seed')} onChange={(val) => handleFieldValueChange(val, 'seed')}
style={{ marginBottom: 0 }} style={{ marginBottom: 0, marginTop: 16 }}
></Slider> ></Slider>
</FieldWrapper> </FieldWrapper>
{/* <SealInput.Number
label="Seed"
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Number> */}
</Form.Item> </Form.Item>
<Form.Item<ParamsSettingsFormProps> <Form.Item<ParamsSettingsFormProps>
name="stop" name="stop"
@@ -7,6 +7,7 @@ interface ReferenceParamsProps {
completion_tokens: number; completion_tokens: number;
prompt_tokens: number; prompt_tokens: number;
total_tokens: number; total_tokens: number;
time_per_output_token_ms: number;
}; };
} }
@@ -37,6 +38,11 @@ const ReferenceParams = (props: ReferenceParamsProps) => {
{usage.total_tokens} {usage.total_tokens}
</span> </span>
</Tooltip> </Tooltip>
<span>
{intl.formatMessage({ id: 'playground.tokenoutput' })}:{' '}
{usage.time_per_output_token_ms} token/s
</span>
</div> </div>
); );
}; };
@@ -135,7 +135,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
closeIcon={true} closeIcon={true}
maskClosable={false} maskClosable={false}
keyboard={false} keyboard={false}
width={600} width={'max(50%, 600px)'}
style={{ top: '80px' }} style={{ top: '80px' }}
footer={null} footer={null}
> >
@@ -151,7 +151,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onChangeLang={handleOnChangeLang} onChangeLang={handleOnChangeLang}
> >
<Editor <Editor
height="400px" height="500px"
theme="vs-dark" theme="vs-dark"
className="monaco-editor" className="monaco-editor"
defaultLanguage="shell" defaultLanguage="shell"
+2 -1
View File
@@ -1,6 +1,7 @@
export const Roles = { export const Roles = {
User: 'user', User: 'user',
Assistant: 'assistant' Assistant: 'assistant',
System: 'system'
}; };
export const playGroundRoles = [ export const playGroundRoles = [
{ {
+1 -1
View File
@@ -7,7 +7,7 @@
:global(.label-val) { :global(.label-val) {
position: absolute; position: absolute;
top: -14px; top: -14px;
right: 26px; right: 2px;
width: 80px; width: 80px;
border-radius: 8px; border-radius: 8px;
text-align: center; text-align: center;
+8 -2
View File
@@ -4,15 +4,18 @@
justify-content: flex-start; justify-content: flex-start;
align-items: flex-start; align-items: flex-start;
margin-bottom: 12px; margin-bottom: 12px;
&:hover { &:hover {
.delete-btn { .delete-btn {
opacity: 1; opacity: 1;
transition: all 0.3s var(--seal-transition-func); transition: all 0.3s var(--seal-transition-func);
} }
} }
.role-type { .role-type {
margin-right: 12px; margin-right: 12px;
background-color: var(--ant-button-text-hover-bg); background-color: var(--ant-button-text-hover-bg);
.ant-btn { .ant-btn {
text-align: left; text-align: left;
width: 100px; width: 100px;
@@ -20,17 +23,20 @@
height: 46px; height: 46px;
} }
} }
.message-content-input { .message-content-input {
flex: 1; flex: 1;
.ant-input { .ant-input {
padding-right: 30px; padding-right: 40px;
} }
} }
.delete-btn { .delete-btn {
opacity: 0; opacity: 0;
position: absolute; position: absolute;
top: 2px; top: 2px;
right: 0; right: 2px;
transition: all 0.3s var(--seal-transition-func); transition: all 0.3s var(--seal-transition-func);
} }
} }
@@ -5,4 +5,5 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: var(--ant-orange); color: var(--ant-orange);
gap: 20px;
} }