chore: deploy model state merge

This commit is contained in:
jialin
2024-08-09 10:26:46 +08:00
parent dea99ff70a
commit 0a47c4c067
11 changed files with 172 additions and 112 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ const APIKeys: React.FC = () => {
const fetchData = async () => { const fetchData = async () => {
setDataSource((pre) => { setDataSource((pre) => {
pre.loading = true; pre.loading = true;
return pre; return { ...pre };
}); });
try { try {
const params = { const params = {
+23 -4
View File
@@ -4,8 +4,9 @@ import SealSelect from '@/components/seal-form/seal-select';
import { PageAction } from '@/config'; import { PageAction } from '@/config';
import { PageActionType } from '@/config/types'; import { PageActionType } from '@/config/types';
import { convertFileSize } from '@/utils'; import { convertFileSize } from '@/utils';
import { CloseOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max'; import { useIntl } from '@umijs/max';
import { Drawer, Form } from 'antd'; import { Button, Drawer, Form } from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { memo, useCallback, useEffect, useState } from 'react'; import { memo, useCallback, useEffect, useState } from 'react';
import { queryHuggingfaceModelFiles, queryHuggingfaceModels } from '../apis'; import { queryHuggingfaceModelFiles, queryHuggingfaceModels } from '../apis';
@@ -276,17 +277,35 @@ const AddModal: React.FC<AddModalProps> = (props) => {
return ( return (
<Drawer <Drawer
title={title} title={
<div className="flex-between flex-center">
<span
style={{
color: 'var(--ant-color-text)',
fontWeight: 'var(--font-weight-medium)',
fontSize: 'var(--font-size-middle)'
}}
>
{title}
</span>
<Button type="text" size="small" onClick={onCancel}>
<CloseOutlined></CloseOutlined>
</Button>
</div>
}
open={open} open={open}
onClose={onCancel} onClose={onCancel}
destroyOnClose={true} destroyOnClose={true}
closeIcon={true} closeIcon={false}
maskClosable={false} maskClosable={false}
keyboard={false} keyboard={false}
styles={{ styles={{
body: { body: {
height: 'calc(100vh - 53px)', height: 'calc(100vh - 57px)',
padding: '16px 0' padding: '16px 0'
},
content: {
borderRadius: '8px 0 0 8px'
} }
}} }}
width="90%" width="90%"
+88 -56
View File
@@ -35,75 +35,97 @@ const sourceList = [
]; ];
const SearchModel: React.FC<SearchInputProps> = (props) => { const SearchModel: React.FC<SearchInputProps> = (props) => {
console.log('SearchModel======');
const intl = useIntl(); const intl = useIntl();
const { modelSource, onSourceChange, onSelectModel } = props; const { modelSource, onSourceChange, onSelectModel } = props;
const [repoOptions, setRepoOptions] = useState<any[]>([]); const [dataSource, setDataSource] = useState<{
const [loading, setLoading] = useState(false); repoOptions: any[];
loading: boolean;
}>({
repoOptions: [],
loading: false
});
const [current, setCurrent] = useState<string>(''); const [current, setCurrent] = useState<string>('');
const [sortType, setSortType] = useState<string>('downloads'); const [sortType, setSortType] = useState<string>('downloads');
const cacheRepoOptions = useRef<any[]>([]); const cacheRepoOptions = useRef<any[]>([]);
const axiosTokenRef = useRef<any>(null); const axiosTokenRef = useRef<any>(null);
const customOllamaModelRef = useRef<any>(null); const customOllamaModelRef = useRef<any>(null);
const handleOnSelectModel = (item: any) => { const handleOnSelectModel = useCallback((item: any) => {
onSelectModel(item); onSelectModel(item);
setCurrent(item.id); setCurrent(item.id);
};
const handleOnSearchRepo = async (text: string) => {
axiosTokenRef.current?.abort?.();
axiosTokenRef.current = new AbortController();
if (loading) return;
try {
setLoading(true);
cacheRepoOptions.current = [];
const params = {
search: {
query: text,
tags: ['gguf']
}
};
const models = await queryHuggingfaceModels(params, {
signal: axiosTokenRef.current.signal
});
const list = _.map(models || [], (item: any) => {
return {
...item,
value: item.name,
label: item.name
};
});
const sortedList = _.sortBy(
list,
(item: any) => item[sortType]
).reverse();
cacheRepoOptions.current = sortedList;
setRepoOptions(sortedList);
handleOnSelectModel(sortedList[0]);
} catch (error) {
setRepoOptions([]);
handleOnSelectModel({});
cacheRepoOptions.current = [];
} finally {
setLoading(false);
}
};
const handlerSearchModels = useCallback(async (e: any) => {
const text = e.target.value;
handleOnSearchRepo(text);
}, []); }, []);
const handleOnSearchRepo = useCallback(
async (text: string) => {
axiosTokenRef.current?.abort?.();
axiosTokenRef.current = new AbortController();
if (dataSource.loading) return;
try {
setDataSource((pre) => {
pre.loading = true;
return { ...pre };
});
cacheRepoOptions.current = [];
const params = {
search: {
query: text,
tags: ['gguf']
}
};
const models = await queryHuggingfaceModels(params, {
signal: axiosTokenRef.current.signal
});
const list = _.map(models || [], (item: any) => {
return {
...item,
value: item.name,
label: item.name
};
});
const sortedList = _.sortBy(
list,
(item: any) => item[sortType]
).reverse();
cacheRepoOptions.current = sortedList;
setDataSource({
repoOptions: sortedList,
loading: false
});
handleOnSelectModel(sortedList[0]);
} catch (error) {
setDataSource({
repoOptions: [],
loading: false
});
handleOnSelectModel({});
cacheRepoOptions.current = [];
}
},
[dataSource]
);
const handlerSearchModels = useCallback(
async (e: any) => {
const text = e.target.value;
handleOnSearchRepo(text);
},
[handleOnSearchRepo]
);
const handleOnOpen = () => { const handleOnOpen = () => {
if ( if (
!repoOptions.length && !dataSource.repoOptions.length &&
!cacheRepoOptions.current.length && !cacheRepoOptions.current.length &&
modelSource === modelSourceMap.huggingface_value modelSource === modelSourceMap.huggingface_value
) { ) {
handleOnSearchRepo(''); handleOnSearchRepo('');
} }
if (modelSourceMap.ollama_library_value === modelSource) { if (modelSourceMap.ollama_library_value === modelSource) {
setRepoOptions(ollamaModelOptions); setDataSource({
repoOptions: ollamaModelOptions,
loading: false
});
cacheRepoOptions.current = ollamaModelOptions; cacheRepoOptions.current = ollamaModelOptions;
handleOnSelectModel(ollamaModelOptions[0]); handleOnSelectModel(ollamaModelOptions[0]);
} }
@@ -114,7 +136,10 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
const list = _.filter(cacheRepoOptions.current, (item: any) => { const list = _.filter(cacheRepoOptions.current, (item: any) => {
return item.name.includes(text); return item.name.includes(text);
}); });
setRepoOptions(list); setDataSource({
repoOptions: list,
loading: false
});
}; };
const debounceFilter = _.debounce((e: any) => { const debounceFilter = _.debounce((e: any) => {
@@ -124,7 +149,10 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
const handleSourceChange = (source: string) => { const handleSourceChange = (source: string) => {
axiosTokenRef.current?.abort?.(); axiosTokenRef.current?.abort?.();
onSourceChange?.(source); onSourceChange?.(source);
setRepoOptions([]); setDataSource({
repoOptions: [],
loading: false
});
cacheRepoOptions.current = []; cacheRepoOptions.current = [];
}; };
@@ -146,11 +174,14 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
const handleSortChange = (value: string) => { const handleSortChange = (value: string) => {
const sortedList = _.sortBy( const sortedList = _.sortBy(
repoOptions, dataSource.repoOptions,
(item: any) => item[value] (item: any) => item[value]
).reverse(); ).reverse();
setSortType(value); setSortType(value);
setRepoOptions(sortedList); setDataSource({
repoOptions: sortedList,
loading: false
});
}; };
const renderHFSearch = () => { const renderHFSearch = () => {
@@ -159,7 +190,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
<SearchInput onSearch={handlerSearchModels}></SearchInput> <SearchInput onSearch={handlerSearchModels}></SearchInput>
<div className={SearchStyle.filter}> <div className={SearchStyle.filter}>
<span> <span>
<span className="value">{repoOptions.length}</span>results <span className="value">{dataSource.repoOptions.length}</span>
results
</span> </span>
<Select <Select
value={sortType} value={sortType}
@@ -220,8 +252,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
</div> </div>
{ {
<SearchResult <SearchResult
loading={loading} loading={dataSource.loading}
resultList={repoOptions} resultList={dataSource.repoOptions}
current={current} current={current}
source={modelSource} source={modelSource}
onSelect={handleOnSelectModel} onSelect={handleOnSelectModel}
+38 -35
View File
@@ -14,6 +14,7 @@ interface SearchResultProps {
} }
const SearchResult: React.FC<SearchResultProps> = (props) => { const SearchResult: React.FC<SearchResultProps> = (props) => {
console.log('SearchResult======');
const { resultList, onSelect, source } = props; const { resultList, onSelect, source } = props;
const handleSelect = (e: any, item: any) => { const handleSelect = (e: any, item: any) => {
@@ -22,41 +23,43 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
}; };
return ( return (
<div style={{ ...props.style }} className="search-result-wrap"> <div style={{ ...props.style }} className="search-result-wrap">
<Spin spinning={props.loading} style={{ minHeight: 100 }}> <Spin spinning={props.loading}>
{resultList.length ? ( <div style={{ minHeight: 200 }}>
<Row gutter={[16, 16]}> {resultList.length ? (
{resultList.map((item, index) => ( <Row gutter={[16, 16]}>
<Col span={24} key={item.name}> {resultList.map((item, index) => (
<div onClick={(e) => handleSelect(e, item)}> <Col span={24} key={item.name}>
<HFModelItem <div onClick={(e) => handleSelect(e, item)}>
source={source} <HFModelItem
tags={item.tags} source={source}
key={index} tags={item.tags}
title={item.name} key={index}
downloads={item.downloads} title={item.name}
likes={item.likes} downloads={item.downloads}
task={item.task} likes={item.likes}
updatedAt={item.updatedAt} task={item.task}
active={item.id === props.current} updatedAt={item.updatedAt}
/> active={item.id === props.current}
</div> />
</Col> </div>
))} </Col>
</Row> ))}
) : ( </Row>
!props.loading && ( ) : (
<Empty !props.loading && (
imageStyle={{ height: 'auto', marginTop: '20px' }} <Empty
image={ imageStyle={{ height: 'auto', marginTop: '20px' }}
<SearchOutlined image={
className="font-size-16" <SearchOutlined
style={{ color: 'var(--ant-color-text-tertiary)' }} className="font-size-16"
></SearchOutlined> style={{ color: 'var(--ant-color-text-tertiary)' }}
} ></SearchOutlined>
description="No models found" }
/> description="No models found"
) />
)} )
)}
</div>
</Spin> </Spin>
</div> </div>
); );
+3 -3
View File
@@ -34,9 +34,9 @@ import {
} from '../apis'; } from '../apis';
import { modelSourceMap } from '../config'; import { modelSourceMap } from '../config';
import { FormData, ListItem, ModelInstanceListItem } from '../config/types'; import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
import AddModal from './add-modal';
import DeployModal from './deploy-modal'; import DeployModal from './deploy-modal';
import InstanceItem from './instance-item'; import InstanceItem from './instance-item';
import UpdateModel from './update-modal';
import ViewLogsModal from './view-logs-modal'; import ViewLogsModal from './view-logs-modal';
interface ModelsProps { interface ModelsProps {
@@ -467,14 +467,14 @@ const Models: React.FC<ModelsProps> = ({
/> />
</SealTable> </SealTable>
</PageContainer> </PageContainer>
<AddModal <UpdateModel
open={openAddModal} open={openAddModal}
action={PageAction.EDIT} action={PageAction.EDIT}
title={title} title={title}
data={currentData} data={currentData}
onCancel={handleModalCancel} onCancel={handleModalCancel}
onOk={handleModalOk} onOk={handleModalOk}
></AddModal> ></UpdateModel>
<DeployModal <DeployModal
open={openDeployModal} open={openDeployModal}
action={PageAction.CREATE} action={PageAction.CREATE}
+15 -9
View File
@@ -4,7 +4,7 @@ import useSetChunkRequest, {
} from '@/hooks/use-chunk-request'; } from '@/hooks/use-chunk-request';
import useUpdateChunkedList from '@/hooks/use-update-chunk-list'; import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
import _ from 'lodash'; import _ from 'lodash';
import { useCallback, useEffect, useRef, useState } from 'react'; import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { MODELS_API, MODEL_INSTANCE_API, queryModelsList } from './apis'; import { MODELS_API, MODEL_INSTANCE_API, queryModelsList } from './apis';
import TableList from './components/table-list'; import TableList from './components/table-list';
import { ListItem } from './config/types'; import { ListItem } from './config/types';
@@ -15,8 +15,6 @@ const Models: React.FC = () => {
const { setChunkRequest } = useSetChunkRequest(); const { setChunkRequest } = useSetChunkRequest();
const { setChunkRequest: setModelInstanceChunkRequest } = const { setChunkRequest: setModelInstanceChunkRequest } =
useSetChunkRequest(); useSetChunkRequest();
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [modelInstances, setModelInstances] = useState<any[]>([]); const [modelInstances, setModelInstances] = useState<any[]>([]);
const [dataSource, setDataSource] = useState<{ const [dataSource, setDataSource] = useState<{
dataList: ListItem[]; dataList: ListItem[];
@@ -53,7 +51,7 @@ const Models: React.FC = () => {
axiosToken = createAxiosToken(); axiosToken = createAxiosToken();
setDataSource((pre) => { setDataSource((pre) => {
pre.loading = true; pre.loading = true;
return pre; return { ...pre };
}); });
try { try {
const params = { const params = {
@@ -68,6 +66,11 @@ const Models: React.FC = () => {
loading: false, loading: false,
total: res.pagination.total total: res.pagination.total
}); });
} else {
setDataSource({
...dataSource,
total: res.pagination.total
});
} }
} catch (error) { } catch (error) {
setDataSource({ setDataSource({
@@ -79,7 +82,7 @@ const Models: React.FC = () => {
} finally { } finally {
setFirstLoad(false); setFirstLoad(false);
} }
}, [queryParams]); }, [queryParams, firstLoad]);
const handlePageChange = useCallback( const handlePageChange = useCallback(
(page: number, pageSize: number | undefined) => { (page: number, pageSize: number | undefined) => {
@@ -129,9 +132,12 @@ const Models: React.FC = () => {
} }
}; };
const handleSearch = useCallback((e: any) => { const handleSearch = useCallback(
fetchData(); (e: any) => {
}, []); fetchData();
},
[fetchData]
);
const handleNameChange = useCallback( const handleNameChange = useCallback(
(e: any) => { (e: any) => {
@@ -181,4 +187,4 @@ const Models: React.FC = () => {
); );
}; };
export default Models; export default memo(Models);
+1 -1
View File
@@ -1,6 +1,6 @@
.column-wrapper { .column-wrapper {
flex: 1; flex: 1;
height: calc(100vh - 85px); height: calc(100vh - 89px);
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
border-left: 1px solid var(--ant-color-split); border-left: 1px solid var(--ant-color-split);
+1 -1
View File
@@ -48,7 +48,7 @@ const GPUList: React.FC = () => {
const fetchData = async () => { const fetchData = async () => {
setDataSource((pre) => { setDataSource((pre) => {
pre.loading = true; pre.loading = true;
return pre; return { ...pre };
}); });
try { try {
const params = { const params = {
+1 -1
View File
@@ -49,7 +49,7 @@ const Resources: React.FC = () => {
const fetchData = async () => { const fetchData = async () => {
setDataSource((pre) => { setDataSource((pre) => {
pre.loading = true; pre.loading = true;
return pre; return { ...pre };
}); });
try { try {
const params = { const params = {
+1 -1
View File
@@ -72,7 +72,7 @@ const Users: React.FC = () => {
const fetchData = async () => { const fetchData = async () => {
setDataSource((pre) => { setDataSource((pre) => {
pre.loading = true; pre.loading = true;
return pre; return { ...pre };
}); });
try { try {
const params = { const params = {