chore: extract a model file item
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Col, Empty, Row, Select, Spin, Tag, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { Empty, Select, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, {
|
||||
forwardRef,
|
||||
@@ -16,18 +13,25 @@ import React, {
|
||||
} from 'react';
|
||||
import SimpleBar from 'simplebar-react';
|
||||
import 'simplebar-react/dist/simplebar.min.css';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
evaluationsModelSpec,
|
||||
queryHuggingfaceModelFiles,
|
||||
queryModelScopeModelFiles
|
||||
} from '../apis';
|
||||
import { modelSourceMap } from '../config';
|
||||
import { getFileType } from '../config/file-type';
|
||||
import '../style/hf-model-file.less';
|
||||
import FileParts from './file-parts';
|
||||
import IncompatiableInfo from './incompatiable-info';
|
||||
import ModelFileItem from './model-file-item';
|
||||
import TitleWrapper from './title-wrapper';
|
||||
|
||||
const ItemFileWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: 24px;
|
||||
`;
|
||||
|
||||
interface HFModelFileProps {
|
||||
isDownload?: boolean;
|
||||
selectedModel: any;
|
||||
@@ -44,35 +48,6 @@ const filterReg = /\.(safetensors|gguf)$/i;
|
||||
const includeReg = /\.(safetensors|gguf)$/i;
|
||||
const filterRegGGUF = /\.(gguf)$/i;
|
||||
|
||||
const FilePartsTag = (props: { parts: any[] }) => {
|
||||
if (!props.parts || !props.parts.length) {
|
||||
return null;
|
||||
}
|
||||
const { parts } = props;
|
||||
return (
|
||||
<Tooltip
|
||||
overlayInnerStyle={{
|
||||
width: 180,
|
||||
padding: 0
|
||||
}}
|
||||
title={<FileParts fileList={parts}></FileParts>}
|
||||
>
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="purple"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
<span style={{ opacity: 1 }}>
|
||||
<InfoCircleOutlined className="m-r-5" />
|
||||
{parts.length} parts
|
||||
</span>
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
||||
const { collapsed, modelSource, isDownload } = props;
|
||||
const intl = useIntl();
|
||||
@@ -332,28 +307,6 @@ const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
||||
setDataSource({ ...dataSource, fileList: list });
|
||||
};
|
||||
|
||||
const getModelQuantizationType = useCallback((item: any) => {
|
||||
let path = item.path;
|
||||
if (item?.parts?.length) {
|
||||
path = `${item.path}.gguf`;
|
||||
}
|
||||
const quanType = getFileType(path);
|
||||
if (quanType) {
|
||||
return (
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="cyan"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
{_.toUpper(quanType)}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
const handleOnEnter = (e: any, item: any) => {
|
||||
e.stopPropagation();
|
||||
if (e.key === 'Enter') {
|
||||
@@ -418,43 +371,20 @@ const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
||||
>
|
||||
<div style={{ padding: '16px 24px' }}>
|
||||
{dataSource.fileList.length ? (
|
||||
<Row gutter={[16, 24]}>
|
||||
<ItemFileWrapper>
|
||||
{_.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>
|
||||
<div className="tags flex-between">
|
||||
<span className="flex-center gap-8">
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="green"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
{convertFileSize(item.size)}
|
||||
</Tag>
|
||||
{getModelQuantizationType(item)}
|
||||
<FilePartsTag parts={item.parts}></FilePartsTag>
|
||||
</span>
|
||||
<IncompatiableInfo
|
||||
isEvaluating={isEvaluating}
|
||||
data={item.evaluateResult}
|
||||
></IncompatiableInfo>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
<ModelFileItem
|
||||
key={item.path}
|
||||
data={item}
|
||||
isEvaluating={isEvaluating}
|
||||
active={item.path === current}
|
||||
handleSelectModelFile={handleSelectModelFile}
|
||||
handleOnEnter={handleOnEnter}
|
||||
></ModelFileItem>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</ItemFileWrapper>
|
||||
) : (
|
||||
!dataSource.loading &&
|
||||
!dataSource.fileList.length && (
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
import { convertFileSize } from '@/utils';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import { Tag, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import _ from 'lodash';
|
||||
import React from 'react';
|
||||
import 'simplebar-react/dist/simplebar.min.css';
|
||||
import { getFileType } from '../config/file-type';
|
||||
import '../style/hf-model-file.less';
|
||||
import FileParts from './file-parts';
|
||||
import IncompatiableInfo from './incompatiable-info';
|
||||
|
||||
interface ModelFileItemProps {
|
||||
data: Record<string, any>;
|
||||
isEvaluating: boolean;
|
||||
active: boolean;
|
||||
handleSelectModelFile: (item: any) => void;
|
||||
handleOnEnter: (e: any, item: any) => void;
|
||||
}
|
||||
|
||||
const FilePartsTag = (props: { parts: any[] }) => {
|
||||
if (!props.parts || !props.parts.length) {
|
||||
return null;
|
||||
}
|
||||
const { parts } = props;
|
||||
return (
|
||||
<Tooltip
|
||||
overlayInnerStyle={{
|
||||
width: 180,
|
||||
padding: 0
|
||||
}}
|
||||
title={<FileParts fileList={parts}></FileParts>}
|
||||
>
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="purple"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
<span style={{ opacity: 1 }}>
|
||||
<InfoCircleOutlined className="m-r-5" />
|
||||
{parts.length} parts
|
||||
</span>
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
const ModelFileItem: React.FC<ModelFileItemProps> = (props) => {
|
||||
const {
|
||||
data: item,
|
||||
isEvaluating,
|
||||
active,
|
||||
handleSelectModelFile,
|
||||
handleOnEnter
|
||||
} = props;
|
||||
|
||||
const getModelQuantizationType = (item: any) => {
|
||||
let path = item.path;
|
||||
if (item?.parts?.length) {
|
||||
path = `${item.path}.gguf`;
|
||||
}
|
||||
const quanType = getFileType(path);
|
||||
if (quanType) {
|
||||
return (
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="cyan"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
{_.toUpper(quanType)}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('hf-model-file', {
|
||||
active: active
|
||||
})}
|
||||
tabIndex={0}
|
||||
onClick={() => handleSelectModelFile(item)}
|
||||
onKeyDown={(e) => handleOnEnter(e, item)}
|
||||
>
|
||||
<div className="title">{item.path}</div>
|
||||
<div className="tags flex-between">
|
||||
<span className="flex-center gap-8">
|
||||
<Tag
|
||||
className="tag-item"
|
||||
color="green"
|
||||
style={{
|
||||
marginRight: 0
|
||||
}}
|
||||
>
|
||||
{convertFileSize(item.size)}
|
||||
</Tag>
|
||||
{getModelQuantizationType(item)}
|
||||
<FilePartsTag parts={item.parts}></FilePartsTag>
|
||||
</span>
|
||||
<IncompatiableInfo
|
||||
isEvaluating={isEvaluating}
|
||||
data={item.evaluateResult}
|
||||
></IncompatiableInfo>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModelFileItem;
|
||||
@@ -14,9 +14,10 @@ const SearchInputWrapper = styled.div`
|
||||
const Holder = styled.div`
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
top: 13px;
|
||||
left: 34px;
|
||||
color: var(--ant-color-text-quaternary);
|
||||
font-size: var(--font-size-small);
|
||||
z-index: 10;
|
||||
kbd {
|
||||
border: 1px solid var(--ant-color-border);
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
backendOptionsMap,
|
||||
modelSourceMap
|
||||
} from '../config';
|
||||
import { identifyModelTask } from '../config/audio-catalog';
|
||||
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
||||
import SearchStyle from '../style/search-result.less';
|
||||
import SearchInput from './search-input';
|
||||
import SearchResult from './search-result';
|
||||
@@ -206,9 +206,9 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
||||
}
|
||||
try {
|
||||
const repoList = list.map((item) => {
|
||||
const isAuido = identifyModelTask(modelSource, item.name);
|
||||
const res = handleRecognizeAudioModel(item, modelSource);
|
||||
return {
|
||||
...(isAuido ? { backend: backendOptionsMap.voxBox } : {}),
|
||||
...(res.isAudio ? { backend: backendOptionsMap.voxBox } : {}),
|
||||
source: modelSource,
|
||||
...(modelSource === modelSourceMap.huggingface_value
|
||||
? {
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { modelSourceMap, modelTaskMap } from './index';
|
||||
import {
|
||||
HuggingFaceTaskMap,
|
||||
ModelscopeTaskMap,
|
||||
modelSourceMap,
|
||||
modelTaskMap
|
||||
} from './index';
|
||||
|
||||
export const HuggingFaceModels = [
|
||||
{
|
||||
@@ -208,3 +213,32 @@ export const identifyModelTask = (source: string, modelName: string) => {
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
export const handleRecognizeAudioModel = (selectModel: any, source: string) => {
|
||||
const modelTaskType = identifyModelTask(source, selectModel.name);
|
||||
let isAudio = modelTaskType === modelTaskMap.audio;
|
||||
|
||||
// Check if the model is audio type, if not, check if the task is audio
|
||||
if (!isAudio) {
|
||||
const modelTask =
|
||||
HuggingFaceTaskMap.audio.includes(selectModel.task) ||
|
||||
ModelscopeTaskMap.audio.includes(selectModel.task)
|
||||
? modelTaskMap.audio
|
||||
: '';
|
||||
|
||||
isAudio = modelTask === modelTaskMap.audio;
|
||||
}
|
||||
|
||||
const modelTaskData = {
|
||||
value: selectModel.task,
|
||||
type: isAudio ? modelTaskMap.audio : '',
|
||||
isAudio: isAudio,
|
||||
text2speech:
|
||||
HuggingFaceTaskMap[modelTaskMap.textToSpeech] === selectModel.task ||
|
||||
ModelscopeTaskMap[modelTaskMap.textToSpeech] === selectModel.task,
|
||||
speech2text:
|
||||
HuggingFaceTaskMap[modelTaskMap.speechToText] === selectModel.task ||
|
||||
ModelscopeTaskMap[modelTaskMap.speechToText] === selectModel.task
|
||||
};
|
||||
return modelTaskData;
|
||||
};
|
||||
|
||||
@@ -8,15 +8,13 @@ import _ from 'lodash';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { evaluationsModelSpec, queryGPUList } from '../apis';
|
||||
import {
|
||||
HuggingFaceTaskMap,
|
||||
ModelscopeTaskMap,
|
||||
backendOptionsMap,
|
||||
getSourceRepoConfigValue,
|
||||
modelSourceMap,
|
||||
modelTaskMap,
|
||||
setSourceRepoConfigValue
|
||||
} from '../config';
|
||||
import { identifyModelTask } from '../config/audio-catalog';
|
||||
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
||||
import {
|
||||
EvaluateResult,
|
||||
FormData,
|
||||
@@ -310,10 +308,12 @@ export const useCheckCompatibility = () => {
|
||||
const vram = convertFileSize(resource_claim.vram, 2);
|
||||
msgData = {
|
||||
title: intl.formatMessage({ id: 'models.form.check.passed' }),
|
||||
message: intl.formatMessage(
|
||||
{ id: 'models.form.check.claims' },
|
||||
{ ram, vram }
|
||||
)
|
||||
message: ram
|
||||
? intl.formatMessage(
|
||||
{ id: 'models.form.check.claims' },
|
||||
{ ram, vram }
|
||||
)
|
||||
: intl.formatMessage({ id: 'models.form.check.claims2' }, { vram })
|
||||
};
|
||||
}
|
||||
|
||||
@@ -522,28 +522,6 @@ export const useCheckCompatibility = () => {
|
||||
};
|
||||
|
||||
export const useSelectModel = () => {
|
||||
const handleRecognizeAudioModel = (selectModel: any, source: string) => {
|
||||
const modelTaskType = identifyModelTask(source, selectModel.name);
|
||||
|
||||
const modelTask =
|
||||
HuggingFaceTaskMap.audio.includes(selectModel.task) ||
|
||||
ModelscopeTaskMap.audio.includes(selectModel.task)
|
||||
? modelTaskMap.audio
|
||||
: '';
|
||||
|
||||
const modelTaskData = {
|
||||
value: selectModel.task,
|
||||
type: modelTaskType || modelTask,
|
||||
text2speech:
|
||||
HuggingFaceTaskMap[modelTaskMap.textToSpeech] === selectModel.task ||
|
||||
ModelscopeTaskMap[modelTaskMap.textToSpeech] === selectModel.task,
|
||||
speech2text:
|
||||
HuggingFaceTaskMap[modelTaskMap.speechToText] === selectModel.task ||
|
||||
ModelscopeTaskMap[modelTaskMap.speechToText] === selectModel.task
|
||||
};
|
||||
return modelTaskData;
|
||||
};
|
||||
|
||||
// just for setting the model name or repo_id, and the backend, Since the model type is fixed.
|
||||
const onSelectModel = (selectModel: any, source: string) => {
|
||||
let name = _.split(selectModel.name, '/').slice(-1)[0];
|
||||
@@ -551,6 +529,7 @@ export const useSelectModel = () => {
|
||||
name = _.toLower(name).replace(reg, '');
|
||||
|
||||
const modelTaskData = handleRecognizeAudioModel(selectModel, source);
|
||||
|
||||
return {
|
||||
repo_id: selectModel.name,
|
||||
name: name,
|
||||
|
||||
@@ -151,7 +151,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = forwardRef(
|
||||
<div>
|
||||
{
|
||||
<>
|
||||
<h3 className="m-b-20 m-l-10 font-size-14 line-24 font-600">
|
||||
<h3 className="m-b-20 font-size-14 line-24 font-600">
|
||||
{parametersTitle || (
|
||||
<span>
|
||||
{intl.formatMessage({ id: 'playground.parameters' })}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
position: relative;
|
||||
padding: 0 4px;
|
||||
border-radius: var(--border-radius-mini);
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.actions {
|
||||
|
||||
Reference in New Issue
Block a user