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: {
type: 'hash'
},
// https: {
// http2: true
// },
base: process.env.npm_config_base || '/',
...(isProduction
? {
+1 -1
View File
@@ -1,5 +1,5 @@
.editor-wrap {
border-radius: 8px;
border-radius: var(--border-radius-mini);
overflow: hidden;
.editor-header {
+1 -1
View File
@@ -3,7 +3,7 @@
padding: 5px 0 5px 10px;
overflow: auto;
background-color: var(--color-logs-bg);
border-radius: var(--border-radius-small);
border-radius: var(--border-radius-mini);
.content {
word-wrap: break-word;
@@ -1,4 +1,3 @@
import React from 'react';
import '../styles/row-children.less';
const RowChildren = (props: any) => {
@@ -7,4 +6,4 @@ const RowChildren = (props: any) => {
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 classNames from 'classnames';
import _ from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import RowContext from '../row-context';
import { RowContextProps, SealTableProps } from '../types';
@@ -39,7 +39,8 @@ const TableRow: React.FC<
childrenDataRef.current = childrenData;
console.log('table row====', record.name, firstLoad, expanded);
const { updateChunkedList } = useUpdateChunkedList({
const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
dataList: childrenData,
setDataList: setChildrenData
// callback: (list) => renderChildren?.(list)
});
@@ -69,12 +70,13 @@ const TableRow: React.FC<
clearInterval(pollTimer.current);
}
chunkRequestRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
};
}, []);
const renderChildrenData = () => {
const renderChildrenData = useCallback(() => {
return renderChildren?.(childrenData);
};
}, [childrenData]);
const handlePolling = async () => {
if (pollingChildren) {
@@ -91,8 +93,8 @@ const TableRow: React.FC<
console.log('first load=====', firstLoad);
try {
setLoading(true);
const data = await loadChildren?.(record);
setChildrenData(data || []);
// const data = await loadChildren?.(record);
// setChildrenData(data || []);
setLoading(false);
} catch (error) {
setChildrenData([]);
@@ -171,6 +173,7 @@ const TableRow: React.FC<
}
return () => {
chunkRequestRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
};
}, [firstLoad, expanded]);
+3
View File
@@ -38,6 +38,9 @@ export const modalConfig = {
centered: false,
maskClosable: true,
footer: null,
style: {
top: '30%'
},
width: 400
};
+5 -1
View File
@@ -16,6 +16,7 @@ html {
--border-radius-base: 8px;
--border-radius-middle: 20px;
--border-radius-small: 8px;
--border-radius-mini: 4px;
--color-white-1: rgba(255, 255, 255, 100%);
--color-fill-sider: #f4f5f4;
--font-weight-normal: 500;
@@ -51,6 +52,7 @@ html {
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
--ant-border-radius-lg: 8px;
--ant-menu-item-color: var(--color-text-1);
--color-selected-bg: rgba(230, 230, 230, 88%);
// --box-shadow-base: none;
.css-var-rf {
@@ -104,8 +106,9 @@ html {
&.ant-modal-css-var {
--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-content-padding: 20px 24px 24px;
}
}
@@ -129,6 +132,7 @@ html {
.css-var-r0.ant-select-css-var {
--ant-select-option-active-bg: var(--color-fill-1);
--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 _ from 'lodash';
import { useRef } from 'react';
interface ChunkedCollection {
ids: string[];
@@ -9,16 +10,24 @@ interface ChunkedCollection {
}
// Only used to update lists without nested state
export function useUpdateChunkedList(options: {
dataList?: any[];
setDataList: (args: any) => void;
callback?: (args: any) => void;
filterFun?: (args: any) => boolean;
mapFun?: (args: any) => any;
computedID?: (d: object) => string;
}) {
const cacheDataListRef = useRef<any[]>([]);
const updateChunkedList = (
data: ChunkedCollection,
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 || [];
if (options?.computedID) {
collections = _.map(collections, (item: any) => {
@@ -35,10 +44,10 @@ export function useUpdateChunkedList(options: {
const ids = data?.ids || [];
// CREATE
if (data?.type === WatchEventType.CREATE) {
const newDataList = _.cloneDeep(dataList);
const newDataList: any[] = [];
_.each(collections, (item: any) => {
const updateIndex = _.findIndex(
dataList,
cacheDataListRef.current,
(sItem: any) => sItem.id === item.id
);
if (updateIndex === -1) {
@@ -47,47 +56,46 @@ export function useUpdateChunkedList(options: {
}
console.log('create=========', updateIndex, dataList, collections);
});
options.setDataList?.(() => {
return newDataList;
});
cacheDataListRef.current = [...newDataList, ...cacheDataListRef.current];
options.setDataList?.(cacheDataListRef.current);
}
// DELETE
if (data?.type === WatchEventType.DELETE) {
options.setDataList?.(() => {
const updatedList = _.filter(dataList, (item: any) => {
return !_.find(ids, (id: any) => id === item.id);
});
return updatedList;
});
cacheDataListRef.current = _.filter(
cacheDataListRef.current,
(item: any) => {
return !_.includes(ids, item.id);
}
);
// console.log('updateChunkedList=====delete', updatedList);
// return updatedList;
options.setDataList?.(() => cacheDataListRef.current);
}
// UPDATE
if (data?.type === WatchEventType.UPDATE) {
options.setDataList?.(() => {
const updatedDataList = _.cloneDeep(dataList);
_.each(collections, (item: any) => {
const updateIndex = _.findIndex(
updatedDataList,
(sItem: any) => sItem.id === item.id
);
if (updateIndex > -1) {
const updateItem = _.cloneDeep(item);
updatedDataList[updateIndex] = updateItem;
} else if (updateIndex === -1) {
const updateItem = _.cloneDeep(item);
updatedDataList.push(updateItem);
}
});
return updatedDataList;
// const updatedDataList = _.cloneDeep(dataList);
_.each(collections, (item: any) => {
const updateIndex = _.findIndex(
cacheDataListRef.current,
(sItem: any) => sItem.id === item.id
);
if (updateIndex > -1) {
const updateItem = _.cloneDeep(item);
cacheDataListRef.current[updateIndex] = updateItem;
} else if (updateIndex === -1) {
const updateItem = _.cloneDeep(item);
cacheDataListRef.current.push(updateItem);
}
});
options.setDataList?.(() => cacheDataListRef.current);
}
if (options?.callback) {
options?.callback(dataList);
options?.callback(cacheDataListRef.current);
}
};
return {
updateChunkedList
updateChunkedList,
cacheDataListRef
};
}
+5 -5
View File
@@ -57,13 +57,13 @@ export default {
'common.table.default': 'Default Value',
'common.copy.success': 'Copied success!',
'common.copy.fail': 'Copied failed!',
'common.delete.success': 'delete success!',
'common.delete.fail': 'delete failed',
'common.edit.success': 'update success!',
'common.delete.success': 'Delete success!',
'common.delete.fail': 'Delete failed',
'common.edit.success': 'Update success!',
'common.edit.fail': 'update failed',
'common.title.config': 'Configuration',
'common.message.fail': 'failed!',
'common.message.success': 'succeed!',
'common.message.fail': 'Failed!',
'common.message.success': 'Succeed!',
'common.delete.tips': 'Are you sure you want to delete?',
'common.button.close': 'Close',
'common.button.done': 'Done',
+3 -1
View File
@@ -24,5 +24,7 @@ export default {
'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.',
'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':
'如果指定,我们的系统将尽最大努力进行确定性采样,以便使用相同 seed 和参数的重复请求应返回相同的结果。',
'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 span={5}>
<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>
</Col>
<Col span={4}>
+1 -2
View File
@@ -371,8 +371,7 @@ const Models: React.FC<ModelsProps> = ({
showSorterTooltip={false}
sorter={true}
render={(val, row) => {
console.log('val=====', val, row['created_at'], row.name);
return dayjs(val).format('YYYY-MM-DD HH:mm:ss');
return dayjs.utc(val).format('YYYY-MM-DD HH:mm:ss');
}}
/>
<SealColumn
@@ -15,7 +15,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const { open, url, onCancel } = props || {};
const [modalSize, setModalSize] = useState<any>({
width: 600,
height: 450
height: 420
});
const isFullScreenRef = React.useRef(false);
const intl = useIntl();
@@ -24,7 +24,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
setModalSize((size: any) => {
return {
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;
const { updateChunkedList } = useUpdateChunkedList({
const { updateChunkedList, cacheDataListRef } = useUpdateChunkedList({
dataList: dataSource,
setDataList: setDataSource
});
@@ -46,7 +47,9 @@ const Models: React.FC = () => {
cancelToken: axiosToken.token
});
console.log('res=======', res);
setDataSource(res.items);
if (!firstLoad) {
setDataSource(res.items);
}
setTotal(res.pagination.total);
} catch (error) {
setDataSource([]);
@@ -118,8 +121,10 @@ const Models: React.FC = () => {
if (!firstLoad) {
createModelsChunkRequest();
}
createModelsChunkRequest();
return () => {
chunkRequedtRef.current?.current?.cancel?.();
cacheDataListRef.current = [];
};
}, [firstLoad]);
@@ -1,7 +1,8 @@
import EditorWrap from '@/components/editor-wrap';
import { BulbOutlined } from '@ant-design/icons';
import Editor from '@monaco-editor/react';
import { useIntl } from '@umijs/max';
import { Modal, Spin } from 'antd';
import { Button, Modal, Spin } from 'antd';
import _ from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
@@ -30,6 +31,8 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const [codeValue, setCodeValue] = useState('');
const [lang, setLang] = useState('shell');
const BaseURL = `${window.location.origin}/v1-openai/chat/completions`;
const langOptions = [
{ label: 'Curl', value: 'shell' },
{ label: 'Python', value: 'python' },
@@ -66,7 +69,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const systemList = 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,
messages: [...systemList, ...messageList]
@@ -92,7 +95,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
const systemList = 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);
}
formatCode();
@@ -152,7 +155,7 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onChangeLang={handleOnChangeLang}
>
<Editor
height="min(450px, 90vh)"
height={380}
theme="vs-dark"
className="monaco-editor"
defaultLanguage="shell"
@@ -162,6 +165,29 @@ const ViewCodeModal: React.FC<ViewModalProps> = (props) => {
onMount={handleEditorDidMount}
/>
</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>
</Modal>
</>