chore: add cancel query model
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Col, Empty, Row, Space, Spin, Tag } from 'antd';
|
||||
import { Col, Empty, Row, Select, Space, Spin, Tag } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import SimpleBar from 'simplebar-react';
|
||||
import 'simplebar-react/dist/simplebar.min.css';
|
||||
import { queryHuggingfaceModelFiles } from '../apis';
|
||||
import FileType from '../config/file-type';
|
||||
import '../style/hf-model-file.less';
|
||||
@@ -12,16 +14,31 @@ import TitleWrapper from './title-wrapper';
|
||||
|
||||
interface HFModelFileProps {
|
||||
repo: string;
|
||||
collapsed?: boolean;
|
||||
loadingModel?: boolean;
|
||||
onSelectFile?: (file: any) => void;
|
||||
}
|
||||
|
||||
const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
const { collapsed, loadingModel } = props;
|
||||
const intl = useIntl();
|
||||
const [dataSource, setDataSource] = useState<any>({
|
||||
fileList: [],
|
||||
loading: false
|
||||
});
|
||||
|
||||
const [sortType, setSortType] = useState<string>('size');
|
||||
const [current, setCurrent] = useState<string>('');
|
||||
const modelFilesSortOptions = useRef<any[]>([
|
||||
{
|
||||
label: intl.formatMessage({ id: 'models.sort.size' }),
|
||||
value: 'size'
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage({ id: 'models.sort.name' }),
|
||||
value: 'name'
|
||||
}
|
||||
]);
|
||||
const axiosTokenRef = useRef<any>(null);
|
||||
|
||||
const handleSelectModelFile = (item: any) => {
|
||||
props.onSelectFile?.(item);
|
||||
@@ -34,14 +51,23 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
handleSelectModelFile({});
|
||||
return;
|
||||
}
|
||||
axiosTokenRef.current?.abort?.();
|
||||
axiosTokenRef.current = new AbortController();
|
||||
setDataSource({ ...dataSource, loading: true });
|
||||
setCurrent('');
|
||||
try {
|
||||
const res = await queryHuggingfaceModelFiles({ repo: props.repo });
|
||||
const res = await queryHuggingfaceModelFiles(
|
||||
{ repo: props.repo },
|
||||
{
|
||||
signal: axiosTokenRef.current.signal
|
||||
}
|
||||
);
|
||||
const list = _.filter(res, (file: any) => {
|
||||
return _.endsWith(file.path, '.gguf') || _.includes(file.path, '.gguf');
|
||||
});
|
||||
const sortList = _.sortBy(list, (item: any) => item.size);
|
||||
const sortList = _.sortBy(list, (item: any) => {
|
||||
return sortType === 'size' ? item.size : item.path;
|
||||
});
|
||||
setDataSource({ fileList: sortList, loading: false });
|
||||
handleSelectModelFile(list[0]);
|
||||
} catch (error) {
|
||||
@@ -50,6 +76,14 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSortChange = (value: string) => {
|
||||
const list = _.sortBy(dataSource.fileList, (item: any) => {
|
||||
return value === 'size' ? item.size : item.path;
|
||||
});
|
||||
setSortType(value);
|
||||
setDataSource({ ...dataSource, fileList: list });
|
||||
};
|
||||
|
||||
const getModelQuantizationType = (item: any) => {
|
||||
const name = _.split(item.path, '.').slice(0, -1).join('.');
|
||||
let quanType = _.toUpper(name.split('-').slice(-1)[0]);
|
||||
@@ -77,76 +111,93 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||
useEffect(() => {
|
||||
handleFetchModelFiles();
|
||||
}, [props.repo]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
axiosTokenRef.current?.abort?.();
|
||||
};
|
||||
}, []);
|
||||
return (
|
||||
<div>
|
||||
<TitleWrapper>
|
||||
<span>Available Files ({dataSource.fileList.length || 0})</span>
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'models.available.files' })} (
|
||||
{dataSource.fileList.length || 0})
|
||||
</span>
|
||||
<Select
|
||||
value={sortType}
|
||||
onChange={handleSortChange}
|
||||
labelRender={({ label }) => {
|
||||
return (
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'model.deploy.sort' })}: {label}
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
options={modelFilesSortOptions.current}
|
||||
size="middle"
|
||||
style={{ width: '120px' }}
|
||||
></Select>
|
||||
</TitleWrapper>
|
||||
<div style={{ padding: '16px 24px' }}>
|
||||
<Spin spinning={dataSource.loading} style={{ minHeight: 100 }}>
|
||||
{dataSource.fileList.length ? (
|
||||
<Row gutter={[16, 24]}>
|
||||
{_.map(dataSource.fileList, (item: any) => {
|
||||
return (
|
||||
<Col span={24} key={item.path}>
|
||||
<div
|
||||
className={classNames('hf-model-file', {
|
||||
active: item.path === current
|
||||
})}
|
||||
tabIndex={0}
|
||||
onClick={() => handleSelectModelFile(item)}
|
||||
onKeyDown={(e) => handleOnEnter(e, item)}
|
||||
>
|
||||
<div className="title">{item.path}</div>
|
||||
<Space className="tags">
|
||||
{/* <span className="tag-item">
|
||||
{convertFileSize(item.size)}
|
||||
</span> */}
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="green"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
<span style={{ opacity: 0.65 }}>
|
||||
{convertFileSize(item.size)}
|
||||
</span>
|
||||
</Tag>
|
||||
{getModelQuantizationType(item)}
|
||||
</Space>
|
||||
<div className="btn">
|
||||
{/* <Button size="middle">
|
||||
{item.path === current
|
||||
? intl.formatMessage({
|
||||
id: 'common.button.selected'
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'common.button.select'
|
||||
})}
|
||||
</Button> */}
|
||||
<SimpleBar
|
||||
style={{ maxHeight: collapsed ? 'max-content' : 'calc(100vh - 330px)' }}
|
||||
>
|
||||
<div style={{ padding: '16px 24px' }}>
|
||||
<Spin
|
||||
spinning={dataSource.loading || loadingModel}
|
||||
style={{ minHeight: 100 }}
|
||||
>
|
||||
{dataSource.fileList.length ? (
|
||||
<Row gutter={[16, 24]}>
|
||||
{_.map(dataSource.fileList, (item: any) => {
|
||||
return (
|
||||
<Col span={24} key={item.path}>
|
||||
<div
|
||||
className={classNames('hf-model-file', {
|
||||
active: item.path === current
|
||||
})}
|
||||
tabIndex={0}
|
||||
onClick={() => handleSelectModelFile(item)}
|
||||
onKeyDown={(e) => handleOnEnter(e, item)}
|
||||
>
|
||||
<div className="title">{item.path}</div>
|
||||
<Space className="tags">
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="green"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
<span style={{ opacity: 0.65 }}>
|
||||
{convertFileSize(item.size)}
|
||||
</span>
|
||||
</Tag>
|
||||
{getModelQuantizationType(item)}
|
||||
</Space>
|
||||
<div className="btn"></div>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
) : (
|
||||
!dataSource.loading && (
|
||||
<Empty
|
||||
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
||||
image={
|
||||
<SearchOutlined
|
||||
className="font-size-16"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
></SearchOutlined>
|
||||
}
|
||||
description="No files found"
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Spin>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
) : (
|
||||
!dataSource.loading && (
|
||||
<Empty
|
||||
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
||||
image={
|
||||
<SearchOutlined
|
||||
className="font-size-16"
|
||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||
></SearchOutlined>
|
||||
}
|
||||
description="No files found"
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Spin>
|
||||
</div>
|
||||
</SimpleBar>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user