fix: model list watch data

This commit is contained in:
jialin
2024-07-15 08:21:06 +08:00
parent 0a0b96735c
commit ec28523daa
17 changed files with 119 additions and 61 deletions
+3 -1
View File
@@ -19,7 +19,9 @@ export default defineConfig({
history: { history: {
type: 'hash' type: 'hash'
}, },
// https: {
// http2: true
// },
base: process.env.npm_config_base || '/', base: process.env.npm_config_base || '/',
...(isProduction ...(isProduction
? { ? {
+1 -1
View File
@@ -1,5 +1,5 @@
.editor-wrap { .editor-wrap {
border-radius: 8px; border-radius: var(--border-radius-mini);
overflow: hidden; overflow: hidden;
.editor-header { .editor-header {
+1 -1
View File
@@ -3,7 +3,7 @@
padding: 5px 0 5px 10px; padding: 5px 0 5px 10px;
overflow: auto; overflow: auto;
background-color: var(--color-logs-bg); background-color: var(--color-logs-bg);
border-radius: var(--border-radius-small); border-radius: var(--border-radius-mini);
.content { .content {
word-wrap: break-word; word-wrap: break-word;
@@ -1,4 +1,3 @@
import React from 'react';
import '../styles/row-children.less'; import '../styles/row-children.less';
const RowChildren = (props: any) => { const RowChildren = (props: any) => {
@@ -7,4 +6,4 @@ const RowChildren = (props: any) => {
return <div className="row-children">{children}</div>; return <div className="row-children">{children}</div>;
}; };
export default React.memo(RowChildren); export default RowChildren;
@@ -4,7 +4,7 @@ import { DownOutlined, RightOutlined } from '@ant-design/icons';
import { Button, Checkbox, Col, Empty, Row, Spin } 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, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import RowContext from '../row-context'; import RowContext from '../row-context';
import { RowContextProps, SealTableProps } from '../types'; import { RowContextProps, SealTableProps } from '../types';
@@ -39,7 +39,8 @@ const TableRow: React.FC<
childrenDataRef.current = childrenData; childrenDataRef.current = childrenData;
console.log('table row====', record.name, firstLoad, expanded); console.log('table row====', record.name, firstLoad, expanded);
const { updateChunkedList } = useUpdateChunkedList({ const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
dataList: childrenData,
setDataList: setChildrenData setDataList: setChildrenData
// callback: (list) => renderChildren?.(list) // callback: (list) => renderChildren?.(list)
}); });
@@ -69,12 +70,13 @@ const TableRow: React.FC<
clearInterval(pollTimer.current); clearInterval(pollTimer.current);
} }
chunkRequestRef.current?.current?.cancel?.(); chunkRequestRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
}; };
}, []); }, []);
const renderChildrenData = () => { const renderChildrenData = useCallback(() => {
return renderChildren?.(childrenData); return renderChildren?.(childrenData);
}; }, [childrenData]);
const handlePolling = async () => { const handlePolling = async () => {
if (pollingChildren) { if (pollingChildren) {
@@ -91,8 +93,8 @@ const TableRow: React.FC<
console.log('first load=====', firstLoad); console.log('first load=====', firstLoad);
try { try {
setLoading(true); setLoading(true);
const data = await loadChildren?.(record); // const data = await loadChildren?.(record);
setChildrenData(data || []); // setChildrenData(data || []);
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
setChildrenData([]); setChildrenData([]);
@@ -171,6 +173,7 @@ const TableRow: React.FC<
} }
return () => { return () => {
chunkRequestRef.current?.current?.cancel?.(); chunkRequestRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
}; };
}, [firstLoad, expanded]); }, [firstLoad, expanded]);
+3
View File
@@ -38,6 +38,9 @@ export const modalConfig = {
centered: false, centered: false,
maskClosable: true, maskClosable: true,
footer: null, footer: null,
style: {
top: '30%'
},
width: 400 width: 400
}; };
+5 -1
View File
@@ -16,6 +16,7 @@ html {
--border-radius-base: 8px; --border-radius-base: 8px;
--border-radius-middle: 20px; --border-radius-middle: 20px;
--border-radius-small: 8px; --border-radius-small: 8px;
--border-radius-mini: 4px;
--color-white-1: rgba(255, 255, 255, 100%); --color-white-1: rgba(255, 255, 255, 100%);
--color-fill-sider: #f4f5f4; --color-fill-sider: #f4f5f4;
--font-weight-normal: 500; --font-weight-normal: 500;
@@ -51,6 +52,7 @@ html {
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%); --box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
--ant-border-radius-lg: 8px; --ant-border-radius-lg: 8px;
--ant-menu-item-color: var(--color-text-1); --ant-menu-item-color: var(--color-text-1);
--color-selected-bg: rgba(230, 230, 230, 88%);
// --box-shadow-base: none; // --box-shadow-base: none;
.css-var-rf { .css-var-rf {
@@ -104,8 +106,9 @@ html {
&.ant-modal-css-var { &.ant-modal-css-var {
--ant-modal-title-font-size: 14px; --ant-modal-title-font-size: 14px;
--ant-modal-header-margin-bottom: 26px; --ant-modal-header-margin-bottom: 20px;
--ant-modal-footer-margin-top: 30px; --ant-modal-footer-margin-top: 30px;
--ant-modal-content-padding: 20px 24px 24px;
} }
} }
@@ -129,6 +132,7 @@ html {
.css-var-r0.ant-select-css-var { .css-var-r0.ant-select-css-var {
--ant-select-option-active-bg: var(--color-fill-1); --ant-select-option-active-bg: var(--color-fill-1);
--ant-select-option-font-size: var(--font-size-base); --ant-select-option-font-size: var(--font-size-base);
--ant-select-option-selected-bg: var(--color-selected-bg);
} }
} }
+5
View File
@@ -1 +1,6 @@
// 应用前置、全局运行的逻辑时 会在这里执行 // 应用前置、全局运行的逻辑时 会在这里执行
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
+39 -31
View File
@@ -1,5 +1,6 @@
import { WatchEventType } from '@/config'; import { WatchEventType } from '@/config';
import _ from 'lodash'; import _ from 'lodash';
import { useRef } from 'react';
interface ChunkedCollection { interface ChunkedCollection {
ids: string[]; ids: string[];
@@ -9,16 +10,24 @@ interface ChunkedCollection {
} }
// Only used to update lists without nested state // Only used to update lists without nested state
export function useUpdateChunkedList(options: { export function useUpdateChunkedList(options: {
dataList?: any[];
setDataList: (args: any) => void; setDataList: (args: any) => void;
callback?: (args: any) => void; callback?: (args: any) => void;
filterFun?: (args: any) => boolean; filterFun?: (args: any) => boolean;
mapFun?: (args: any) => any; mapFun?: (args: any) => any;
computedID?: (d: object) => string; computedID?: (d: object) => string;
}) { }) {
const cacheDataListRef = useRef<any[]>([]);
const updateChunkedList = ( const updateChunkedList = (
data: ChunkedCollection, data: ChunkedCollection,
dataList: { id: string | number }[] dataList: { id: string | number }[]
) => { ) => {
console.log('updateChunkedList=====', {
ids: data?.ids,
type: data?.type,
collection: data?.collection,
dataList: _.map(dataList, (o: any) => o.id)
});
let collections = data?.collection || []; let collections = data?.collection || [];
if (options?.computedID) { if (options?.computedID) {
collections = _.map(collections, (item: any) => { collections = _.map(collections, (item: any) => {
@@ -35,10 +44,10 @@ export function useUpdateChunkedList(options: {
const ids = data?.ids || []; const ids = data?.ids || [];
// CREATE // CREATE
if (data?.type === WatchEventType.CREATE) { if (data?.type === WatchEventType.CREATE) {
const newDataList = _.cloneDeep(dataList); const newDataList: any[] = [];
_.each(collections, (item: any) => { _.each(collections, (item: any) => {
const updateIndex = _.findIndex( const updateIndex = _.findIndex(
dataList, cacheDataListRef.current,
(sItem: any) => sItem.id === item.id (sItem: any) => sItem.id === item.id
); );
if (updateIndex === -1) { if (updateIndex === -1) {
@@ -47,47 +56,46 @@ export function useUpdateChunkedList(options: {
} }
console.log('create=========', updateIndex, dataList, collections); console.log('create=========', updateIndex, dataList, collections);
}); });
options.setDataList?.(() => { cacheDataListRef.current = [...newDataList, ...cacheDataListRef.current];
return newDataList; options.setDataList?.(cacheDataListRef.current);
});
} }
// DELETE // DELETE
if (data?.type === WatchEventType.DELETE) { if (data?.type === WatchEventType.DELETE) {
options.setDataList?.(() => { cacheDataListRef.current = _.filter(
const updatedList = _.filter(dataList, (item: any) => { cacheDataListRef.current,
return !_.find(ids, (id: any) => id === item.id); (item: any) => {
}); return !_.includes(ids, item.id);
return updatedList; }
}); );
// console.log('updateChunkedList=====delete', updatedList);
// return updatedList;
options.setDataList?.(() => cacheDataListRef.current);
} }
// UPDATE // UPDATE
if (data?.type === WatchEventType.UPDATE) { if (data?.type === WatchEventType.UPDATE) {
options.setDataList?.(() => { // const updatedDataList = _.cloneDeep(dataList);
const updatedDataList = _.cloneDeep(dataList); _.each(collections, (item: any) => {
const updateIndex = _.findIndex(
_.each(collections, (item: any) => { cacheDataListRef.current,
const updateIndex = _.findIndex( (sItem: any) => sItem.id === item.id
updatedDataList, );
(sItem: any) => sItem.id === item.id if (updateIndex > -1) {
); const updateItem = _.cloneDeep(item);
if (updateIndex > -1) { cacheDataListRef.current[updateIndex] = updateItem;
const updateItem = _.cloneDeep(item); } else if (updateIndex === -1) {
updatedDataList[updateIndex] = updateItem; const updateItem = _.cloneDeep(item);
} else if (updateIndex === -1) { cacheDataListRef.current.push(updateItem);
const updateItem = _.cloneDeep(item); }
updatedDataList.push(updateItem);
}
});
return updatedDataList;
}); });
options.setDataList?.(() => cacheDataListRef.current);
} }
if (options?.callback) { if (options?.callback) {
options?.callback(dataList); options?.callback(cacheDataListRef.current);
} }
}; };
return { return {
updateChunkedList updateChunkedList,
cacheDataListRef
}; };
} }
+5 -5
View File
@@ -57,13 +57,13 @@ export default {
'common.table.default': 'Default Value', 'common.table.default': 'Default Value',
'common.copy.success': 'Copied success!', 'common.copy.success': 'Copied success!',
'common.copy.fail': 'Copied failed!', 'common.copy.fail': 'Copied failed!',
'common.delete.success': 'delete success!', 'common.delete.success': 'Delete success!',
'common.delete.fail': 'delete failed', 'common.delete.fail': 'Delete failed',
'common.edit.success': 'update success!', 'common.edit.success': 'Update success!',
'common.edit.fail': 'update failed', 'common.edit.fail': 'update failed',
'common.title.config': 'Configuration', 'common.title.config': 'Configuration',
'common.message.fail': 'failed!', 'common.message.fail': 'Failed!',
'common.message.success': 'succeed!', 'common.message.success': 'Succeed!',
'common.delete.tips': 'Are you sure you want to delete?', 'common.delete.tips': 'Are you sure you want to delete?',
'common.button.close': 'Close', 'common.button.close': 'Close',
'common.button.done': 'Done', 'common.button.done': 'Done',
+3 -1
View File
@@ -24,5 +24,7 @@ export default {
'playground.params.seed.tips': 'playground.params.seed.tips':
'If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result.', 'If specified, our system will make a best effort to sample deterministically, such that repeated requests with the same seed and parameters should return the same result.',
'playground.params.stop.tips': 'playground.params.stop.tips':
'A stop sequence is a predefined or user-specified text string that signals the AI to stop generating further tokens when these sequences appear.' 'A stop sequence is a predefined or user-specified text string that signals the AI to stop generating further tokens when these sequences appear.',
'playground.viewcode.tips': 'Your API Key can be found {here}.',
'playground.viewcode.here': 'here'
}; };
+3 -1
View File
@@ -24,5 +24,7 @@ export default {
'playground.params.seed.tips': 'playground.params.seed.tips':
'如果指定,我们的系统将尽最大努力进行确定性采样,以便使用相同 seed 和参数的重复请求应返回相同的结果。', '如果指定,我们的系统将尽最大努力进行确定性采样,以便使用相同 seed 和参数的重复请求应返回相同的结果。',
'playground.params.stop.tips': 'playground.params.stop.tips':
'停止序列是一个预定义或用户指定的文本字符串,当这些序列出现时,它会提示 AI 停止生成后续的 token。' '停止序列是一个预定义或用户指定的文本字符串,当这些序列出现时,它会提示 AI 停止生成后续的 token。',
'playground.viewcode.tips': '{here} 查看 API 密钥。',
'playground.viewcode.here': '这里'
}; };
@@ -121,7 +121,7 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
</Col> </Col>
<Col span={5}> <Col span={5}>
<span style={{ paddingLeft: 38 }}> <span style={{ paddingLeft: 38 }}>
{dayjs(item.updated_at).format('YYYY-MM-DD HH:mm:ss')} {dayjs.utc(item.created_at).format('YYYY-MM-DD HH:mm:ss')}
</span> </span>
</Col> </Col>
<Col span={4}> <Col span={4}>
+1 -2
View File
@@ -371,8 +371,7 @@ const Models: React.FC<ModelsProps> = ({
showSorterTooltip={false} showSorterTooltip={false}
sorter={true} sorter={true}
render={(val, row) => { render={(val, row) => {
console.log('val=====', val, row['created_at'], row.name); return dayjs.utc(val).format('YYYY-MM-DD HH:mm:ss');
return dayjs(val).format('YYYY-MM-DD HH:mm:ss');
}} }}
/> />
<SealColumn <SealColumn
@@ -15,7 +15,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const { open, url, onCancel } = props || {}; const { open, url, onCancel } = props || {};
const [modalSize, setModalSize] = useState<any>({ const [modalSize, setModalSize] = useState<any>({
width: 600, width: 600,
height: 450 height: 420
}); });
const isFullScreenRef = React.useRef(false); const isFullScreenRef = React.useRef(false);
const intl = useIntl(); const intl = useIntl();
@@ -24,7 +24,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
setModalSize((size: any) => { setModalSize((size: any) => {
return { return {
width: size.width === 600 ? '100%' : 600, width: size.width === 600 ? '100%' : 600,
height: size.height === 450 ? 'calc(100vh - 100px)' : 450 height: size.height === 420 ? 'calc(100vh - 100px)' : 420
}; };
}); });
}; };
+7 -2
View File
@@ -30,7 +30,8 @@ const Models: React.FC = () => {
dataSourceRef.current = dataSource; dataSourceRef.current = dataSource;
const { updateChunkedList } = useUpdateChunkedList({ const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
dataList: dataSource,
setDataList: setDataSource setDataList: setDataSource
}); });
@@ -46,7 +47,9 @@ const Models: React.FC = () => {
cancelToken: axiosToken.token cancelToken: axiosToken.token
}); });
console.log('res=======', res); console.log('res=======', res);
setDataSource(res.items); if (!firstLoad) {
setDataSource(res.items);
}
setTotal(res.pagination.total); setTotal(res.pagination.total);
} catch (error) { } catch (error) {
setDataSource([]); setDataSource([]);
@@ -118,8 +121,10 @@ const Models: React.FC = () => {
if (!firstLoad) { if (!firstLoad) {
createModelsChunkRequest(); createModelsChunkRequest();
} }
createModelsChunkRequest();
return () => { return () => {
chunkRequedtRef.current?.current?.cancel?.(); chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
}; };
}, [firstLoad]); }, [firstLoad]);
@@ -1,7 +1,8 @@
import EditorWrap from '@/components/editor-wrap'; import EditorWrap from '@/components/editor-wrap';
import { BulbOutlined } from '@ant-design/icons';
import Editor from '@monaco-editor/react'; import Editor from '@monaco-editor/react';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Modal, Spin } from 'antd'; import { Button, Modal, Spin } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
@@ -30,6 +31,8 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const [codeValue, setCodeValue] = useState(''); const [codeValue, setCodeValue] = useState('');
const [lang, setLang] = useState('shell'); const [lang, setLang] = useState('shell');
const BaseURL = `${window.location.origin}/v1-openai/chat/completions`;
const langOptions = [ const langOptions = [
{ label: 'Curl', value: 'shell' }, { label: 'Curl', value: 'shell' },
{ label: 'Python', value: 'python' }, { label: 'Python', value: 'python' },
@@ -66,7 +69,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const systemList = systemMessage const systemList = systemMessage
? [{ role: 'system', content: systemMessage }] ? [{ role: 'system', content: systemMessage }]
: []; : [];
const code = `import OpenAI from "openai";\nconst openai = new OpenAI();\n\nasync function main(){\nconst params = ${JSON.stringify( const code = `import OpenAI from "openai";\nconst openai = new OpenAI();\n\nconst baseURL = "${BaseURL}"\n\nasync function main(){\nconst params = ${JSON.stringify(
{ {
...parameters, ...parameters,
messages: [...systemList, ...messageList] messages: [...systemList, ...messageList]
@@ -92,7 +95,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const systemList = systemMessage const systemList = systemMessage
? [{ role: 'system', content: systemMessage }] ? [{ role: 'system', content: systemMessage }]
: []; : [];
const code = `from openai import OpenAI\nclient = OpenAI()\n\ncompletion = client.chat.completions.create(\n${formattedParams} messages=${JSON.stringify([...systemList, ...messageList], null, 2)})\nprint(completion.choices[0].message)`; const code = `from openai import OpenAI\nclient = OpenAI()\n\nbaseURL = ${BaseURL}\n\ncompletion = client.chat.completions.create(\n${formattedParams} messages=${JSON.stringify([...systemList, ...messageList], null, 2)})\nprint(completion.choices[0].message)`;
setCodeValue(code); setCodeValue(code);
} }
formatCode(); formatCode();
@@ -152,7 +155,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onChangeLang={handleOnChangeLang} onChangeLang={handleOnChangeLang}
> >
<Editor <Editor
height="min(450px, 90vh)" height={380}
theme="vs-dark" theme="vs-dark"
className="monaco-editor" className="monaco-editor"
defaultLanguage="shell" defaultLanguage="shell"
@@ -162,6 +165,29 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onMount={handleEditorDidMount} onMount={handleEditorDidMount}
/> />
</EditorWrap> </EditorWrap>
<div style={{ marginTop: 10 }}>
<BulbOutlined className="m-r-8" />
<span>
{intl.formatMessage(
{ id: 'playground.viewcode.tips' },
{
here: (
<Button
type="link"
size="small"
href="#/api-keys"
target="_blank"
>
<span>
{' '}
{intl.formatMessage({ id: 'playground.viewcode.here' })}
</span>
</Button>
)
}
)}
</span>
</div>
</Spin> </Spin>
</Modal> </Modal>
</> </>