fix: query modelscope files by recursive

This commit is contained in:
jialin
2024-09-27 16:50:09 +08:00
parent 7e985991cd
commit 49c0467428
26 changed files with 292 additions and 118 deletions
+1
View File
@@ -38,6 +38,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"marked": "^14.1.0", "marked": "^14.1.0",
"numeral": "^2.0.6", "numeral": "^2.0.6",
"overlayscrollbars-react": "^0.5.6",
"query-string": "^9.0.0", "query-string": "^9.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
+20
View File
@@ -86,6 +86,12 @@ dependencies:
numeral: numeral:
specifier: ^2.0.6 specifier: ^2.0.6
version: 2.0.6 version: 2.0.6
overlayscrollbars:
specifier: ^2.10.0
version: 2.10.0
overlayscrollbars-react:
specifier: ^0.5.6
version: 0.5.6(overlayscrollbars@2.10.0)(react@18.2.0)
query-string: query-string:
specifier: ^9.0.0 specifier: ^9.0.0
version: 9.0.0 version: 9.0.0
@@ -12606,6 +12612,20 @@ packages:
mem: 5.1.1 mem: 5.1.1
dev: false dev: false
/overlayscrollbars-react@0.5.6(overlayscrollbars@2.10.0)(react@18.2.0):
resolution: {integrity: sha512-E5To04bL5brn9GVCZ36SnfGanxa2I2MDkWoa4Cjo5wol7l+diAgi4DBc983V7l2nOk/OLJ6Feg4kySspQEGDBw==, tarball: https://registry.npmjs.org/overlayscrollbars-react/-/overlayscrollbars-react-0.5.6.tgz}
peerDependencies:
overlayscrollbars: ^2.0.0
react: '>=16.8.0'
dependencies:
overlayscrollbars: 2.10.0
react: 18.2.0
dev: false
/overlayscrollbars@2.10.0:
resolution: {integrity: sha512-diNMeEafWTE0A4GJfwRpdBp2rE/BEvrhptBdBcDu8/UeytWcdCy9Td8tZWnztJeJ26f8/uHCWfPnPUC/dtgJdw==, tarball: https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-2.10.0.tgz}
dev: false
/p-defer@1.0.0: /p-defer@1.0.0:
resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==, tarball: https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz} resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==, tarball: https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -8,7 +8,7 @@
padding-block: 1.2em; padding-block: 1.2em;
&::-webkit-scrollbar { &::-webkit-scrollbar {
height: 8px; height: var(--scrollbar-size);
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
@@ -0,0 +1,15 @@
.list-item {
display: flex;
align-items: center;
justify-content: flex-start;
width: 100%;
margin-bottom: 12px;
.field-wrapper {
flex: 1;
}
.btn {
margin-left: 10px;
}
}
+2 -2
View File
@@ -32,8 +32,8 @@
overflow-y: auto !important; overflow-y: auto !important;
// custom scrollbar // custom scrollbar
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 8px; width: var(--scrollbar-size);
height: 6px; height: var(--scrollbar-size);
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
@@ -79,7 +79,7 @@ const TableRow: React.FC<
}, []); }, []);
const renderChildrenData = () => { const renderChildrenData = () => {
return renderChildren?.(childrenData); return renderChildren?.(childrenData, record);
}; };
const handlePolling = async () => { const handlePolling = async () => {
+1 -1
View File
@@ -52,7 +52,7 @@ export interface SealTableProps {
onCell?: (record: any, dataIndex: string) => void; onCell?: (record: any, dataIndex: string) => void;
onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void; onSort?: (dataIndex: string, order: 'ascend' | 'descend') => void;
onExpand?: (expanded: boolean, record: any, rowKey: any) => void; onExpand?: (expanded: boolean, record: any, rowKey: any) => void;
renderChildren?: (data: any) => React.ReactNode; renderChildren?: (data: any, parent?: any) => React.ReactNode;
loadChildren?: (record: any) => Promise<any[]>; loadChildren?: (record: any) => Promise<any[]>;
loadChildrenAPI?: (record: any) => string; loadChildrenAPI?: (record: any) => string;
contentRendered?: () => void; contentRendered?: () => void;
-1
View File
@@ -37,7 +37,6 @@
} }
.ant-input { .ant-input {
/* 只隐藏垂直滚动条轨道 */
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
width: 0 !important; width: 0 !important;
color: transparent; color: transparent;
+20 -2
View File
@@ -13,6 +13,9 @@ html {
--color-text-light-1: rgba(255, 255, 255, 90%); --color-text-light-1: rgba(255, 255, 255, 90%);
--color-fill-1: var(--ant-color-fill-tertiary); --color-fill-1: var(--ant-color-fill-tertiary);
--color-scrollbar-thumb: rgba(193, 193, 193, 80%); --color-scrollbar-thumb: rgba(193, 193, 193, 80%);
--scrollbar-size: 6px;
--scrollbar-handle-bg: rgba(0, 0, 0, 44%);
--scrollbar-handle-hover-bg: rgba(0, 0, 0, 55%);
--color-editor-dark: #282c34; --color-editor-dark: #282c34;
--color-editor-light: #fafafa; --color-editor-light: #fafafa;
--color-scrollbar-track: var(--ant-color-fill-tertiary); --color-scrollbar-track: var(--ant-color-fill-tertiary);
@@ -476,7 +479,7 @@ body {
.custome-scrollbar { .custome-scrollbar {
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 8px; width: var(--scrollbar-size);
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
@@ -498,7 +501,7 @@ body {
.custom-scrollbar-horizontal { .custom-scrollbar-horizontal {
&::-webkit-scrollbar { &::-webkit-scrollbar {
height: 8px; height: var(--scrollbar-size);
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
@@ -518,6 +521,21 @@ body {
} }
} }
.simplebar-scrollbar.simplebar-visible::before {
opacity: 1;
}
.simplebar-scrollbar::before {
background: var(--scrollbar-handle-bg);
width: var(--scrollbar-size);
}
.simplebar-scrollbar.simplebar-visible.simplebar-hover {
&::before {
background: var(--scrollbar-handle-hover-bg);
}
}
.ant-dropdown-menu .ant-dropdown-menu
.ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not( .ant-dropdown-menu-item.ant-dropdown-menu-item-danger:not(
.ant-dropdown-menu-item-disabled .ant-dropdown-menu-item-disabled
+72
View File
@@ -0,0 +1,72 @@
import { throttle } from 'lodash';
import {
useOverlayScrollbars,
UseOverlayScrollbarsParams
} from 'overlayscrollbars-react';
import React from 'react';
export const overlaySollerOptions: UseOverlayScrollbarsParams = {
options: {
update: {
debounce: 0
},
overflow: {
x: 'hidden'
},
scrollbars: {
autoHide: 'scroll',
autoHideDelay: 600,
clickScroll: 'instant'
}
},
defer: true
};
export default function useOverlayScroller() {
const scrollEventElement = React.useRef<any>(null);
const instanceRef = React.useRef<any>(null);
const [initialize, instance] = useOverlayScrollbars({
...overlaySollerOptions
});
instanceRef.current = instance?.();
scrollEventElement.current =
instanceRef.current?.elements()?.scrollEventElement;
const throttledScroll = React.useMemo(
() =>
throttle(() => {
scrollEventElement.current?.scrollTo?.({
top: scrollEventElement.current.scrollHeight,
behavior: 'smooth'
});
instanceRef.current?.update?.();
}, 300),
[scrollEventElement, instanceRef]
);
const throttledUpdateScrollerPosition = React.useCallback(() => {
throttledScroll();
}, [throttledScroll]);
// const createInstance = React.useCallback((el: any) => {
// if (el) {
// instanceRef.current?.destroy?.();
// initialize(el);
// instanceRef.current = instance?.();
// scrollEventElement.current =
// instanceRef.current?.elements()?.scrollEventElement;
// }
// }, []);
React.useEffect(() => {
return () => {
instanceRef.current?.destroy?.();
};
}, []);
return {
initialize,
instance: instanceRef.current,
updateScrollerPosition: throttledUpdateScrollerPosition
};
}
+1
View File
@@ -203,6 +203,7 @@ export async function queryModelScopeModelFiles(
const res = await fetch( const res = await fetch(
`${MODE_SCOPE_MODEL_FIELS_API}${params.name}/repo/files?${qs.stringify({ `${MODE_SCOPE_MODEL_FIELS_API}${params.name}/repo/files?${qs.stringify({
Revision: 'master', Revision: 'master',
Recursive: true,
Root: '' Root: ''
})}`, })}`,
{ {
@@ -192,6 +192,32 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
</Form.Item> </Form.Item>
</> </>
)} )}
{scheduleType === 'manual' && (
<Form.Item<FormData>
name="gpu_selector"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.select'
},
{
name: 'gpu_selector'
}
)
}
]}
>
<SealSelect label="GPU Selector" required>
{gpuOptions.map((item) => (
<Select.Option key={item.value} value={item.value}>
<GPUCard data={item}></GPUCard>
</Select.Option>
))}
</SealSelect>
</Form.Item>
)}
<Form.Item name="backend"> <Form.Item name="backend">
<SealSelect <SealSelect
label={intl.formatMessage({ id: 'models.form.backend' })} label={intl.formatMessage({ id: 'models.form.backend' })}
@@ -219,32 +245,6 @@ const AdvanceConfig: React.FC<AdvanceConfigProps> = (props) => {
options={paramsConfig} options={paramsConfig}
></ListInput> ></ListInput>
</Form.Item> </Form.Item>
{scheduleType === 'manual' && (
<Form.Item<FormData>
name="gpu_selector"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.select'
},
{
name: 'gpu_selector'
}
)
}
]}
>
<SealSelect label="GPU Selector" required>
{gpuOptions.map((item) => (
<Select.Option key={item.value} value={item.value}>
<GPUCard data={item}></GPUCard>
</Select.Option>
))}
</SealSelect>
</Form.Item>
)}
{isGGUF && ( {isGGUF && (
<div style={{ paddingBottom: 22, paddingLeft: 10 }}> <div style={{ paddingBottom: 22, paddingLeft: 10 }}>
<Form.Item<FormData> <Form.Item<FormData>
@@ -35,6 +35,7 @@ const pattern = /^(.*)-(\d+)-of-(\d+)\.(.*)$/;
const filterReg = /\.(safetensors|gguf)$/i; const filterReg = /\.(safetensors|gguf)$/i;
const includeReg = /\.(safetensors|gguf)$/i; const includeReg = /\.(safetensors|gguf)$/i;
const filterRegGGUF = /\.(gguf)$/i;
const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => { const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
const { collapsed, modelSource } = props; const { collapsed, modelSource } = props;
@@ -159,8 +160,11 @@ const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
} }
); );
const fileList = _.filter(_.get(data, ['Data', 'Files']), (file: any) => { const fileList = _.filter(_.get(data, ['Data', 'Files']), (file: any) => {
return filterReg.test(file.Path) || _.includes(includeReg, file.Path); return (
filterRegGGUF.test(file.Path) || _.includes(filterRegGGUF, file.Path)
);
}); });
const list = _.map(fileList, (item: any) => { const list = _.map(fileList, (item: any) => {
return { return {
path: item.Path, path: item.Path,
@@ -23,6 +23,7 @@ interface InstanceItemProps {
list: ModelInstanceListItem[]; list: ModelInstanceListItem[];
gpuDeviceList: GPUDeviceItem[]; gpuDeviceList: GPUDeviceItem[];
workerList: WorkerListItem[]; workerList: WorkerListItem[];
modelData?: any;
handleChildSelect: ( handleChildSelect: (
val: string, val: string,
item: ModelInstanceListItem, item: ModelInstanceListItem,
@@ -33,6 +34,7 @@ interface InstanceItemProps {
const InstanceItem: React.FC<InstanceItemProps> = ({ const InstanceItem: React.FC<InstanceItemProps> = ({
list, list,
workerList, workerList,
modelData,
handleChildSelect handleChildSelect
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@@ -98,6 +100,10 @@ const InstanceItem: React.FC<InstanceItemProps> = ({
{intl.formatMessage({ id: 'models.table.gpuindex' })}: [ {intl.formatMessage({ id: 'models.table.gpuindex' })}: [
{_.join(item.gpu_indexes?.sort?.(), ',')}] {_.join(item.gpu_indexes?.sort?.(), ',')}]
</div> </div>
<div>
{intl.formatMessage({ id: 'models.form.backend' })}:{' '}
{modelData?.backend || ''}
</div>
</div> </div>
); );
}; };
@@ -8,6 +8,7 @@ import {
} from '@ant-design/icons'; } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Empty, Spin, Tag, Tooltip } from 'antd'; import { Button, Empty, Spin, Tag, Tooltip } from 'antd';
import 'overlayscrollbars/overlayscrollbars.css';
import React, { useCallback, useEffect, useRef, useState } from 'react'; import React, { useCallback, useEffect, useRef, useState } from 'react';
import SimpleBar from 'simplebar-react'; import SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css'; import 'simplebar-react/dist/simplebar.min.css';
+5 -4
View File
@@ -402,10 +402,11 @@ const Models: React.FC<ModelsProps> = ({
); );
const renderChildren = useCallback( const renderChildren = useCallback(
(list: any) => { (list: any, parent?: any) => {
return ( return (
<InstanceItem <InstanceItem
list={list} list={list}
modelData={parent}
gpuDeviceList={gpuDeviceList} gpuDeviceList={gpuDeviceList}
workerList={workerList} workerList={workerList}
handleChildSelect={handleChildSelect} handleChildSelect={handleChildSelect}
@@ -417,12 +418,12 @@ const Models: React.FC<ModelsProps> = ({
const generateSource = useCallback((record: ListItem) => { const generateSource = useCallback((record: ListItem) => {
if (record.source === modelSourceMap.modelscope_value) { if (record.source === modelSourceMap.modelscope_value) {
return `${modelSourceMap.modelScope} / ${record.model_scope_file_path || record.model_scope_model_id}`; return `${modelSourceMap.modelScope}/${record.model_scope_file_path || record.model_scope_model_id}`;
} }
if (record.source === modelSourceMap.huggingface_value) { if (record.source === modelSourceMap.huggingface_value) {
return `${modelSourceMap.huggingface} / ${record.huggingface_filename || record.huggingface_repo_id}`; return `${modelSourceMap.huggingface}/${record.huggingface_filename || record.huggingface_repo_id}`;
} }
return `${modelSourceMap.ollama_library} / ${record.ollama_library_model_name}`; return `${modelSourceMap.ollama_library}/${record.ollama_library_model_name}`;
}, []); }, []);
const handleCloseViewCode = useCallback(() => { const handleCloseViewCode = useCallback(() => {
+22 -15
View File
@@ -2,6 +2,20 @@ import { StatusMaps } from '@/config';
import { EditOutlined } from '@ant-design/icons'; import { EditOutlined } from '@ant-design/icons';
export const ollamaModelOptions = [ export const ollamaModelOptions = [
{
label: 'llama3.2',
value: 'llama3.2',
name: 'llama3.2',
id: 'llama3.2',
tags: ['Tools', '1B', '3B']
},
{
label: 'qwen2.5',
value: 'qwen2.5',
name: 'qwen2.5',
tags: ['Tools', '0.5B', '1.5B', '3B', '7B', '14B', '32B', '72B'],
id: 'gemma2'
},
{ {
label: 'llama3.1', label: 'llama3.1',
value: 'llama3.1', value: 'llama3.1',
@@ -9,20 +23,20 @@ export const ollamaModelOptions = [
id: 'llama3.1', id: 'llama3.1',
tags: ['8B', '70B', '405B'] tags: ['8B', '70B', '405B']
}, },
{
label: 'llama3',
value: 'llama3',
name: 'llama3',
tags: ['8B', '70B'],
id: 'llama3'
},
{ {
label: 'gemma2', label: 'gemma2',
value: 'gemma2', value: 'gemma2',
name: 'gemma2', name: 'gemma2',
tags: ['9B', '27B'], tags: ['2B', '9B', '27B'],
id: 'gemma2' id: 'gemma2'
}, },
{
label: 'llava',
value: 'llava',
name: 'llava',
tags: ['7B', '13B', '34B'],
id: 'llava'
},
{ {
label: 'mistral-nemo', label: 'mistral-nemo',
value: 'mistral-nemo', value: 'mistral-nemo',
@@ -44,13 +58,6 @@ export const ollamaModelOptions = [
tags: ['7B'], tags: ['7B'],
id: 'mistral' id: 'mistral'
}, },
{
label: 'llava',
value: 'llava',
name: 'llava',
tags: ['7B', '13B', '34B'],
id: 'llava'
},
{ {
label: 'qwen2', label: 'qwen2',
value: 'qwen2', value: 'qwen2',
+18 -2
View File
@@ -1,11 +1,12 @@
export default [ const options = [
{ {
label: '--chat-template', label: '--chat-template',
value: '--chat-template' value: '--chat-template'
}, },
{ {
label: '--ctx-size', label: '--ctx-size',
value: '--ctx-size' value: '--ctx-size',
options: ['8192']
}, },
{ {
label: '--flash-attn', label: '--flash-attn',
@@ -24,3 +25,18 @@ export default [
value: '--ubatch-size' value: '--ubatch-size'
} }
]; ];
const resultList = options.map((option) => {
return {
label: option.label,
value: option.value,
opts: option.options?.map((opt) => {
return {
label: opt,
value: opt
};
})
};
});
export default resultList;
+1 -1
View File
@@ -183,7 +183,7 @@ const options = [
{ {
label: '--max-model-len', label: '--max-model-len',
value: '--max-model-len', value: '--max-model-len',
options: [] options: ['8192']
}, },
{ {
label: '--guided-decoding-backend', label: '--guided-decoding-backend',
+1 -1
View File
@@ -5,7 +5,7 @@
} }
.simplebar-scrollbar::before { .simplebar-scrollbar::before {
background: rgba(0, 0, 0, 50%); width: var(--scrollbar-size);
} }
.column-wrapper-footer { .column-wrapper-footer {
@@ -8,10 +8,6 @@
// height: calc(100vh - 194px); // height: calc(100vh - 194px);
} }
.simplebar-scrollbar::before {
background: rgba(0, 0, 0, 50%);
}
.search-bar { .search-bar {
left: 0; left: 0;
right: 0; right: 0;
+24 -25
View File
@@ -1,9 +1,10 @@
import useContainerScroll from '@/hooks/use-container-scorll'; import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data'; import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
import { useIntl, useSearchParams } from '@umijs/max'; import { useIntl, useSearchParams } from '@umijs/max';
import { Spin } from 'antd'; import { Spin } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import _ from 'lodash'; import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import { import {
forwardRef, forwardRef,
memo, memo,
@@ -12,7 +13,6 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import 'simplebar-react/dist/simplebar.min.css';
import { CHAT_API } from '../apis'; import { CHAT_API } from '../apis';
import { Roles } from '../config'; import { Roles } from '../config';
import { MessageItem } from '../config/types'; import { MessageItem } from '../config/types';
@@ -48,21 +48,10 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
const controllerRef = useRef<any>(null); const controllerRef = useRef<any>(null);
const scroller = useRef<any>(null); const scroller = useRef<any>(null);
const currentMessageRef = useRef<any>(null); const currentMessageRef = useRef<any>(null);
const paramsScroller = useRef<any>(null); const paramsRef = useRef<any>(null);
const leftSimple = useRef<any>(null);
const { updateScrollerPosition, handleContentWheel } = useContainerScroll(
scroller,
{ toBottom: true }
);
useEffect(() => { const { initialize, updateScrollerPosition } = useOverlayScroller();
updateScrollerPosition(); const { initialize: innitializeParams } = useOverlayScroller();
}, [messageList]);
useEffect(() => {
paramsScroller.current?.recalculate();
leftSimple.current?.recalculate();
}, [collapse]);
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
@@ -200,9 +189,7 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
console.log('error=====', error); console.log('error=====', error);
setMessageList((pre) => {
return [...pre, ...currentMessageRef.current];
});
setLoading(false); setLoading(false);
} }
}; };
@@ -243,14 +230,26 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
setMessageList(userMsg); setMessageList(userMsg);
}; };
useEffect(() => {
if (scroller.current) {
initialize(scroller.current);
}
}, [scroller.current, initialize]);
useEffect(() => {
if (paramsRef.current) {
innitializeParams(paramsRef.current);
}
}, [paramsRef.current, innitializeParams]);
useEffect(() => {
updateScrollerPosition();
}, [messageList]);
return ( return (
<div className="ground-left-wrapper"> <div className="ground-left-wrapper">
<div className="ground-left"> <div className="ground-left">
<div <div className="message-list-wrap" ref={scroller}>
className="message-list-wrap custome-scrollbar"
onWheel={handleContentWheel}
ref={scroller}
>
<div <div
style={{ style={{
marginBottom: 20 marginBottom: 20
@@ -305,11 +304,11 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
/> />
</div> </div>
</div> </div>
<div <div
className={classNames('params-wrapper', { className={classNames('params-wrapper', {
collapsed: collapse collapsed: collapse
})} })}
ref={paramsRef}
> >
<div className="box"> <div className="box">
<ParamsSettings <ParamsSettings
@@ -1,4 +1,6 @@
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import _ from 'lodash'; import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import CompareContext from '../../config/compare-context'; import CompareContext from '../../config/compare-context';
import { MessageItem, ModelSelectionItem } from '../../config/types'; import { MessageItem, ModelSelectionItem } from '../../config/types';
@@ -14,6 +16,7 @@ interface MultiCompareProps {
} }
const MultiCompare: React.FC<MultiCompareProps> = ({ modelList }) => { const MultiCompare: React.FC<MultiCompareProps> = ({ modelList }) => {
const { initialize } = useOverlayScroller();
const [loadingStatus, setLoadingStatus] = useState<Record<symbol, boolean>>( const [loadingStatus, setLoadingStatus] = useState<Record<symbol, boolean>>(
{} {}
); );
@@ -36,6 +39,7 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList }) => {
}); });
const modelsCounterMap = useRef<Record<string, number>>({}); const modelsCounterMap = useRef<Record<string, number>>({});
const modelRefs = useRef<any>({}); const modelRefs = useRef<any>({});
const chatListScrollRef = useRef<any>(null);
const boxHeight = 'calc(100vh - 72px)'; const boxHeight = 'calc(100vh - 72px)';
const isLoading = useMemo(() => { const isLoading = useMemo(() => {
@@ -249,29 +253,33 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList }) => {
setModelSelections(resultList); setModelSelections(resultList);
}, [modelList]); }, [modelList]);
useEffect(() => {
if (chatListScrollRef.current) {
initialize(chatListScrollRef.current);
}
}, [chatListScrollRef.current, initialize]);
return ( return (
<div className="multiple-chat" style={{ height: boxHeight }}> <div className="multiple-chat" style={{ height: boxHeight }}>
<div className="chat-list"> <div className="chat-list" ref={chatListScrollRef}>
<div className="chat-list-inner"> <CompareContext.Provider
<CompareContext.Provider value={{
value={{ spans,
spans, globalParams,
globalParams, loadingStatus,
loadingStatus, modelFullList: modelList,
modelFullList: modelList, handleApplySystemChangeToAll,
handleApplySystemChangeToAll, setGlobalParams,
setGlobalParams, setLoadingStatus: handleSetLoadingStatus,
setLoadingStatus: handleSetLoadingStatus, handleDeleteModel: handleDeleteModel
handleDeleteModel: handleDeleteModel }}
}} >
> <ActiveModels
<ActiveModels spans={spans}
spans={spans} modelSelections={modelSelections}
modelSelections={modelSelections} setModelRefs={setModelRefs}
setModelRefs={setModelRefs} ></ActiveModels>
></ActiveModels> </CompareContext.Provider>
</CompareContext.Provider>
</div>
</div> </div>
<div> <div>
<MessageInput <MessageInput
@@ -31,6 +31,7 @@ const MessageContent: React.FC<MessageContentProps> = ({
newMessageList.splice(index, 1); newMessageList.splice(index, 1);
setMessageList?.(newMessageList); setMessageList?.(newMessageList);
}; };
return ( return (
<> <>
{!!messageList.length && ( {!!messageList.length && (
@@ -1,4 +1,5 @@
import IconFont from '@/components/icon-font'; import IconFont from '@/components/icon-font';
import useOverlayScroller from '@/hooks/use-overlay-scroller';
import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data'; import { fetchChunkedData, readStreamData } from '@/utils/fetch-chunk-data';
import { import {
ClearOutlined, ClearOutlined,
@@ -9,6 +10,7 @@ import {
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Button, Checkbox, Dropdown, Popover, Select, Spin } from 'antd'; import { Button, Checkbox, Dropdown, Popover, Select, Spin } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import 'overlayscrollbars/overlayscrollbars.css';
import React, { import React, {
forwardRef, forwardRef,
useContext, useContext,
@@ -18,7 +20,6 @@ import React, {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import SimpleBar from 'simplebar-react';
import 'simplebar-react/dist/simplebar.min.css'; import 'simplebar-react/dist/simplebar.min.css';
import { CHAT_API } from '../../apis'; import { CHAT_API } from '../../apis';
import { Roles } from '../../config'; import { Roles } from '../../config';
@@ -62,6 +63,9 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
const contentRef = useRef<any>(''); const contentRef = useRef<any>('');
const controllerRef = useRef<any>(null); const controllerRef = useRef<any>(null);
const currentMessageRef = useRef<MessageItem[]>([]); const currentMessageRef = useRef<MessageItem[]>([]);
const modelScrollRef = useRef<any>(null);
const { initialize } = useOverlayScroller();
const setMessageId = () => { const setMessageId = () => {
messageId.current = messageId.current + 1; messageId.current = messageId.current + 1;
@@ -122,8 +126,6 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
setMessageList((preList) => { setMessageList((preList) => {
return [...preList, ...currentMessageRef.current]; return [...preList, ...currentMessageRef.current];
}); });
console.log('currentMessageRef.current 1:', currentMessageRef.current);
console.log('currentMessage==========4', messageList);
const messages = _.map( const messages = _.map(
[...messageList, ...currentMessageRef.current], [...messageList, ...currentMessageRef.current],
(item: MessageItem) => { (item: MessageItem) => {
@@ -194,9 +196,6 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
}); });
setLoadingStatus(instanceId, false); setLoadingStatus(instanceId, false);
} catch (error) { } catch (error) {
setMessageList((preList) => {
return [...preList, ...currentMessageRef.current];
});
setLoadingStatus(instanceId, false); setLoadingStatus(instanceId, false);
} }
}; };
@@ -333,6 +332,12 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
}; };
}, []); }, []);
useEffect(() => {
if (modelScrollRef.current) {
initialize(modelScrollRef.current);
}
}, [modelScrollRef.current, initialize]);
useImperativeHandle(ref, () => { useImperativeHandle(ref, () => {
return { return {
submit: handleSubmit, submit: handleSubmit,
@@ -410,8 +415,12 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
applyToAll={handleApplySystemChangeToAll} applyToAll={handleApplySystemChangeToAll}
setSystemMessage={setSystemMessage} setSystemMessage={setSystemMessage}
></SystemMessage> ></SystemMessage>
<SimpleBar style={{ maxHeight: maxHeight }}> <div
<div className="content"> className="content"
ref={modelScrollRef}
style={{ maxHeight: maxHeight }}
>
<div>
<MessageContent <MessageContent
spans={spans} spans={spans}
messageList={messageList} messageList={messageList}
@@ -424,7 +433,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
style={{ width: '100%' }} style={{ width: '100%' }}
/> />
</div> </div>
</SimpleBar> </div>
<ViewCodeModal <ViewCodeModal
open={show} open={show}
systemMessage={systemMessage} systemMessage={systemMessage}
@@ -44,7 +44,7 @@
} }
textarea::-webkit-scrollbar { textarea::-webkit-scrollbar {
width: 8px; width: var(--scrollbar-size);
} }
textarea::-webkit-scrollbar-track { textarea::-webkit-scrollbar-track {