fix: query models sort
This commit is contained in:
@@ -26,6 +26,10 @@
|
|||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.m-r-2 {
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.m-r-8 {
|
.m-r-8 {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
@@ -67,6 +71,10 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-5 {
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.relative {
|
.relative {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFromIconfontCN } from '@ant-design/icons';
|
import { createFromIconfontCN } from '@ant-design/icons';
|
||||||
|
|
||||||
const IconFont = createFromIconfontCN({
|
const IconFont = createFromIconfontCN({
|
||||||
scriptUrl: '//at.alicdn.com/t/c/font_4613488_orlwzwe9x4k.js'
|
scriptUrl: '//at.alicdn.com/t/c/font_4613488_m179wc500g.js'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -22,11 +22,16 @@ export default {
|
|||||||
'models.sort.name': 'Name',
|
'models.sort.name': 'Name',
|
||||||
'models.sort.size': 'Size',
|
'models.sort.size': 'Size',
|
||||||
'models.sort.likes': 'Likes',
|
'models.sort.likes': 'Likes',
|
||||||
|
'models.sort.trending': 'Trending',
|
||||||
'models.sort.downloads': 'Downloads',
|
'models.sort.downloads': 'Downloads',
|
||||||
'models.sort.updated': 'Updated',
|
'models.sort.updated': 'Updated',
|
||||||
'models.search.result': '{count} results',
|
'models.search.result': '{count} results',
|
||||||
'models.data.card': 'Model Card',
|
'models.data.card': 'Model Card',
|
||||||
'models.available.files': 'Available Files',
|
'models.available.files': 'Available Files',
|
||||||
'models.viewin.hf': 'View in Hugging Face',
|
'models.viewin.hf': 'View in Hugging Face',
|
||||||
'models.architecture': 'Architecture'
|
'models.architecture': 'Architecture',
|
||||||
|
'models.search.noresult': 'No related models found',
|
||||||
|
'models.search.nofiles': 'No available files',
|
||||||
|
'models.search.networkerror': 'Network connection exception!',
|
||||||
|
'models.search.hfvisit': 'Please make sure you can visit'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,11 +22,16 @@ export default {
|
|||||||
'models.sort.name': '名称',
|
'models.sort.name': '名称',
|
||||||
'models.sort.size': '大小',
|
'models.sort.size': '大小',
|
||||||
'models.sort.likes': '喜欢',
|
'models.sort.likes': '喜欢',
|
||||||
|
'models.sort.trending': '趋势',
|
||||||
'models.sort.downloads': '下载',
|
'models.sort.downloads': '下载',
|
||||||
'models.sort.updated': '更新时间',
|
'models.sort.updated': '更新时间',
|
||||||
'models.search.result': '{count} 个结果',
|
'models.search.result': '{count} 个结果',
|
||||||
'models.data.card': '模型简介',
|
'models.data.card': '模型简介',
|
||||||
'models.available.files': '可用文件',
|
'models.available.files': '可用文件',
|
||||||
'models.viewin.hf': '在 Hugging Face 中查看',
|
'models.viewin.hf': '在 Hugging Face 中查看',
|
||||||
'models.architecture': '架构'
|
'models.architecture': '架构',
|
||||||
|
'models.search.noresult': '未找到相关模型',
|
||||||
|
'models.search.nofiles': '无可用文件',
|
||||||
|
'models.search.networkerror': '网络连接异常!',
|
||||||
|
'models.search.hfvisit': '请确保您可以访问'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export async function queryHuggingfaceModels(
|
|||||||
search: {
|
search: {
|
||||||
query: string;
|
query: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
sort?: string;
|
||||||
task?: PipelineType;
|
task?: PipelineType;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -143,16 +144,15 @@ export async function queryHuggingfaceModels(
|
|||||||
for await (const model of listModels({
|
for await (const model of listModels({
|
||||||
...params,
|
...params,
|
||||||
...options,
|
...options,
|
||||||
limit: 500,
|
limit: 100,
|
||||||
additionalFields: ['sha'],
|
additionalFields: ['sha'],
|
||||||
fetch(url: string, config: any) {
|
fetch(url: string, config: any) {
|
||||||
try {
|
try {
|
||||||
return fetch(url, {
|
return fetch(`${url}&sort=${params.search.sort}`, {
|
||||||
...config,
|
...config,
|
||||||
signal: options.signal
|
signal: options.signal
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('queryHuggingfaceModels error===', error);
|
|
||||||
// ignore
|
// ignore
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -170,6 +170,7 @@ export async function queryHuggingfaceModelFiles(
|
|||||||
const result = [];
|
const result = [];
|
||||||
for await (const fileInfo of listFiles({
|
for await (const fileInfo of listFiles({
|
||||||
...params,
|
...params,
|
||||||
|
recursive: true,
|
||||||
fetch(url: string, config: any) {
|
fetch(url: string, config: any) {
|
||||||
try {
|
try {
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { convertFileSize } from '@/utils';
|
import { convertFileSize } from '@/utils';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Col, Empty, Row, Select, Space, Spin, Tag } from 'antd';
|
import { Col, Empty, Row, Select, Space, Spin, Tag } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
@@ -62,7 +61,11 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
|||||||
signal: axiosTokenRef.current.signal
|
signal: axiosTokenRef.current.signal
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
const list = _.filter(res, (file: any) => {
|
const fileList = _.filter(res, (file: any) => {
|
||||||
|
return file.type === 'file';
|
||||||
|
});
|
||||||
|
|
||||||
|
const list = _.filter(fileList, (file: any) => {
|
||||||
return _.endsWith(file.path, '.gguf') || _.includes(file.path, '.gguf');
|
return _.endsWith(file.path, '.gguf') || _.includes(file.path, '.gguf');
|
||||||
});
|
});
|
||||||
const sortList = _.sortBy(list, (item: any) => {
|
const sortList = _.sortBy(list, (item: any) => {
|
||||||
@@ -182,16 +185,14 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
|||||||
})}
|
})}
|
||||||
</Row>
|
</Row>
|
||||||
) : (
|
) : (
|
||||||
!dataSource.loading && (
|
!dataSource.loading &&
|
||||||
|
!loadingModel && (
|
||||||
<Empty
|
<Empty
|
||||||
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
||||||
image={
|
image={Empty.PRESENTED_IMAGE_SIMPLE}
|
||||||
<SearchOutlined
|
description={intl.formatMessage({
|
||||||
className="font-size-16"
|
id: 'models.search.nofiles'
|
||||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
})}
|
||||||
></SearchOutlined>
|
|
||||||
}
|
|
||||||
description="No files found"
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ const ModelCard: React.FC<{
|
|||||||
repo: string;
|
repo: string;
|
||||||
onCollapse: (flag: boolean) => void;
|
onCollapse: (flag: boolean) => void;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
|
loadingModel?: boolean;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const { repo, onCollapse, collapsed } = props;
|
const { repo, onCollapse, collapsed, loadingModel } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const requestSource = useRequestToken();
|
const requestSource = useRequestToken();
|
||||||
const [modelData, setModelData] = useState<any>({});
|
const [modelData, setModelData] = useState<any>({});
|
||||||
@@ -138,7 +139,7 @@ const ModelCard: React.FC<{
|
|||||||
>
|
>
|
||||||
<span className="mkd-title" onClick={handleCollapse}>
|
<span className="mkd-title" onClick={handleCollapse}>
|
||||||
<span>
|
<span>
|
||||||
<FileTextOutlined className="m-r-5" /> README.md
|
<FileTextOutlined className="m-r-2" /> README.md
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{collapsed ? <DownOutlined /> : <RightOutlined />}
|
{collapsed ? <DownOutlined /> : <RightOutlined />}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
|
||||||
import { BulbOutlined } from '@ant-design/icons';
|
import { BulbOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Input, Select } from 'antd';
|
import { Button, Input, Select } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { queryHuggingfaceModels } from '../apis';
|
import { queryHuggingfaceModels } from '../apis';
|
||||||
import { modelSourceMap, ollamaModelOptions } from '../config';
|
import { ModelSortType, modelSourceMap, ollamaModelOptions } from '../config';
|
||||||
import SearchStyle from '../style/search-result.less';
|
import SearchStyle from '../style/search-result.less';
|
||||||
import SearchInput from './search-input';
|
import SearchInput from './search-input';
|
||||||
import SearchResult from './search-result';
|
import SearchResult from './search-result';
|
||||||
@@ -17,21 +16,6 @@ interface SearchInputProps {
|
|||||||
onSelectModel: (model: any) => void;
|
onSelectModel: (model: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sourceList = [
|
|
||||||
{
|
|
||||||
label: (
|
|
||||||
<IconFont type="icon-huggingface" className="font-size-14"></IconFont>
|
|
||||||
),
|
|
||||||
value: 'huggingface',
|
|
||||||
key: 'huggingface'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: <IconFont type="icon-ollama" className="font-size-14"></IconFont>,
|
|
||||||
value: 'ollama_library',
|
|
||||||
key: 'ollama_library'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const SearchModel: React.FC<SearchInputProps> = (props) => {
|
const SearchModel: React.FC<SearchInputProps> = (props) => {
|
||||||
console.log('SearchModel======');
|
console.log('SearchModel======');
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -39,24 +23,35 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
const [dataSource, setDataSource] = useState<{
|
const [dataSource, setDataSource] = useState<{
|
||||||
repoOptions: any[];
|
repoOptions: any[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
networkError: boolean;
|
||||||
|
sortType: string;
|
||||||
}>({
|
}>({
|
||||||
repoOptions: [],
|
repoOptions: [],
|
||||||
loading: false
|
loading: false,
|
||||||
|
networkError: false,
|
||||||
|
sortType: ModelSortType.trendingScore
|
||||||
});
|
});
|
||||||
const [current, setCurrent] = useState<string>('');
|
const [current, setCurrent] = useState<string>('');
|
||||||
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 searchInputRef = useRef<any>('');
|
||||||
const modelFilesSortOptions = useRef<any[]>([
|
const modelFilesSortOptions = useRef<any[]>([
|
||||||
{ label: intl.formatMessage({ id: 'models.sort.likes' }), value: 'likes' },
|
{
|
||||||
|
label: intl.formatMessage({ id: 'models.sort.trending' }),
|
||||||
|
value: ModelSortType.trendingScore
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage({ id: 'models.sort.likes' }),
|
||||||
|
value: ModelSortType.likes
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: intl.formatMessage({ id: 'models.sort.downloads' }),
|
label: intl.formatMessage({ id: 'models.sort.downloads' }),
|
||||||
value: 'downloads'
|
value: ModelSortType.downloads
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: intl.formatMessage({ id: 'models.sort.updated' }),
|
label: intl.formatMessage({ id: 'models.sort.updated' }),
|
||||||
value: 'updatedAt'
|
value: ModelSortType.lastModified
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -66,7 +61,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOnSearchRepo = useCallback(
|
const handleOnSearchRepo = useCallback(
|
||||||
async (text: string) => {
|
async (sortType?: string) => {
|
||||||
axiosTokenRef.current?.abort?.();
|
axiosTokenRef.current?.abort?.();
|
||||||
axiosTokenRef.current = new AbortController();
|
axiosTokenRef.current = new AbortController();
|
||||||
if (dataSource.loading) return;
|
if (dataSource.loading) return;
|
||||||
@@ -79,7 +74,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
cacheRepoOptions.current = [];
|
cacheRepoOptions.current = [];
|
||||||
const params = {
|
const params = {
|
||||||
search: {
|
search: {
|
||||||
query: text,
|
query: searchInputRef.current || '',
|
||||||
|
sort: sortType || dataSource.sortType,
|
||||||
tags: ['gguf']
|
tags: ['gguf']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -93,22 +89,22 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
label: item.name
|
label: item.name
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const sortedList = _.sortBy(
|
|
||||||
list,
|
cacheRepoOptions.current = list;
|
||||||
(item: any) => item[sortType]
|
|
||||||
).reverse();
|
|
||||||
cacheRepoOptions.current = sortedList;
|
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: sortedList,
|
repoOptions: list,
|
||||||
loading: false
|
loading: false,
|
||||||
|
networkError: false,
|
||||||
|
sortType: sortType || dataSource.sortType
|
||||||
});
|
});
|
||||||
setLoadingModel?.(false);
|
setLoadingModel?.(false);
|
||||||
handleOnSelectModel(sortedList[0]);
|
handleOnSelectModel(list[0]);
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.log('queryHuggingfaceModels error===', error);
|
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: [],
|
repoOptions: [],
|
||||||
loading: false
|
loading: false,
|
||||||
|
sortType: sortType || dataSource.sortType,
|
||||||
|
networkError: error?.message === 'Failed to fetch'
|
||||||
});
|
});
|
||||||
setLoadingModel?.(false);
|
setLoadingModel?.(false);
|
||||||
handleOnSelectModel({});
|
handleOnSelectModel({});
|
||||||
@@ -120,8 +116,8 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
|
|
||||||
const handlerSearchModels = useCallback(
|
const handlerSearchModels = useCallback(
|
||||||
async (e: any) => {
|
async (e: any) => {
|
||||||
const text = e.target.value;
|
searchInputRef.current = e.target.value;
|
||||||
handleOnSearchRepo(text);
|
handleOnSearchRepo();
|
||||||
},
|
},
|
||||||
[handleOnSearchRepo]
|
[handleOnSearchRepo]
|
||||||
);
|
);
|
||||||
@@ -132,12 +128,14 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
!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) {
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: ollamaModelOptions,
|
repoOptions: ollamaModelOptions,
|
||||||
loading: false
|
loading: false,
|
||||||
|
networkError: false,
|
||||||
|
sortType: dataSource.sortType
|
||||||
});
|
});
|
||||||
cacheRepoOptions.current = ollamaModelOptions;
|
cacheRepoOptions.current = ollamaModelOptions;
|
||||||
handleOnSelectModel(ollamaModelOptions[0]);
|
handleOnSelectModel(ollamaModelOptions[0]);
|
||||||
@@ -151,7 +149,9 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
});
|
});
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: list,
|
repoOptions: list,
|
||||||
loading: false
|
loading: false,
|
||||||
|
networkError: false,
|
||||||
|
sortType: dataSource.sortType
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,7 +164,9 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
onSourceChange?.(source);
|
onSourceChange?.(source);
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: [],
|
repoOptions: [],
|
||||||
loading: false
|
loading: false,
|
||||||
|
networkError: false,
|
||||||
|
sortType: dataSource.sortType
|
||||||
});
|
});
|
||||||
cacheRepoOptions.current = [];
|
cacheRepoOptions.current = [];
|
||||||
};
|
};
|
||||||
@@ -186,15 +188,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSortChange = (value: string) => {
|
const handleSortChange = (value: string) => {
|
||||||
const sortedList = _.sortBy(
|
handleOnSearchRepo(value);
|
||||||
dataSource.repoOptions,
|
|
||||||
(item: any) => item[value]
|
|
||||||
).reverse();
|
|
||||||
setSortType(value);
|
|
||||||
setDataSource({
|
|
||||||
repoOptions: sortedList,
|
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
const renderHFSearch = () => {
|
const renderHFSearch = () => {
|
||||||
return (
|
return (
|
||||||
@@ -210,7 +204,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<Select
|
||||||
value={sortType}
|
value={dataSource.sortType}
|
||||||
onChange={handleSortChange}
|
onChange={handleSortChange}
|
||||||
labelRender={({ label }) => {
|
labelRender={({ label }) => {
|
||||||
return (
|
return (
|
||||||
@@ -275,6 +269,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
<SearchResult
|
<SearchResult
|
||||||
loading={dataSource.loading}
|
loading={dataSource.loading}
|
||||||
resultList={dataSource.repoOptions}
|
resultList={dataSource.repoOptions}
|
||||||
|
networkError={dataSource.networkError}
|
||||||
current={current}
|
current={current}
|
||||||
source={modelSource}
|
source={modelSource}
|
||||||
onSelect={handleOnSelectModel}
|
onSelect={handleOnSelectModel}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { Col, Empty, Row, Spin } from 'antd';
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Button, Col, Empty, Row, Spin } from 'antd';
|
||||||
import React from 'react';
|
import React 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';
|
||||||
@@ -13,11 +15,13 @@ interface SearchResultProps {
|
|||||||
source?: string;
|
source?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
networkError?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchResult: React.FC<SearchResultProps> = (props) => {
|
const SearchResult: React.FC<SearchResultProps> = (props) => {
|
||||||
console.log('SearchResult======');
|
console.log('SearchResult======');
|
||||||
const { resultList, onSelect, source } = props;
|
const { resultList, onSelect, source, networkError } = props;
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleSelect = (e: any, item: any) => {
|
const handleSelect = (e: any, item: any) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -29,6 +33,57 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
onSelect?.(item);
|
onSelect?.(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderEmpty = () => {
|
||||||
|
if (networkError) {
|
||||||
|
return (
|
||||||
|
<Empty
|
||||||
|
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
||||||
|
image={
|
||||||
|
<IconFont
|
||||||
|
type="icon-networkerror"
|
||||||
|
style={{
|
||||||
|
color: 'var(--ant-color-text-tertiary)',
|
||||||
|
fontSize: '66px'
|
||||||
|
}}
|
||||||
|
></IconFont>
|
||||||
|
}
|
||||||
|
description={
|
||||||
|
<div className="flex-column gap-5">
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'models.search.networkerror' })}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({ id: 'models.search.hfvisit' })}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
href="https://huggingface.co/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Hugging Face
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Empty
|
||||||
|
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
||||||
|
image={
|
||||||
|
<SearchOutlined
|
||||||
|
className="font-size-16"
|
||||||
|
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
||||||
|
></SearchOutlined>
|
||||||
|
}
|
||||||
|
description={intl.formatMessage({ id: 'models.search.noresult' })}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<SimpleBar style={{ height: 'calc(100vh - 194px)' }}>
|
<SimpleBar style={{ height: 'calc(100vh - 194px)' }}>
|
||||||
<div style={{ ...props.style }} className="search-result-wrap">
|
<div style={{ ...props.style }} className="search-result-wrap">
|
||||||
@@ -58,18 +113,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
))}
|
))}
|
||||||
</Row>
|
</Row>
|
||||||
) : (
|
) : (
|
||||||
!props.loading && (
|
!props.loading && renderEmpty()
|
||||||
<Empty
|
|
||||||
imageStyle={{ height: 'auto', marginTop: '20px' }}
|
|
||||||
image={
|
|
||||||
<SearchOutlined
|
|
||||||
className="font-size-16"
|
|
||||||
style={{ color: 'var(--ant-color-text-tertiary)' }}
|
|
||||||
></SearchOutlined>
|
|
||||||
}
|
|
||||||
description="No models found"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
|
|||||||
@@ -141,9 +141,9 @@ export const ActionList = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export const modelFilesSortOptions = [
|
export const ModelSortType = {
|
||||||
// { label: 'Trending', value: 'trendingScore' },
|
trendingScore: 'trendingScore',
|
||||||
{ label: 'models.sort.likes', value: 'likes' },
|
likes: 'likes',
|
||||||
{ label: 'models.sort.downloads', value: 'downloads' },
|
downloads: 'downloads',
|
||||||
{ label: 'models.sort.updated', value: 'updatedAt' }
|
lastModified: 'lastModified'
|
||||||
];
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
border: 1px solid var(--ant-color-border);
|
border: 1px solid var(--ant-color-border);
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-fill-sider);
|
background-color: var(--color-fill-sider);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
border: 1px solid var(--ant-color-border);
|
border: 1px solid var(--ant-color-border);
|
||||||
border-radius: var(--border-radius-base);
|
border-radius: var(--border-radius-base);
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-fill-sider);
|
background-color: var(--color-fill-sider);
|
||||||
|
|||||||
Reference in New Issue
Block a user