diff --git a/config/config.ts b/config/config.ts index be103b95..8be0f5f8 100644 --- a/config/config.ts +++ b/config/config.ts @@ -19,7 +19,9 @@ export default defineConfig({ history: { type: 'hash' }, - + // https: { + // http2: true + // }, base: process.env.npm_config_base || '/', ...(isProduction ? { diff --git a/src/components/editor-wrap/index.less b/src/components/editor-wrap/index.less index 7ff7aea3..3840439f 100644 --- a/src/components/editor-wrap/index.less +++ b/src/components/editor-wrap/index.less @@ -1,5 +1,5 @@ .editor-wrap { - border-radius: 8px; + border-radius: var(--border-radius-mini); overflow: hidden; .editor-header { diff --git a/src/components/logs-viewer/index.less b/src/components/logs-viewer/index.less index f631b709..d54d3d72 100644 --- a/src/components/logs-viewer/index.less +++ b/src/components/logs-viewer/index.less @@ -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; diff --git a/src/components/seal-table/components/row-children.tsx b/src/components/seal-table/components/row-children.tsx index bc7d8e3a..e02899ea 100644 --- a/src/components/seal-table/components/row-children.tsx +++ b/src/components/seal-table/components/row-children.tsx @@ -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
{children}
; }; -export default React.memo(RowChildren); +export default RowChildren; diff --git a/src/components/seal-table/components/table-row.tsx b/src/components/seal-table/components/table-row.tsx index b3643a79..0363f33e 100644 --- a/src/components/seal-table/components/table-row.tsx +++ b/src/components/seal-table/components/table-row.tsx @@ -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]); diff --git a/src/components/version-info/index.tsx b/src/components/version-info/index.tsx index fb99387a..c8901cd8 100644 --- a/src/components/version-info/index.tsx +++ b/src/components/version-info/index.tsx @@ -38,6 +38,9 @@ export const modalConfig = { centered: false, maskClosable: true, footer: null, + style: { + top: '30%' + }, width: 400 }; diff --git a/src/global.less b/src/global.less index 8424000c..ec333a34 100644 --- a/src/global.less +++ b/src/global.less @@ -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); } } diff --git a/src/global.tsx b/src/global.tsx index c573fc4a..0bd6267d 100644 --- a/src/global.tsx +++ b/src/global.tsx @@ -1 +1,6 @@ // 应用前置、全局运行的逻辑时 会在这里执行 + +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; + +dayjs.extend(utc); diff --git a/src/hooks/use-update-chunk-list.ts b/src/hooks/use-update-chunk-list.ts index 7bcd4e1a..d7707ff3 100644 --- a/src/hooks/use-update-chunk-list.ts +++ b/src/hooks/use-update-chunk-list.ts @@ -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([]); 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 }; } diff --git a/src/locales/en-US/common.ts b/src/locales/en-US/common.ts index d162cfee..d8b8eaf7 100644 --- a/src/locales/en-US/common.ts +++ b/src/locales/en-US/common.ts @@ -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', diff --git a/src/locales/en-US/playground.ts b/src/locales/en-US/playground.ts index f2e6879a..1d00dfd3 100644 --- a/src/locales/en-US/playground.ts +++ b/src/locales/en-US/playground.ts @@ -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' }; diff --git a/src/locales/zh-CN/playground.ts b/src/locales/zh-CN/playground.ts index bab82ccb..f76852f5 100644 --- a/src/locales/zh-CN/playground.ts +++ b/src/locales/zh-CN/playground.ts @@ -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': '这里' }; diff --git a/src/pages/llmodels/components/instance-item.tsx b/src/pages/llmodels/components/instance-item.tsx index fe74fe30..41534fb9 100644 --- a/src/pages/llmodels/components/instance-item.tsx +++ b/src/pages/llmodels/components/instance-item.tsx @@ -121,7 +121,7 @@ const InstanceItem: React.FC = ({ - {dayjs(item.updated_at).format('YYYY-MM-DD HH:mm:ss')} + {dayjs.utc(item.created_at).format('YYYY-MM-DD HH:mm:ss')} diff --git a/src/pages/llmodels/components/table-list.tsx b/src/pages/llmodels/components/table-list.tsx index 66f22004..c0632809 100644 --- a/src/pages/llmodels/components/table-list.tsx +++ b/src/pages/llmodels/components/table-list.tsx @@ -371,8 +371,7 @@ const Models: React.FC = ({ 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'); }} /> = (props) => { const { open, url, onCancel } = props || {}; const [modalSize, setModalSize] = useState({ width: 600, - height: 450 + height: 420 }); const isFullScreenRef = React.useRef(false); const intl = useIntl(); @@ -24,7 +24,7 @@ const ViewCodeModal: React.FC = (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 }; }); }; diff --git a/src/pages/llmodels/index.tsx b/src/pages/llmodels/index.tsx index cf4dc3cd..3ba5359f 100644 --- a/src/pages/llmodels/index.tsx +++ b/src/pages/llmodels/index.tsx @@ -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]); diff --git a/src/pages/playground/components/view-code-modal.tsx b/src/pages/playground/components/view-code-modal.tsx index 959b5afb..ba2ed545 100644 --- a/src/pages/playground/components/view-code-modal.tsx +++ b/src/pages/playground/components/view-code-modal.tsx @@ -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 = (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 = (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 = (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 = (props) => { onChangeLang={handleOnChangeLang} > = (props) => { onMount={handleEditorDidMount} /> +
+ + + {intl.formatMessage( + { id: 'playground.viewcode.tips' }, + { + here: ( + + ) + } + )} + +