chore: extract a model file item
This commit is contained in:
@@ -30,7 +30,7 @@
|
|||||||
&.success {
|
&.success {
|
||||||
border: 1px solid var(--color-progress-green);
|
border: 1px solid var(--color-progress-green);
|
||||||
color: var(--color-progress-green);
|
color: var(--color-progress-green);
|
||||||
background: var(--ant-green-1);
|
background: var(--color-green-fill-light);
|
||||||
|
|
||||||
.content.success {
|
.content.success {
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ export const FilterBar: React.FC<FilterBarProps> = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}, [actionItems, actionType]);
|
}, [actionItems, actionType, rowSelection?.selectedRowKeys]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageTools
|
<PageTools
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ const InputWrapper = styled.div`
|
|||||||
input.ant-input-number-input {
|
input.ant-input-number-input {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
height: ${INPUTHEIGHT}px !important;
|
height: ${INPUTHEIGHT}px !important;
|
||||||
padding-block: 5px 4px;
|
padding-block: 6px 4px;
|
||||||
padding-inline: ${INPUT_INNER_PADDING}px;
|
padding-inline: ${INPUT_INNER_PADDING}px;
|
||||||
}
|
}
|
||||||
.ant-input-group {
|
.ant-input-group {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// background-color: rgba(0, 0, 0, 15%);
|
|
||||||
background-color: #e0f5ec;
|
background-color: #e0f5ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ export const StatusColorMap: Record<
|
|||||||
},
|
},
|
||||||
success: {
|
success: {
|
||||||
text: `var(--color-progress-green)`,
|
text: `var(--color-progress-green)`,
|
||||||
bg: `var(--ant-green-1)`
|
bg: `var(--color-green-fill-light)`
|
||||||
},
|
},
|
||||||
inactive: {
|
inactive: {
|
||||||
text: `var(--ant-color-text-tertiary)`,
|
text: `var(--ant-color-text-tertiary)`,
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ html {
|
|||||||
--color-chart-glod: rgba(250, 173, 20, 80%);
|
--color-chart-glod: rgba(250, 173, 20, 80%);
|
||||||
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
--seal-transition-func: cubic-bezier(0, 0, 1, 1);
|
||||||
--color-progress-green: rgba(84, 204, 152, 100%);
|
--color-progress-green: rgba(84, 204, 152, 100%);
|
||||||
|
--color-green-fill-light: rgb(243 251 248);
|
||||||
--color-border-1: rgba(217, 217, 217, 100%);
|
--color-border-1: rgba(217, 217, 217, 100%);
|
||||||
--ant-rate-star-color: #fadb14;
|
--ant-rate-star-color: #fadb14;
|
||||||
--color-fill-mask: rgba(255, 255, 255, 60%);
|
--color-fill-mask: rgba(255, 255, 255, 60%);
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export default {
|
|||||||
'models.search.vllm.tips':
|
'models.search.vllm.tips':
|
||||||
'Non-GGUF models use vox-box for audio and vLLM(x86 Linux only) for others.',
|
'Non-GGUF models use vox-box for audio and vLLM(x86 Linux only) for others.',
|
||||||
'models.search.voxbox.tips':
|
'models.search.voxbox.tips':
|
||||||
'To deploy an audio model, uncheck the GGUF checkbox.',
|
'To deploy an audio model, uncheck the checkbox.',
|
||||||
'models.form.ollamalink': 'Find More in Ollama Library',
|
'models.form.ollamalink': 'Find More in Ollama Library',
|
||||||
'models.form.backend_parameters.llamabox.placeholder':
|
'models.form.backend_parameters.llamabox.placeholder':
|
||||||
'e.g., --ctx-size=8192',
|
'e.g., --ctx-size=8192',
|
||||||
@@ -131,6 +131,7 @@ export default {
|
|||||||
'models.form.check.passed': 'Compatibility Check Passed',
|
'models.form.check.passed': 'Compatibility Check Passed',
|
||||||
'models.form.check.claims':
|
'models.form.check.claims':
|
||||||
'The model requires approximately {vram} VRAM and {ram} RAM.',
|
'The model requires approximately {vram} VRAM and {ram} RAM.',
|
||||||
|
'models.form.check.claims2': 'The model requires approximately {vram} VRAM.',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'Changes will only apply after you delete and recreate the instance.'
|
'Changes will only apply after you delete and recreate the instance.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
'resources.form.binpack.tips':
|
'resources.form.binpack.tips':
|
||||||
'Prioritize the overall utilization of cluster resources, reducing resource fragmentation on GPUs/Workers.',
|
'Prioritize the overall utilization of cluster resources, reducing resource fragmentation on GPUs/Workers.',
|
||||||
'resources.form.workerSelector.description':
|
'resources.form.workerSelector.description':
|
||||||
'The system selects the most suitable GPU or Worker for deploying model instances based on predefined labels.',
|
'The system selects the most suitable Worker for deploying model instances based on predefined labels.',
|
||||||
'resources.table.ip': 'IP',
|
'resources.table.ip': 'IP',
|
||||||
'resources.table.cpu': 'CPU',
|
'resources.table.cpu': 'CPU',
|
||||||
'resources.table.memory': 'RAM',
|
'resources.table.memory': 'RAM',
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ export default {
|
|||||||
'models.form.check.passed': 'Compatibility Check Passed',
|
'models.form.check.passed': 'Compatibility Check Passed',
|
||||||
'models.form.check.claims':
|
'models.form.check.claims':
|
||||||
'The model requires approximately {vram} VRAM and {ram} RAM.',
|
'The model requires approximately {vram} VRAM and {ram} RAM.',
|
||||||
|
'models.form.check.claims2': 'The model requires approximately {vram} VRAM.',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'Changes will only apply after you delete and recreate the instance.'
|
'Changes will only apply after you delete and recreate the instance.'
|
||||||
};
|
};
|
||||||
@@ -146,5 +147,6 @@ export default {
|
|||||||
// 11. 'models.form.check.passed',
|
// 11. 'models.form.check.passed',
|
||||||
// 12. 'models.form.check.claims',
|
// 12. 'models.form.check.claims',
|
||||||
// 13. 'model.deploy.search.placeholder',
|
// 13. 'model.deploy.search.placeholder',
|
||||||
// 14. 'models.form.update.tips
|
// 14. 'models.form.update.tips,
|
||||||
|
// 15. models.form.check.claims2
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
'resources.form.binpack.tips':
|
'resources.form.binpack.tips':
|
||||||
'クラスターリソースの全体的な利用率を優先し、ワーカー/GPU上のリソース断片化を減らします。',
|
'クラスターリソースの全体的な利用率を優先し、ワーカー/GPU上のリソース断片化を減らします。',
|
||||||
'resources.form.workerSelector.description':
|
'resources.form.workerSelector.description':
|
||||||
'システムは、事前定義されたラベルに基づいて、モデルインスタンスをデプロイするために最適なGPUまたはワーカーを選択します。',
|
'The system selects the most suitable Worker for deploying model instances based on predefined labels.',
|
||||||
'resources.table.ip': 'IP',
|
'resources.table.ip': 'IP',
|
||||||
'resources.table.cpu': 'CPU',
|
'resources.table.cpu': 'CPU',
|
||||||
'resources.table.memory': 'メモリ',
|
'resources.table.memory': 'メモリ',
|
||||||
@@ -93,4 +93,5 @@ export default {
|
|||||||
// 14. 'resources.worker.add.step2.tips',
|
// 14. 'resources.worker.add.step2.tips',
|
||||||
// 15. 'resources.modelfiles.copy.tips',
|
// 15. 'resources.modelfiles.copy.tips',
|
||||||
// 16. 'resources.filter.path',
|
// 16. 'resources.filter.path',
|
||||||
|
// 17. 'resources.form.workerSelector.description
|
||||||
// ========== End of To-Do List ==========
|
// ========== End of To-Do List ==========
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export default {
|
|||||||
'models.form.check.passed': 'Compatibility Check Passed',
|
'models.form.check.passed': 'Compatibility Check Passed',
|
||||||
'models.form.check.claims':
|
'models.form.check.claims':
|
||||||
'Модель требует примерно {vram} VRAM и {ram} RAM.',
|
'Модель требует примерно {vram} VRAM и {ram} RAM.',
|
||||||
|
'models.form.check.claims2': 'Модель требует примерно {vram} VRAM.',
|
||||||
'models.form.update.tips':
|
'models.form.update.tips':
|
||||||
'Changes will only apply after you delete and recreate the instance.'
|
'Changes will only apply after you delete and recreate the instance.'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
'resources.form.binpack.tips':
|
'resources.form.binpack.tips':
|
||||||
'Максимизирует утилизацию ресурсов, уменьшая фрагментацию на воркерах/GPU.',
|
'Максимизирует утилизацию ресурсов, уменьшая фрагментацию на воркерах/GPU.',
|
||||||
'resources.form.workerSelector.description':
|
'resources.form.workerSelector.description':
|
||||||
'Система выбирает подходящие GPU/воркеры для развертывания моделей на основе меток.',
|
'Система выбирает подходящие воркеры для развертывания моделей на основе меток.',
|
||||||
'resources.table.ip': 'IP-адрес',
|
'resources.table.ip': 'IP-адрес',
|
||||||
'resources.table.cpu': 'CPU',
|
'resources.table.cpu': 'CPU',
|
||||||
'resources.table.memory': 'ОЗУ',
|
'resources.table.memory': 'ОЗУ',
|
||||||
|
|||||||
@@ -60,10 +60,10 @@ export default {
|
|||||||
'models.form.backend': '后端',
|
'models.form.backend': '后端',
|
||||||
'models.form.backend_parameters': '后端参数',
|
'models.form.backend_parameters': '后端参数',
|
||||||
'models.search.gguf.tips':
|
'models.search.gguf.tips':
|
||||||
'GGUF 模型用 llama-box(支持 Linux, macOS 和 Windows)。',
|
'GGUF 模型用 llama-box(支持 Linux, macOS 和 Windows)。',
|
||||||
'models.search.vllm.tips':
|
'models.search.vllm.tips':
|
||||||
' 非 GGUF 的语音模型用 vox-box,其它非 GGUF 的模型用 vLLM(仅支持 x86 Linux)。',
|
' 非 GGUF 的语音模型用 vox-box,其它非 GGUF 的模型用 vLLM(仅支持 x86 Linux)。',
|
||||||
'models.search.voxbox.tips': '若需部语音模型取消勾选 GGUF 复选框。',
|
'models.search.voxbox.tips': '若需部署语音模型取消勾选。',
|
||||||
'models.form.ollamalink': '在 Ollama Library 中查找',
|
'models.form.ollamalink': '在 Ollama Library 中查找',
|
||||||
'models.form.backend_parameters.llamabox.placeholder':
|
'models.form.backend_parameters.llamabox.placeholder':
|
||||||
'例如,--ctx-size=8192',
|
'例如,--ctx-size=8192',
|
||||||
@@ -123,5 +123,6 @@ export default {
|
|||||||
'models.form.check.params': '正在校验配置...',
|
'models.form.check.params': '正在校验配置...',
|
||||||
'models.form.check.passed': '兼容性检查通过',
|
'models.form.check.passed': '兼容性检查通过',
|
||||||
'models.form.check.claims': '该模型大约需要 {vram} 显存和 {ram} 内存。',
|
'models.form.check.claims': '该模型大约需要 {vram} 显存和 {ram} 内存。',
|
||||||
|
'models.form.check.claims2': '该模型大约需要 {vram} 显存。',
|
||||||
'models.form.update.tips': '更改仅在删除并重新创建实例后生效。'
|
'models.form.update.tips': '更改仅在删除并重新创建实例后生效。'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default {
|
|||||||
'resources.form.binpack.tips':
|
'resources.form.binpack.tips':
|
||||||
'优先考虑整体集群的资源最大化利用,减少 GPU/Worker 上的资源碎片。',
|
'优先考虑整体集群的资源最大化利用,减少 GPU/Worker 上的资源碎片。',
|
||||||
'resources.form.workerSelector.description':
|
'resources.form.workerSelector.description':
|
||||||
'系统在部署模型实例时,会根据预定义的标签来选择最符合要求的 GPU 或 Worker。',
|
'系统在部署模型实例时,会根据预定义的标签来选择最符合要求的 Worker。',
|
||||||
'resources.table.ip': 'IP',
|
'resources.table.ip': 'IP',
|
||||||
'resources.table.cpu': 'CPU',
|
'resources.table.cpu': 'CPU',
|
||||||
'resources.table.memory': '内存',
|
'resources.table.memory': '内存',
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
import { createAxiosToken } from '@/hooks/use-chunk-request';
|
||||||
import { convertFileSize } from '@/utils';
|
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Col, Empty, Row, Select, Spin, Tag, Tooltip } from 'antd';
|
import { Empty, Select, Spin } from 'antd';
|
||||||
import classNames from 'classnames';
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React, {
|
import React, {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
@@ -16,18 +13,25 @@ import React, {
|
|||||||
} from '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';
|
||||||
|
import styled from 'styled-components';
|
||||||
import {
|
import {
|
||||||
evaluationsModelSpec,
|
evaluationsModelSpec,
|
||||||
queryHuggingfaceModelFiles,
|
queryHuggingfaceModelFiles,
|
||||||
queryModelScopeModelFiles
|
queryModelScopeModelFiles
|
||||||
} from '../apis';
|
} from '../apis';
|
||||||
import { modelSourceMap } from '../config';
|
import { modelSourceMap } from '../config';
|
||||||
import { getFileType } from '../config/file-type';
|
|
||||||
import '../style/hf-model-file.less';
|
import '../style/hf-model-file.less';
|
||||||
import FileParts from './file-parts';
|
import ModelFileItem from './model-file-item';
|
||||||
import IncompatiableInfo from './incompatiable-info';
|
|
||||||
import TitleWrapper from './title-wrapper';
|
import TitleWrapper from './title-wrapper';
|
||||||
|
|
||||||
|
const ItemFileWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
gap: 24px;
|
||||||
|
`;
|
||||||
|
|
||||||
interface HFModelFileProps {
|
interface HFModelFileProps {
|
||||||
isDownload?: boolean;
|
isDownload?: boolean;
|
||||||
selectedModel: any;
|
selectedModel: any;
|
||||||
@@ -44,35 +48,6 @@ const filterReg = /\.(safetensors|gguf)$/i;
|
|||||||
const includeReg = /\.(safetensors|gguf)$/i;
|
const includeReg = /\.(safetensors|gguf)$/i;
|
||||||
const filterRegGGUF = /\.(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 HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
||||||
const { collapsed, modelSource, isDownload } = props;
|
const { collapsed, modelSource, isDownload } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -332,28 +307,6 @@ const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
|||||||
setDataSource({ ...dataSource, fileList: list });
|
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) => {
|
const handleOnEnter = (e: any, item: any) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
@@ -418,43 +371,20 @@ const HFModelFile: React.FC<HFModelFileProps> = forwardRef((props, ref) => {
|
|||||||
>
|
>
|
||||||
<div style={{ padding: '16px 24px' }}>
|
<div style={{ padding: '16px 24px' }}>
|
||||||
{dataSource.fileList.length ? (
|
{dataSource.fileList.length ? (
|
||||||
<Row gutter={[16, 24]}>
|
<ItemFileWrapper>
|
||||||
{_.map(dataSource.fileList, (item: any) => {
|
{_.map(dataSource.fileList, (item: any) => {
|
||||||
return (
|
return (
|
||||||
<Col span={24} key={item.path}>
|
<ModelFileItem
|
||||||
<div
|
key={item.path}
|
||||||
className={classNames('hf-model-file', {
|
data={item}
|
||||||
active: item.path === current
|
isEvaluating={isEvaluating}
|
||||||
})}
|
active={item.path === current}
|
||||||
tabIndex={0}
|
handleSelectModelFile={handleSelectModelFile}
|
||||||
onClick={() => handleSelectModelFile(item)}
|
handleOnEnter={handleOnEnter}
|
||||||
onKeyDown={(e) => handleOnEnter(e, item)}
|
></ModelFileItem>
|
||||||
>
|
|
||||||
<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>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Row>
|
</ItemFileWrapper>
|
||||||
) : (
|
) : (
|
||||||
!dataSource.loading &&
|
!dataSource.loading &&
|
||||||
!dataSource.fileList.length && (
|
!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`
|
const Holder = styled.div`
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 12px;
|
top: 13px;
|
||||||
left: 34px;
|
left: 34px;
|
||||||
color: var(--ant-color-text-quaternary);
|
color: var(--ant-color-text-quaternary);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
kbd {
|
kbd {
|
||||||
border: 1px solid var(--ant-color-border);
|
border: 1px solid var(--ant-color-border);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {
|
|||||||
backendOptionsMap,
|
backendOptionsMap,
|
||||||
modelSourceMap
|
modelSourceMap
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { identifyModelTask } from '../config/audio-catalog';
|
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
||||||
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';
|
||||||
@@ -206,9 +206,9 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const repoList = list.map((item) => {
|
const repoList = list.map((item) => {
|
||||||
const isAuido = identifyModelTask(modelSource, item.name);
|
const res = handleRecognizeAudioModel(item, modelSource);
|
||||||
return {
|
return {
|
||||||
...(isAuido ? { backend: backendOptionsMap.voxBox } : {}),
|
...(res.isAudio ? { backend: backendOptionsMap.voxBox } : {}),
|
||||||
source: modelSource,
|
source: modelSource,
|
||||||
...(modelSource === modelSourceMap.huggingface_value
|
...(modelSource === modelSourceMap.huggingface_value
|
||||||
? {
|
? {
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import { modelSourceMap, modelTaskMap } from './index';
|
import {
|
||||||
|
HuggingFaceTaskMap,
|
||||||
|
ModelscopeTaskMap,
|
||||||
|
modelSourceMap,
|
||||||
|
modelTaskMap
|
||||||
|
} from './index';
|
||||||
|
|
||||||
export const HuggingFaceModels = [
|
export const HuggingFaceModels = [
|
||||||
{
|
{
|
||||||
@@ -208,3 +213,32 @@ export const identifyModelTask = (source: string, modelName: string) => {
|
|||||||
}
|
}
|
||||||
return '';
|
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 { useEffect, useRef, useState } from 'react';
|
||||||
import { evaluationsModelSpec, queryGPUList } from '../apis';
|
import { evaluationsModelSpec, queryGPUList } from '../apis';
|
||||||
import {
|
import {
|
||||||
HuggingFaceTaskMap,
|
|
||||||
ModelscopeTaskMap,
|
|
||||||
backendOptionsMap,
|
backendOptionsMap,
|
||||||
getSourceRepoConfigValue,
|
getSourceRepoConfigValue,
|
||||||
modelSourceMap,
|
modelSourceMap,
|
||||||
modelTaskMap,
|
modelTaskMap,
|
||||||
setSourceRepoConfigValue
|
setSourceRepoConfigValue
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { identifyModelTask } from '../config/audio-catalog';
|
import { handleRecognizeAudioModel } from '../config/audio-catalog';
|
||||||
import {
|
import {
|
||||||
EvaluateResult,
|
EvaluateResult,
|
||||||
FormData,
|
FormData,
|
||||||
@@ -310,10 +308,12 @@ export const useCheckCompatibility = () => {
|
|||||||
const vram = convertFileSize(resource_claim.vram, 2);
|
const vram = convertFileSize(resource_claim.vram, 2);
|
||||||
msgData = {
|
msgData = {
|
||||||
title: intl.formatMessage({ id: 'models.form.check.passed' }),
|
title: intl.formatMessage({ id: 'models.form.check.passed' }),
|
||||||
message: intl.formatMessage(
|
message: ram
|
||||||
{ id: 'models.form.check.claims' },
|
? intl.formatMessage(
|
||||||
{ ram, vram }
|
{ 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 = () => {
|
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.
|
// just for setting the model name or repo_id, and the backend, Since the model type is fixed.
|
||||||
const onSelectModel = (selectModel: any, source: string) => {
|
const onSelectModel = (selectModel: any, source: string) => {
|
||||||
let name = _.split(selectModel.name, '/').slice(-1)[0];
|
let name = _.split(selectModel.name, '/').slice(-1)[0];
|
||||||
@@ -551,6 +529,7 @@ export const useSelectModel = () => {
|
|||||||
name = _.toLower(name).replace(reg, '');
|
name = _.toLower(name).replace(reg, '');
|
||||||
|
|
||||||
const modelTaskData = handleRecognizeAudioModel(selectModel, source);
|
const modelTaskData = handleRecognizeAudioModel(selectModel, source);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
repo_id: selectModel.name,
|
repo_id: selectModel.name,
|
||||||
name: name,
|
name: name,
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ const ParamsSettings: React.FC<ParamsSettingsProps> = forwardRef(
|
|||||||
<div>
|
<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 || (
|
{parametersTitle || (
|
||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({ id: 'playground.parameters' })}
|
{intl.formatMessage({ id: 'playground.parameters' })}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
border-radius: var(--border-radius-mini);
|
border-radius: var(--border-radius-mini);
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
|
|||||||
+2
-2
@@ -25,8 +25,8 @@ export const convertFileSize = (
|
|||||||
sizeInBytes?: number,
|
sizeInBytes?: number,
|
||||||
prec = 1,
|
prec = 1,
|
||||||
allowEmpty = false
|
allowEmpty = false
|
||||||
): string => {
|
): string | number => {
|
||||||
if (!sizeInBytes) return allowEmpty ? '' : '0';
|
if (!sizeInBytes) return allowEmpty ? '' : 0;
|
||||||
|
|
||||||
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB'];
|
||||||
let size = sizeInBytes;
|
let size = sizeInBytes;
|
||||||
|
|||||||
Reference in New Issue
Block a user