feat: modelscope model
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const proxyTableList = ['cli', 'v1', 'auth', 'v1-openai', 'version'];
|
const proxyTableList = ['cli', 'v1', 'auth', 'v1-openai', 'version', 'proxy'];
|
||||||
|
|
||||||
// @ts-ingore
|
// @ts-ingore
|
||||||
export default function createProxyTable(target?: string) {
|
export default function createProxyTable(target?: string) {
|
||||||
|
|||||||
@@ -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_7vr8v36d7xp.js'
|
scriptUrl: '//at.alicdn.com/t/c/font_4613488_4jkdkc8jcf7.js'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default IconFont;
|
export default IconFont;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const KeybindingsMap = {
|
|||||||
INPUT: ['Ctrl+K', 'Meta+K'],
|
INPUT: ['Ctrl+K', 'Meta+K'],
|
||||||
NEW1: ['Ctrl+1', 'Meta+1'],
|
NEW1: ['Ctrl+1', 'Meta+1'],
|
||||||
NEW2: ['Ctrl+2', 'Meta+2'],
|
NEW2: ['Ctrl+2', 'Meta+2'],
|
||||||
|
NEW3: ['Ctrl+3', 'Meta+3'],
|
||||||
FOCUS: ['/', '/'],
|
FOCUS: ['/', '/'],
|
||||||
ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter']
|
ADD: ['Alt+Ctrl+Enter', 'Alt+Meta+Enter']
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,9 +153,6 @@ html {
|
|||||||
|
|
||||||
body * {
|
body * {
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
font-family: 'noto sans', sans-serif;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ export default (props: any) => {
|
|||||||
{logo}
|
{logo}
|
||||||
<div className="collapse-wrap">
|
<div className="collapse-wrap">
|
||||||
<Button
|
<Button
|
||||||
|
style={{ marginRight: collapsed ? 0 : -14 }}
|
||||||
size="small"
|
size="small"
|
||||||
type={collapsed ? 'default' : 'text'}
|
type={collapsed ? 'default' : 'text'}
|
||||||
onClick={handleToggleCollapse}
|
onClick={handleToggleCollapse}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default {
|
|||||||
'model.form.ollama.model': 'Ollama Model',
|
'model.form.ollama.model': 'Ollama Model',
|
||||||
'model.form.ollamaholder': 'Please select or input model name',
|
'model.form.ollamaholder': 'Please select or input model name',
|
||||||
'model.deploy.sort': 'Sort',
|
'model.deploy.sort': 'Sort',
|
||||||
'model.deploy.search.placeholder': 'Search models from Hugging Face',
|
'model.deploy.search.placeholder': 'Search models from {source}',
|
||||||
'model.form.ollamatips':
|
'model.form.ollamatips':
|
||||||
'Tip: The following are the preconfigured Ollama models in GPUStack. Please select the model you want, or directly enter the model you wish to deploy in the 【{name}】 input box on the right.',
|
'Tip: The following are the preconfigured Ollama models in GPUStack. Please select the model you want, or directly enter the model you wish to deploy in the 【{name}】 input box on the right.',
|
||||||
'models.sort.name': 'Name',
|
'models.sort.name': 'Name',
|
||||||
@@ -35,6 +35,7 @@ export default {
|
|||||||
'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.viewin.modelscope': 'View in ModelScope',
|
||||||
'models.architecture': 'Architecture',
|
'models.architecture': 'Architecture',
|
||||||
'models.search.noresult': 'No related models found',
|
'models.search.noresult': 'No related models found',
|
||||||
'models.search.nofiles': 'No available files',
|
'models.search.nofiles': 'No available files',
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default {
|
|||||||
'model.form.ollama.model': 'Ollama 模型',
|
'model.form.ollama.model': 'Ollama 模型',
|
||||||
'model.form.ollamaholder': '请选择或输入模型名称',
|
'model.form.ollamaholder': '请选择或输入模型名称',
|
||||||
'model.deploy.sort': '排序',
|
'model.deploy.sort': '排序',
|
||||||
'model.deploy.search.placeholder': '从 Hugging Face 搜索模型',
|
'model.deploy.search.placeholder': '从 {source} 搜索模型',
|
||||||
'model.form.ollamatips':
|
'model.form.ollamatips':
|
||||||
'提示:以下为 GPUStack 预设的 Ollama 模型,请选择你想要的模型或者直接在右侧表单 【{name}】 输入框中输入你要部署的模型。',
|
'提示:以下为 GPUStack 预设的 Ollama 模型,请选择你想要的模型或者直接在右侧表单 【{name}】 输入框中输入你要部署的模型。',
|
||||||
'models.sort.name': '名称',
|
'models.sort.name': '名称',
|
||||||
@@ -35,6 +35,7 @@ export default {
|
|||||||
'models.data.card': '模型简介',
|
'models.data.card': '模型简介',
|
||||||
'models.available.files': '可用文件',
|
'models.available.files': '可用文件',
|
||||||
'models.viewin.hf': '在 Hugging Face 中查看',
|
'models.viewin.hf': '在 Hugging Face 中查看',
|
||||||
|
'models.viewin.modelscope': '在 ModelScope 中查看',
|
||||||
'models.architecture': '架构',
|
'models.architecture': '架构',
|
||||||
'models.search.noresult': '未找到相关模型',
|
'models.search.noresult': '未找到相关模型',
|
||||||
'models.search.nofiles': '无可用文件',
|
'models.search.nofiles': '无可用文件',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { downloadFile, listFiles, listModels } from '@huggingface/hub';
|
import { downloadFile, listFiles, listModels } from '@huggingface/hub';
|
||||||
import { PipelineType } from '@huggingface/tasks';
|
import { PipelineType } from '@huggingface/tasks';
|
||||||
import { request } from '@umijs/max';
|
import { request } from '@umijs/max';
|
||||||
|
import qs from 'query-string';
|
||||||
import {
|
import {
|
||||||
FormData,
|
FormData,
|
||||||
GPUListItem,
|
GPUListItem,
|
||||||
@@ -126,6 +127,15 @@ export async function callHuggingfaceQuickSearch(params: any) {
|
|||||||
|
|
||||||
const HUGGINGFACE_API = 'https://huggingface.co/api/models';
|
const HUGGINGFACE_API = 'https://huggingface.co/api/models';
|
||||||
|
|
||||||
|
const MODEL_SCOPE_LIST_MODEL_API =
|
||||||
|
'/proxy?url=https://www.modelscope.cn/api/v1/dolphin/models';
|
||||||
|
|
||||||
|
const MODEL_SCOPE_DETAIL_MODEL_API =
|
||||||
|
'/proxy?url=https://www.modelscope.cn/api/v1/dolphin/models/';
|
||||||
|
|
||||||
|
const MODE_SCOPE_MODEL_FIELS_API =
|
||||||
|
'/proxy?url=https://modelscope.cn/api/v1/models/';
|
||||||
|
|
||||||
export async function queryHuggingfaceModelDetail(
|
export async function queryHuggingfaceModelDetail(
|
||||||
params: { repo: string },
|
params: { repo: string },
|
||||||
options?: any
|
options?: any
|
||||||
@@ -136,10 +146,69 @@ export async function queryHuggingfaceModelDetail(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryModelScopeModels() {
|
export async function queryModelScopeModels(
|
||||||
return request(`https://www.modelscope.cn/api/v1/dolphin/models`, {
|
params: {
|
||||||
method: 'PUT'
|
PageSize?: number;
|
||||||
|
PageNumber?: number;
|
||||||
|
SortBy?: string;
|
||||||
|
Target?: string;
|
||||||
|
SingleCriterion?: any[];
|
||||||
|
Name: string;
|
||||||
|
},
|
||||||
|
config?: any
|
||||||
|
) {
|
||||||
|
const res = await fetch(`${MODEL_SCOPE_LIST_MODEL_API}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
signal: config?.signal,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
...params,
|
||||||
|
Name: `${params.Name} gguf`,
|
||||||
|
PageSize: 100,
|
||||||
|
PageNumber: 1
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function queryModelScopeModelDetail(
|
||||||
|
params: { name: string },
|
||||||
|
options?: any
|
||||||
|
) {
|
||||||
|
return request(`${MODE_SCOPE_MODEL_FIELS_API}${params.name}`, {
|
||||||
|
method: 'GET',
|
||||||
|
cancelToken: options?.token
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function queryModelScopeModelFiles(
|
||||||
|
params: { name: string },
|
||||||
|
options?: any
|
||||||
|
) {
|
||||||
|
const res = await fetch(
|
||||||
|
`${MODE_SCOPE_MODEL_FIELS_API}${params.name}/repo/files?${qs.stringify({
|
||||||
|
Revision: 'master',
|
||||||
|
Root: ''
|
||||||
|
})}`,
|
||||||
|
{
|
||||||
|
method: 'GET',
|
||||||
|
signal: options?.signal,
|
||||||
|
body: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryHuggingfaceModels(
|
export async function queryHuggingfaceModels(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import React, {
|
|||||||
forwardRef,
|
forwardRef,
|
||||||
useEffect,
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
|
useMemo,
|
||||||
useState
|
useState
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { queryGPUList } from '../apis';
|
import { queryGPUList } from '../apis';
|
||||||
@@ -21,7 +22,7 @@ interface DataFormProps {
|
|||||||
ref?: any;
|
ref?: any;
|
||||||
source: string;
|
source: string;
|
||||||
action: PageActionType;
|
action: PageActionType;
|
||||||
repo: string;
|
selectedModel: any;
|
||||||
onOk: (values: FormData) => void;
|
onOk: (values: FormData) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,11 +36,20 @@ const sourceOptions = [
|
|||||||
label: 'Ollama Library',
|
label: 'Ollama Library',
|
||||||
value: modelSourceMap.ollama_library_value,
|
value: modelSourceMap.ollama_library_value,
|
||||||
key: 'ollama_library'
|
key: 'ollama_library'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ModelScope',
|
||||||
|
value: modelSourceMap.modelscope_value,
|
||||||
|
key: 'model_scope'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
const SEARCH_SOURCE = [
|
||||||
|
modelSourceMap.huggingface_value,
|
||||||
|
modelSourceMap.modelscope_value
|
||||||
|
];
|
||||||
|
|
||||||
const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
||||||
const { action, repo, onOk } = props;
|
const { action, onOk } = props;
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [gpuOptions, setGpuOptions] = useState<
|
const [gpuOptions, setGpuOptions] = useState<
|
||||||
@@ -86,22 +96,21 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleOnSelectModel = () => {
|
const handleOnSelectModel = () => {
|
||||||
console.log('repo=============', repo);
|
if (!props.selectedModel.name) {
|
||||||
if (!repo) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let name = _.split(repo, '/').slice(-1)[0];
|
let name = _.split(props.selectedModel.name, '/').slice(-1)[0];
|
||||||
const reg = /(-gguf)$/i;
|
const reg = /(-gguf)$/i;
|
||||||
name = _.toLower(name).replace(reg, '');
|
name = _.toLower(name).replace(reg, '');
|
||||||
|
|
||||||
if (props.source === modelSourceMap.huggingface_value) {
|
if (SEARCH_SOURCE.includes(props.source)) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
huggingface_repo_id: repo,
|
repo_id: props.selectedModel.name,
|
||||||
name: name
|
name: name
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
ollama_library_model_name: repo,
|
ollama_library_model_name: props.selectedModel.name,
|
||||||
name: name
|
name: name
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -111,8 +120,8 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_repo_id"
|
name="repo_id"
|
||||||
key="huggingface_repo_id"
|
key="repo_id"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -132,7 +141,8 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_filename"
|
name="file_name"
|
||||||
|
key="file_name"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -214,18 +224,21 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderFieldsBySource = () => {
|
const renderFieldsBySource = useMemo(() => {
|
||||||
switch (props.source) {
|
if (SEARCH_SOURCE.includes(props.source)) {
|
||||||
case modelSourceMap.huggingface_value:
|
return renderHuggingfaceFields();
|
||||||
return renderHuggingfaceFields();
|
|
||||||
case modelSourceMap.ollama_library_value:
|
|
||||||
return renderOllamaModelFields();
|
|
||||||
case modelSourceMap.s3_value:
|
|
||||||
return renderS3Fields();
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
if (props.source === modelSourceMap.ollama_library_value) {
|
||||||
|
return renderOllamaModelFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.source === modelSourceMap.s3_value) {
|
||||||
|
return renderS3Fields();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [props.source]);
|
||||||
|
|
||||||
const handleOk = (formdata: FormData) => {
|
const handleOk = (formdata: FormData) => {
|
||||||
const gpu = _.find(gpuOptions, (item: any) => {
|
const gpu = _.find(gpuOptions, (item: any) => {
|
||||||
@@ -249,7 +262,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleOnSelectModel();
|
handleOnSelectModel();
|
||||||
}, [repo]);
|
}, [props.selectedModel.name]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
@@ -314,7 +327,7 @@ const DataForm: React.FC<DataFormProps> = forwardRef((props, ref) => {
|
|||||||
></SealSelect>
|
></SealSelect>
|
||||||
}
|
}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{renderFieldsBySource()}
|
{renderFieldsBySource}
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="replicas"
|
name="replicas"
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
@@ -36,18 +36,22 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
action,
|
action,
|
||||||
width = 600
|
width = 600
|
||||||
} = props || {};
|
} = props || {};
|
||||||
|
const SEARCH_SOURCE = [
|
||||||
|
modelSourceMap.huggingface_value,
|
||||||
|
modelSourceMap.modelscope_value
|
||||||
|
];
|
||||||
const form = useRef<any>({});
|
const form = useRef<any>({});
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [huggingfaceRepoId, setHuggingfaceRepoId] = useState<string>('');
|
const [selectedModel, setSelectedModel] = useState<any>({});
|
||||||
const [collapsed, setCollapsed] = useState<boolean>(false);
|
const [collapsed, setCollapsed] = useState<boolean>(false);
|
||||||
const [loadingModel, setLoadingModel] = useState<boolean>(false);
|
const [loadingModel, setLoadingModel] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleSelectModelFile = useCallback((item: any) => {
|
const handleSelectModelFile = useCallback((item: any) => {
|
||||||
form.current?.setFieldValue?.('huggingface_filename', item.fakeName);
|
form.current?.setFieldValue?.('file_name', item.fakeName);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleOnSelectModel = (item: any) => {
|
const handleOnSelectModel = (item: any) => {
|
||||||
setHuggingfaceRepoId(item.name);
|
setSelectedModel(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
@@ -56,7 +60,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
setHuggingfaceRepoId('');
|
setSelectedModel({});
|
||||||
};
|
};
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
@@ -91,41 +95,43 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
overflowX: 'hidden'
|
overflowX: 'hidden'
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
borderRadius: '8px 0 0 8px'
|
borderRadius: '6px 0 0 6px'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
width={width}
|
width={width}
|
||||||
footer={false}
|
footer={false}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
{props.source === modelSourceMap.huggingface_value && (
|
{SEARCH_SOURCE.includes(props.source) && (
|
||||||
<div style={{ display: 'flex', flex: 1 }}>
|
<>
|
||||||
<ColumnWrapper>
|
<div style={{ display: 'flex', flex: 1 }}>
|
||||||
<SearchModel
|
<ColumnWrapper>
|
||||||
modelSource={props.source}
|
<SearchModel
|
||||||
onSelectModel={handleOnSelectModel}
|
modelSource={props.source}
|
||||||
setLoadingModel={setLoadingModel}
|
onSelectModel={handleOnSelectModel}
|
||||||
></SearchModel>
|
setLoadingModel={setLoadingModel}
|
||||||
</ColumnWrapper>
|
></SearchModel>
|
||||||
<Separator></Separator>
|
</ColumnWrapper>
|
||||||
</div>
|
<Separator></Separator>
|
||||||
)}
|
</div>
|
||||||
{props.source === modelSourceMap.huggingface_value && (
|
<div style={{ display: 'flex', flex: 1 }}>
|
||||||
<div style={{ display: 'flex', flex: 1 }}>
|
<ColumnWrapper>
|
||||||
<ColumnWrapper>
|
<ModelCard
|
||||||
<ModelCard
|
selectedModel={selectedModel}
|
||||||
repo={huggingfaceRepoId}
|
onCollapse={setCollapsed}
|
||||||
onCollapse={setCollapsed}
|
collapsed={collapsed}
|
||||||
collapsed={collapsed}
|
modelSource={props.source}
|
||||||
></ModelCard>
|
></ModelCard>
|
||||||
<HFModelFile
|
<HFModelFile
|
||||||
repo={huggingfaceRepoId}
|
selectedModel={selectedModel}
|
||||||
onSelectFile={handleSelectModelFile}
|
modelSource={props.source}
|
||||||
collapsed={collapsed}
|
onSelectFile={handleSelectModelFile}
|
||||||
></HFModelFile>
|
collapsed={collapsed}
|
||||||
</ColumnWrapper>
|
></HFModelFile>
|
||||||
<Separator></Separator>
|
</ColumnWrapper>
|
||||||
</div>
|
<Separator></Separator>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<ColumnWrapper
|
<ColumnWrapper
|
||||||
footer={
|
footer={
|
||||||
@@ -141,7 +147,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
{source === modelSourceMap.huggingface_value && (
|
{SEARCH_SOURCE.includes(source) && (
|
||||||
<TitleWrapper>
|
<TitleWrapper>
|
||||||
{intl.formatMessage({ id: 'models.form.configurations' })}
|
{intl.formatMessage({ id: 'models.form.configurations' })}
|
||||||
<span style={{ display: 'flex', height: 24 }}></span>
|
<span style={{ display: 'flex', height: 24 }}></span>
|
||||||
@@ -150,7 +156,7 @@ const AddModal: React.FC<AddModalProps> = (props) => {
|
|||||||
<DataForm
|
<DataForm
|
||||||
source={source}
|
source={source}
|
||||||
action={action}
|
action={action}
|
||||||
repo={huggingfaceRepoId}
|
selectedModel={selectedModel}
|
||||||
onOk={onOk}
|
onOk={onOk}
|
||||||
ref={form}
|
ref={form}
|
||||||
></DataForm>
|
></DataForm>
|
||||||
|
|||||||
@@ -7,23 +7,25 @@ import _ from 'lodash';
|
|||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } 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 { queryHuggingfaceModelFiles } from '../apis';
|
import { queryHuggingfaceModelFiles, queryModelScopeModelFiles } from '../apis';
|
||||||
|
import { modelSourceMap } from '../config';
|
||||||
import { getFileType } from '../config/file-type';
|
import { getFileType } from '../config/file-type';
|
||||||
import '../style/hf-model-file.less';
|
import '../style/hf-model-file.less';
|
||||||
import FileParts from './file-parts';
|
import FileParts from './file-parts';
|
||||||
import TitleWrapper from './title-wrapper';
|
import TitleWrapper from './title-wrapper';
|
||||||
|
|
||||||
interface HFModelFileProps {
|
interface HFModelFileProps {
|
||||||
repo: string;
|
selectedModel: any;
|
||||||
collapsed?: boolean;
|
collapsed?: boolean;
|
||||||
loadingModel?: boolean;
|
loadingModel?: boolean;
|
||||||
|
modelSource: string;
|
||||||
onSelectFile?: (file: any) => void;
|
onSelectFile?: (file: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pattern = /^(.*)-(\d+)-of-(\d+)\.gguf$/;
|
const pattern = /^(.*)-(\d+)-of-(\d+)\.gguf$/;
|
||||||
|
|
||||||
const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
||||||
const { collapsed, loadingModel } = props;
|
const { collapsed, modelSource } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [dataSource, setDataSource] = useState<any>({
|
const [dataSource, setDataSource] = useState<any>({
|
||||||
fileList: [],
|
fileList: [],
|
||||||
@@ -109,19 +111,11 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
|||||||
return [...shardFileListResult, ...newGeneralFileList];
|
return [...shardFileListResult, ...newGeneralFileList];
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleFetchModelFiles = async () => {
|
// hugging face files
|
||||||
if (!props.repo) {
|
const getHuggingfaceFiles = async () => {
|
||||||
setDataSource({ fileList: [], loading: false });
|
|
||||||
handleSelectModelFile({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
axiosTokenRef.current?.abort?.();
|
|
||||||
axiosTokenRef.current = new AbortController();
|
|
||||||
setDataSource({ ...dataSource, loading: true });
|
|
||||||
setCurrent('');
|
|
||||||
try {
|
try {
|
||||||
const res = await queryHuggingfaceModelFiles(
|
const res = await queryHuggingfaceModelFiles(
|
||||||
{ repo: props.repo },
|
{ repo: props.selectedModel.name || '' },
|
||||||
{
|
{
|
||||||
signal: axiosTokenRef.current.signal
|
signal: axiosTokenRef.current.signal
|
||||||
}
|
}
|
||||||
@@ -133,6 +127,55 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
|||||||
const list = _.filter(fileList, (file: any) => {
|
const list = _.filter(fileList, (file: any) => {
|
||||||
return _.endsWith(file.path, '.gguf') || _.includes(file.path, '.gguf');
|
return _.endsWith(file.path, '.gguf') || _.includes(file.path, '.gguf');
|
||||||
});
|
});
|
||||||
|
return list;
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// modelscope files
|
||||||
|
const getModelScopeFiles = async () => {
|
||||||
|
try {
|
||||||
|
const data = await queryModelScopeModelFiles(
|
||||||
|
{
|
||||||
|
name: props.selectedModel.name || ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
signal: axiosTokenRef.current.signal
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const fileList = _.filter(_.get(data, ['Data', 'Files']), (file: any) => {
|
||||||
|
return _.endsWith(file.Path, '.gguf') || _.includes(file.Path, '.gguf');
|
||||||
|
});
|
||||||
|
const list = _.map(fileList, (item: any) => {
|
||||||
|
return {
|
||||||
|
path: item.Path,
|
||||||
|
size: item.Size
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFetchModelFiles = async () => {
|
||||||
|
if (!props.selectedModel.name) {
|
||||||
|
setDataSource({ fileList: [], loading: false });
|
||||||
|
handleSelectModelFile({});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
axiosTokenRef.current?.abort?.();
|
||||||
|
axiosTokenRef.current = new AbortController();
|
||||||
|
setDataSource({ ...dataSource, loading: true });
|
||||||
|
setCurrent('');
|
||||||
|
try {
|
||||||
|
let list = [];
|
||||||
|
if (modelSourceMap.huggingface_value === modelSource) {
|
||||||
|
list = await getHuggingfaceFiles();
|
||||||
|
} else if (modelSourceMap.modelscope_value === modelSource) {
|
||||||
|
list = await getModelScopeFiles();
|
||||||
|
}
|
||||||
|
|
||||||
const newList = generateGroupByFilename(list);
|
const newList = generateGroupByFilename(list);
|
||||||
const sortList = _.sortBy(newList, (item: any) => {
|
const sortList = _.sortBy(newList, (item: any) => {
|
||||||
@@ -186,7 +229,7 @@ const HFModelFile: React.FC<HFModelFileProps> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleFetchModelFiles();
|
handleFetchModelFiles();
|
||||||
}, [props.repo]);
|
}, [props.selectedModel.name]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ interface HFModelItemProps {
|
|||||||
}
|
}
|
||||||
const warningTask = ['image', 'audio', 'video'];
|
const warningTask = ['image', 'audio', 'video'];
|
||||||
|
|
||||||
|
const SUPPORTEDSOURCE = [
|
||||||
|
modelSourceMap.huggingface_value,
|
||||||
|
modelSourceMap.modelscope_value
|
||||||
|
];
|
||||||
|
|
||||||
const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const isExcludeTask = () => {
|
const isExcludeTask = () => {
|
||||||
@@ -57,7 +62,7 @@ const HFModelItem: React.FC<HFModelItemProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="info">
|
<div className="info">
|
||||||
{props.source === modelSourceMap.huggingface_value ? (
|
{SUPPORTEDSOURCE.includes(props.source || '') ? (
|
||||||
<div className="info-item">
|
<div className="info-item">
|
||||||
{/* {props.task && (
|
{/* {props.task && (
|
||||||
<Tag
|
<Tag
|
||||||
|
|||||||
@@ -11,17 +11,23 @@ import { Button, Empty, Tag, Tooltip } from 'antd';
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } 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 { downloadModelFile, queryHuggingfaceModelDetail } from '../apis';
|
import {
|
||||||
|
downloadModelFile,
|
||||||
|
queryHuggingfaceModelDetail,
|
||||||
|
queryModelScopeModelDetail
|
||||||
|
} from '../apis';
|
||||||
|
import { modelSourceMap } from '../config';
|
||||||
import '../style/model-card.less';
|
import '../style/model-card.less';
|
||||||
import TitleWrapper from './title-wrapper';
|
import TitleWrapper from './title-wrapper';
|
||||||
|
|
||||||
const ModelCard: React.FC<{
|
const ModelCard: React.FC<{
|
||||||
repo: string;
|
selectedModel: any;
|
||||||
onCollapse: (flag: boolean) => void;
|
onCollapse: (flag: boolean) => void;
|
||||||
collapsed: boolean;
|
collapsed: boolean;
|
||||||
loadingModel?: boolean;
|
loadingModel?: boolean;
|
||||||
|
modelSource: string;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const { repo, onCollapse, collapsed, loadingModel } = props;
|
const { onCollapse, collapsed, modelSource } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const requestSource = useRequestToken();
|
const requestSource = useRequestToken();
|
||||||
const [modelData, setModelData] = useState<any>({});
|
const [modelData, setModelData] = useState<any>({});
|
||||||
@@ -49,28 +55,60 @@ const ModelCard: React.FC<{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getModelCardData = async () => {
|
// huggingface model card data
|
||||||
if (!repo) {
|
const getHuggingfaceModelDetail = async () => {
|
||||||
setModelData(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
requestToken.current?.cancel?.();
|
|
||||||
requestToken.current = requestSource();
|
|
||||||
try {
|
try {
|
||||||
const [modelcard, readme] = await Promise.all([
|
const [modelcard, readme] = await Promise.all([
|
||||||
queryHuggingfaceModelDetail(
|
queryHuggingfaceModelDetail(
|
||||||
{ repo },
|
{ repo: props.selectedModel.name },
|
||||||
{
|
{
|
||||||
token: requestToken.current.token
|
token: requestToken.current.token
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
loadFile(repo, 'main')
|
loadFile(props.selectedModel.name, 'main')
|
||||||
]);
|
]);
|
||||||
|
|
||||||
setModelData(modelcard);
|
setModelData(modelcard);
|
||||||
setReadmeText(readme);
|
setReadmeText(readme);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setModelData({});
|
setModelData({});
|
||||||
|
setReadmeText(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModelScopeModelDetail = async () => {
|
||||||
|
try {
|
||||||
|
const data = await queryModelScopeModelDetail(
|
||||||
|
{
|
||||||
|
name: props.selectedModel.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
token: requestToken.current.token
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log('detaildata==========', data);
|
||||||
|
setModelData({
|
||||||
|
...data?.Data,
|
||||||
|
name: data?.Data?.Name
|
||||||
|
});
|
||||||
|
setReadmeText(data?.Data?.ReadMeContent);
|
||||||
|
} catch (error) {
|
||||||
|
setModelData({});
|
||||||
|
setReadmeText(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModelCardData = async () => {
|
||||||
|
if (!props.selectedModel.name) {
|
||||||
|
setModelData(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requestToken.current?.cancel?.();
|
||||||
|
requestToken.current = requestSource();
|
||||||
|
if (modelSource === modelSourceMap.huggingface_value) {
|
||||||
|
getHuggingfaceModelDetail();
|
||||||
|
} else if (modelSource === modelSourceMap.modelscope_value) {
|
||||||
|
getModelScopeModelDetail();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,9 +116,46 @@ const ModelCard: React.FC<{
|
|||||||
onCollapse(!collapsed);
|
onCollapse(!collapsed);
|
||||||
}, [collapsed]);
|
}, [collapsed]);
|
||||||
|
|
||||||
|
const generateModelLink = () => {
|
||||||
|
const name = modelData?.id || modelData?.name;
|
||||||
|
if (!name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (modelSource === modelSourceMap.huggingface_value) {
|
||||||
|
return (
|
||||||
|
<Tooltip title={intl.formatMessage({ id: 'models.viewin.hf' })}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
target="_blank"
|
||||||
|
href={`https://huggingface.co/${modelData.id}`}
|
||||||
|
>
|
||||||
|
<IconFont type="icon-external-link"></IconFont>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modelSource === modelSourceMap.modelscope_value) {
|
||||||
|
return (
|
||||||
|
<Tooltip title={intl.formatMessage({ id: 'models.viewin.modelscope' })}>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
type="link"
|
||||||
|
target="_blank"
|
||||||
|
href={`https://modelscope.cn/models/${modelData?.Path}/${modelData.name}`}
|
||||||
|
>
|
||||||
|
<IconFont type="icon-external-link"></IconFont>
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getModelCardData();
|
getModelCardData();
|
||||||
}, [repo]);
|
}, [props.selectedModel.name]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!readmeText) {
|
if (!readmeText) {
|
||||||
@@ -98,19 +173,8 @@ const ModelCard: React.FC<{
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TitleWrapper>
|
<TitleWrapper>
|
||||||
<div className="title">{modelData?.id} </div>
|
<div className="title">{modelData?.id || modelData?.name} </div>
|
||||||
{modelData?.id && (
|
{generateModelLink()}
|
||||||
<Tooltip title={intl.formatMessage({ id: 'models.viewin.hf' })}>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
type="link"
|
|
||||||
target="_blank"
|
|
||||||
href={`https://huggingface.co/${modelData.id}`}
|
|
||||||
>
|
|
||||||
<IconFont type="icon-external-link"></IconFont>
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
</TitleWrapper>
|
</TitleWrapper>
|
||||||
<div className="card-wrapper">
|
<div className="card-wrapper">
|
||||||
{modelData ? (
|
{modelData ? (
|
||||||
|
|||||||
@@ -1,41 +1,51 @@
|
|||||||
|
import IconFont from '@/components/icon-font';
|
||||||
import hotkeys from '@/config/hotkeys';
|
import hotkeys from '@/config/hotkeys';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Input } from 'antd';
|
import { Input } from 'antd';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import { modelSourceMap, modelSourceValueMap } from '../config';
|
||||||
|
|
||||||
const SearchInput: React.FC<{
|
const SearchInput: React.FC<{
|
||||||
|
modelSource: string;
|
||||||
onSearch: (e: any) => void;
|
onSearch: (e: any) => void;
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
const { onSearch } = props;
|
const { onSearch, modelSource } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [isFocus, setIsFocus] = useState(false);
|
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
|
|
||||||
useHotkeys(hotkeys.INPUT.join(','), () => {
|
useHotkeys(hotkeys.FOCUS, (e: any) => {
|
||||||
|
e.preventDefault();
|
||||||
inputRef.current?.focus?.();
|
inputRef.current?.focus?.();
|
||||||
setIsFocus(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Input
|
<Input
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
onPressEnter={onSearch}
|
onPressEnter={onSearch}
|
||||||
onFocus={() => setIsFocus(true)}
|
|
||||||
onBlur={() => setIsFocus(false)}
|
|
||||||
allowClear
|
allowClear
|
||||||
placeholder={intl.formatMessage({
|
placeholder={intl.formatMessage(
|
||||||
id: 'model.deploy.search.placeholder'
|
{
|
||||||
})}
|
id: 'model.deploy.search.placeholder'
|
||||||
|
},
|
||||||
|
{ source: modelSourceValueMap[modelSource] }
|
||||||
|
)}
|
||||||
prefix={
|
prefix={
|
||||||
<>
|
<>
|
||||||
<SearchOutlined
|
{/* <SearchOutlined
|
||||||
style={{
|
style={{
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
color: 'var(--ant-color-text-quaternary)'
|
color: 'var(--ant-color-text-quaternary)'
|
||||||
}}
|
}}
|
||||||
/>
|
/> */}
|
||||||
|
<IconFont
|
||||||
|
className="font-size-16"
|
||||||
|
type={
|
||||||
|
modelSource === modelSourceMap.huggingface_value
|
||||||
|
? 'icon-huggingface'
|
||||||
|
: 'icon-tu2'
|
||||||
|
}
|
||||||
|
></IconFont>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
></Input>
|
></Input>
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
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 { 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, queryModelScopeModels } from '../apis';
|
||||||
import { ModelSortType, modelSourceMap, ollamaModelOptions } from '../config';
|
import {
|
||||||
|
ModelScopeSortType,
|
||||||
|
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';
|
||||||
@@ -31,10 +36,13 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
networkError: false,
|
networkError: false,
|
||||||
sortType: ModelSortType.trendingScore
|
sortType: ModelSortType.trendingScore
|
||||||
});
|
});
|
||||||
|
const SUPPORTEDSOURCE = [
|
||||||
|
modelSourceMap.huggingface_value,
|
||||||
|
modelSourceMap.modelscope_value
|
||||||
|
];
|
||||||
const [current, setCurrent] = useState<string>('');
|
const [current, setCurrent] = useState<string>('');
|
||||||
const cacheRepoOptions = useRef<any[]>([]);
|
const cacheRepoOptions = useRef<any[]>([]);
|
||||||
const axiosTokenRef = useRef<any>(null);
|
const axiosTokenRef = useRef<any>(null);
|
||||||
const customOllamaModelRef = useRef<any>(null);
|
|
||||||
const searchInputRef = useRef<any>('');
|
const searchInputRef = useRef<any>('');
|
||||||
const modelFilesSortOptions = useRef<any[]>([
|
const modelFilesSortOptions = useRef<any[]>([
|
||||||
{
|
{
|
||||||
@@ -56,16 +64,74 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
const handleOnSelectModel = useCallback((item: any) => {
|
const handleOnSelectModel = useCallback((item: any) => {
|
||||||
|
console.log('handleOnSelectModel', item);
|
||||||
onSelectModel(item);
|
onSelectModel(item);
|
||||||
setCurrent(item.id);
|
setCurrent(item.id);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// huggeface
|
||||||
|
const getModelsFromHuggingface = useCallback(async (sort: string) => {
|
||||||
|
try {
|
||||||
|
const task: any = searchInputRef.current ? '' : 'text-generation';
|
||||||
|
const params = {
|
||||||
|
search: {
|
||||||
|
query: searchInputRef.current || '',
|
||||||
|
sort: sort,
|
||||||
|
tags: ['gguf'],
|
||||||
|
task
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const data = await queryHuggingfaceModels(params, {
|
||||||
|
signal: axiosTokenRef.current.signal
|
||||||
|
});
|
||||||
|
let list = _.map(data || [], (item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
value: item.name,
|
||||||
|
label: item.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// modelscope
|
||||||
|
const getModelsFromModelscope = useCallback(async (sort: string) => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
Name: searchInputRef.current || '',
|
||||||
|
SortBy: ModelScopeSortType[sort]
|
||||||
|
};
|
||||||
|
const data = await queryModelScopeModels(params, {
|
||||||
|
signal: axiosTokenRef.current.signal
|
||||||
|
});
|
||||||
|
let list = _.map(_.get(data, 'Data.Model.Models') || [], (item: any) => {
|
||||||
|
return {
|
||||||
|
path: item.Path,
|
||||||
|
name: `${item.Path}/${item.Name}`,
|
||||||
|
downloads: item.Downloads,
|
||||||
|
id: item.Name,
|
||||||
|
updatedAt: item.LastUpdatedTime * 1000,
|
||||||
|
likes: item.Stars,
|
||||||
|
value: item.Name,
|
||||||
|
label: item.Name,
|
||||||
|
task: item.Tasks?.map((sItem: any) => sItem.Name).join(',')
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
} catch (error) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleOnSearchRepo = useCallback(
|
const handleOnSearchRepo = useCallback(
|
||||||
async (sortType?: string) => {
|
async (sortType?: string) => {
|
||||||
if (modelSource === modelSourceMap.ollama_library_value) {
|
if (!SUPPORTEDSOURCE.includes(modelSource)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('handleOnSearchRepo', dataSource.loading);
|
|
||||||
axiosTokenRef.current?.abort?.();
|
axiosTokenRef.current?.abort?.();
|
||||||
axiosTokenRef.current = new AbortController();
|
axiosTokenRef.current = new AbortController();
|
||||||
if (dataSource.loading) return;
|
if (dataSource.loading) return;
|
||||||
@@ -77,26 +143,12 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
});
|
});
|
||||||
setLoadingModel?.(true);
|
setLoadingModel?.(true);
|
||||||
cacheRepoOptions.current = [];
|
cacheRepoOptions.current = [];
|
||||||
const task: any = searchInputRef.current ? '' : 'text-generation';
|
let list: any[] = [];
|
||||||
const params = {
|
if (modelSource === modelSourceMap.huggingface_value) {
|
||||||
search: {
|
list = await getModelsFromHuggingface(sort);
|
||||||
query: searchInputRef.current || '',
|
} else if (modelSource === modelSourceMap.modelscope_value) {
|
||||||
sort: sort,
|
list = await getModelsFromModelscope(sort);
|
||||||
tags: ['gguf'],
|
}
|
||||||
task
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const models = await queryHuggingfaceModels(params, {
|
|
||||||
signal: axiosTokenRef.current.signal
|
|
||||||
});
|
|
||||||
let list = _.map(models || [], (item: any) => {
|
|
||||||
return {
|
|
||||||
...item,
|
|
||||||
value: item.name,
|
|
||||||
label: item.name
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
cacheRepoOptions.current = list;
|
cacheRepoOptions.current = list;
|
||||||
setDataSource({
|
setDataSource({
|
||||||
repoOptions: list,
|
repoOptions: list,
|
||||||
@@ -133,7 +185,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
if (
|
if (
|
||||||
!dataSource.repoOptions.length &&
|
!dataSource.repoOptions.length &&
|
||||||
!cacheRepoOptions.current.length &&
|
!cacheRepoOptions.current.length &&
|
||||||
modelSource === modelSourceMap.huggingface_value
|
SUPPORTEDSOURCE.includes(modelSource)
|
||||||
) {
|
) {
|
||||||
handleOnSearchRepo();
|
handleOnSearchRepo();
|
||||||
}
|
}
|
||||||
@@ -149,51 +201,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFilterModels = (e: any) => {
|
|
||||||
const text = e.target.value;
|
|
||||||
const list = _.filter(cacheRepoOptions.current, (item: any) => {
|
|
||||||
return item.name.includes(text);
|
|
||||||
});
|
|
||||||
setDataSource({
|
|
||||||
repoOptions: list,
|
|
||||||
loading: false,
|
|
||||||
networkError: false,
|
|
||||||
sortType: dataSource.sortType
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const debounceFilter = _.debounce((e: any) => {
|
|
||||||
handleFilterModels(e);
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
const handleSourceChange = (source: string) => {
|
|
||||||
axiosTokenRef.current?.abort?.();
|
|
||||||
onSourceChange?.(source);
|
|
||||||
setDataSource({
|
|
||||||
repoOptions: [],
|
|
||||||
loading: false,
|
|
||||||
networkError: false,
|
|
||||||
sortType: dataSource.sortType
|
|
||||||
});
|
|
||||||
cacheRepoOptions.current = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInputChange = (e: any) => {
|
|
||||||
const value = e.target.value;
|
|
||||||
customOllamaModelRef.current = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleConfirm = () => {
|
|
||||||
const model = {
|
|
||||||
label: customOllamaModelRef.current,
|
|
||||||
value: customOllamaModelRef.current,
|
|
||||||
name: customOllamaModelRef.current,
|
|
||||||
id: ''
|
|
||||||
};
|
|
||||||
onSelectModel(model);
|
|
||||||
setCurrent('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSortChange = (value: string) => {
|
const handleSortChange = (value: string) => {
|
||||||
handleOnSearchRepo(value || '');
|
handleOnSearchRepo(value || '');
|
||||||
};
|
};
|
||||||
@@ -201,7 +208,10 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
const renderHFSearch = () => {
|
const renderHFSearch = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchInput onSearch={handlerSearchModels}></SearchInput>
|
<SearchInput
|
||||||
|
onSearch={handlerSearchModels}
|
||||||
|
modelSource={modelSource}
|
||||||
|
></SearchInput>
|
||||||
<div className={SearchStyle.filter}>
|
<div className={SearchStyle.filter}>
|
||||||
<span>
|
<span>
|
||||||
<span className="value">
|
<span className="value">
|
||||||
@@ -231,23 +241,6 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderOllamaCustom = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Input
|
|
||||||
allowClear
|
|
||||||
placeholder="Input ollama model name"
|
|
||||||
onChange={handleInputChange}
|
|
||||||
></Input>
|
|
||||||
<div className={SearchStyle.filter}>
|
|
||||||
<Button type="primary" onClick={handleConfirm}>
|
|
||||||
{intl.formatMessage({ id: 'common.button.confirm' })}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleOnOpen();
|
handleOnOpen();
|
||||||
console.log('SearchModel useEffect', modelSource);
|
console.log('SearchModel useEffect', modelSource);
|
||||||
@@ -262,7 +255,7 @@ const SearchModel: React.FC<SearchInputProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<div className={SearchStyle['search-bar']}>
|
<div className={SearchStyle['search-bar']}>
|
||||||
{modelSource === modelSourceMap.huggingface_value ? (
|
{SUPPORTEDSOURCE.includes(modelSource) ? (
|
||||||
renderHFSearch()
|
renderHFSearch()
|
||||||
) : (
|
) : (
|
||||||
<div style={{ lineHeight: '18px' }}>
|
<div style={{ lineHeight: '18px' }}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Col, Empty, Row, Spin } from 'antd';
|
import { 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';
|
||||||
@@ -53,7 +53,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({ id: 'models.search.networkerror' })}
|
{intl.formatMessage({ id: 'models.search.networkerror' })}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
{/* <span>
|
||||||
<span>
|
<span>
|
||||||
{intl.formatMessage({ id: 'models.search.hfvisit' })}
|
{intl.formatMessage({ id: 'models.search.hfvisit' })}
|
||||||
</span>
|
</span>
|
||||||
@@ -65,7 +65,7 @@ const SearchResult: React.FC<SearchResultProps> = (props) => {
|
|||||||
>
|
>
|
||||||
Hugging Face
|
Hugging Face
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span> */}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import {
|
|||||||
queryModelInstancesList,
|
queryModelInstancesList,
|
||||||
updateModel
|
updateModel
|
||||||
} from '../apis';
|
} from '../apis';
|
||||||
import { modelSourceMap } from '../config';
|
import { getSourceRepoConfigValue, modelSourceMap } from '../config';
|
||||||
import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
|
import { FormData, ListItem, ModelInstanceListItem } from '../config/types';
|
||||||
import DeployModal from './deploy-modal';
|
import DeployModal from './deploy-modal';
|
||||||
import InstanceItem from './instance-item';
|
import InstanceItem from './instance-item';
|
||||||
@@ -95,9 +95,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
source: modelSourceMap.huggingface_value
|
source: modelSourceMap.huggingface_value
|
||||||
});
|
});
|
||||||
const [title, setTitle] = useState<string>('');
|
const [title, setTitle] = useState<string>('');
|
||||||
const [currentData, setCurrentData] = useState<ListItem | undefined>(
|
const [currentData, setCurrentData] = useState<ListItem>({} as ListItem);
|
||||||
undefined
|
|
||||||
);
|
|
||||||
const [currentInstanceUrl, setCurrentInstanceUrl] = useState<string>('');
|
const [currentInstanceUrl, setCurrentInstanceUrl] = useState<string>('');
|
||||||
const modalRef = useRef<any>(null);
|
const modalRef = useRef<any>(null);
|
||||||
|
|
||||||
@@ -116,6 +114,21 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.NEW3.join(','),
|
||||||
|
() => {
|
||||||
|
setOpenDeployModal({
|
||||||
|
show: true,
|
||||||
|
width: 'calc(100vw - 220px)',
|
||||||
|
source: modelSourceMap.modelscope_value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
preventDefault: true,
|
||||||
|
enabled: !openAddModal && !openDeployModal.show && !openLogModal
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
HotKeys.NEW2.join(','),
|
HotKeys.NEW2.join(','),
|
||||||
() => {
|
() => {
|
||||||
@@ -159,6 +172,19 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ModelScope',
|
||||||
|
value: modelSourceMap.modelscope_value,
|
||||||
|
key: 'modelscope',
|
||||||
|
icon: <IconFont type="icon-tu2"></IconFont>,
|
||||||
|
onClick: (e: any) => {
|
||||||
|
setOpenDeployModal({
|
||||||
|
show: true,
|
||||||
|
width: 'calc(100vw - 220px)',
|
||||||
|
source: modelSourceMap.modelscope_value
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -222,9 +248,12 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
const handleModalOk = useCallback(
|
const handleModalOk = useCallback(
|
||||||
async (data: FormData) => {
|
async (data: FormData) => {
|
||||||
try {
|
try {
|
||||||
|
console.log('data:', data, openDeployModal);
|
||||||
|
const result = getSourceRepoConfigValue(currentData?.source, data);
|
||||||
await updateModel({
|
await updateModel({
|
||||||
data: {
|
data: {
|
||||||
...data
|
...result.values,
|
||||||
|
..._.omit(data, result.omits)
|
||||||
},
|
},
|
||||||
id: currentData?.id as number
|
id: currentData?.id as number
|
||||||
});
|
});
|
||||||
@@ -252,7 +281,14 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
try {
|
try {
|
||||||
console.log('data:', data, openDeployModal);
|
console.log('data:', data, openDeployModal);
|
||||||
|
|
||||||
await createModel({ data });
|
const result = getSourceRepoConfigValue(openDeployModal.source, data);
|
||||||
|
|
||||||
|
await createModel({
|
||||||
|
data: {
|
||||||
|
...result.values,
|
||||||
|
..._.omit(data, result.omits)
|
||||||
|
}
|
||||||
|
});
|
||||||
setOpenDeployModal({
|
setOpenDeployModal({
|
||||||
...openDeployModal,
|
...openDeployModal,
|
||||||
show: false
|
show: false
|
||||||
@@ -380,6 +416,16 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
[workerList]
|
[workerList]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const generateSource = useCallback((record: ListItem) => {
|
||||||
|
if (record.source === modelSourceMap.modelscope_value) {
|
||||||
|
return `${modelSourceMap.modelScope} / ${record.model_scope_file_path}`;
|
||||||
|
}
|
||||||
|
if (record.source === modelSourceMap.huggingface_value) {
|
||||||
|
return `${modelSourceMap.huggingface} / ${record.huggingface_filename}`;
|
||||||
|
}
|
||||||
|
return `${modelSourceMap.ollama_library} / ${record.ollama_library_model_name}`;
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleCloseViewCode = useCallback(() => {
|
const handleCloseViewCode = useCallback(() => {
|
||||||
setEmbeddingParams({
|
setEmbeddingParams({
|
||||||
params: {},
|
params: {},
|
||||||
@@ -493,11 +539,7 @@ const Models: React.FC<ModelsProps> = ({
|
|||||||
render={(text, record: ListItem) => {
|
render={(text, record: ListItem) => {
|
||||||
return (
|
return (
|
||||||
<span className="flex flex-column">
|
<span className="flex flex-column">
|
||||||
<span>
|
<span>{generateSource(record)}</span>
|
||||||
{record.source === modelSourceMap.huggingface_value
|
|
||||||
? `${modelSourceMap.huggingface} / ${record.huggingface_filename}`
|
|
||||||
: `${modelSourceMap.ollama_library} / ${record.ollama_library_model_name}`}
|
|
||||||
</span>
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import { convertFileSize } from '@/utils';
|
|||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form, Modal } from 'antd';
|
import { Form, Modal } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useEffect, useState } from 'react';
|
import { memo, useEffect, useMemo, useState } 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 { queryGPUList, queryHuggingfaceModelFiles } from '../apis';
|
import { queryGPUList, queryHuggingfaceModelFiles } from '../apis';
|
||||||
import { modelSourceMap } from '../config';
|
import { modelSourceMap, setSourceRepoConfigValue } from '../config';
|
||||||
import { FormData, GPUListItem, ListItem } from '../config/types';
|
import { FormData, GPUListItem, ListItem } from '../config/types';
|
||||||
import AdvanceConfig from './advance-config';
|
import AdvanceConfig from './advance-config';
|
||||||
|
|
||||||
@@ -35,9 +35,19 @@ const sourceOptions = [
|
|||||||
label: 'Ollama Library',
|
label: 'Ollama Library',
|
||||||
value: modelSourceMap.ollama_library_value,
|
value: modelSourceMap.ollama_library_value,
|
||||||
key: 'ollama_library'
|
key: 'ollama_library'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ModelScope',
|
||||||
|
value: modelSourceMap.modelscope_value,
|
||||||
|
key: 'model_scope'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const SEARCH_SOURCE = [
|
||||||
|
modelSourceMap.huggingface_value,
|
||||||
|
modelSourceMap.modelscope_value
|
||||||
|
];
|
||||||
|
|
||||||
const UpdateModal: React.FC<AddModalProps> = (props) => {
|
const UpdateModal: React.FC<AddModalProps> = (props) => {
|
||||||
console.log('addmodel====');
|
console.log('addmodel====');
|
||||||
const { title, action, open, onOk, onCancel } = props || {};
|
const { title, action, open, onOk, onCancel } = props || {};
|
||||||
@@ -70,8 +80,13 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (action === PageAction.EDIT && open) {
|
if (action === PageAction.EDIT && open) {
|
||||||
|
const result = setSourceRepoConfigValue(
|
||||||
|
props.data?.source || '',
|
||||||
|
props.data
|
||||||
|
);
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...props.data,
|
...result.values,
|
||||||
|
..._.omit(props.data, result.omits),
|
||||||
scheduleType: props.data?.gpu_selector ? 'manual' : 'auto',
|
scheduleType: props.data?.gpu_selector ? 'manual' : 'auto',
|
||||||
gpu_selector: props.data?.gpu_selector
|
gpu_selector: props.data?.gpu_selector
|
||||||
? `${props.data?.gpu_selector.worker_name}-${props.data?.gpu_selector.gpu_name}-${props.data?.gpu_selector.gpu_index}`
|
? `${props.data?.gpu_selector.worker_name}-${props.data?.gpu_selector.gpu_name}-${props.data?.gpu_selector.gpu_index}`
|
||||||
@@ -118,7 +133,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRepoOnBlur = (e: any) => {
|
const handleRepoOnBlur = (e: any) => {
|
||||||
const repo = form.getFieldValue('huggingface_repo_id');
|
const repo = form.getFieldValue('repo_id');
|
||||||
handleFetchModelFiles(repo);
|
handleFetchModelFiles(repo);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,7 +141,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_repo_id"
|
name="repo_id"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -146,7 +161,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
></SealInput.Input>
|
></SealInput.Input>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="huggingface_filename"
|
name="file_name"
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -165,7 +180,6 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
required
|
required
|
||||||
options={fileOptions}
|
options={fileOptions}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onFocus={handleRepoOnBlur}
|
|
||||||
disabled={action === PageAction.EDIT}
|
disabled={action === PageAction.EDIT}
|
||||||
></SealAutoComplete>
|
></SealAutoComplete>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -229,18 +243,21 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderFieldsBySource = () => {
|
const renderFieldsBySource = useMemo(() => {
|
||||||
switch (modelSource) {
|
if (SEARCH_SOURCE.includes(props.data?.source || '')) {
|
||||||
case modelSourceMap.huggingface_value:
|
return renderHuggingfaceFields();
|
||||||
return renderHuggingfaceFields();
|
|
||||||
case modelSourceMap.ollama_library_value:
|
|
||||||
return renderOllamaModelFields();
|
|
||||||
case modelSourceMap.s3_value:
|
|
||||||
return renderS3Fields();
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
if (props.data?.source === modelSourceMap.ollama_library_value) {
|
||||||
|
return renderOllamaModelFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.data?.source === modelSourceMap.s3_value) {
|
||||||
|
return renderS3Fields();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [props.data?.source]);
|
||||||
|
|
||||||
const handleSumit = () => {
|
const handleSumit = () => {
|
||||||
form.submit();
|
form.submit();
|
||||||
@@ -367,7 +384,7 @@ const UpdateModal: React.FC<AddModalProps> = (props) => {
|
|||||||
></SealSelect>
|
></SealSelect>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{renderFieldsBySource()}
|
{renderFieldsBySource}
|
||||||
<Form.Item<FormData>
|
<Form.Item<FormData>
|
||||||
name="replicas"
|
name="replicas"
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
@@ -87,7 +87,16 @@ export const modelSourceMap: Record<string, string> = {
|
|||||||
s3: 'S3',
|
s3: 'S3',
|
||||||
huggingface_value: 'huggingface',
|
huggingface_value: 'huggingface',
|
||||||
ollama_library_value: 'ollama_library',
|
ollama_library_value: 'ollama_library',
|
||||||
s3_value: 's3'
|
s3_value: 's3',
|
||||||
|
modelScope: 'ModelScope',
|
||||||
|
modelscope_value: 'model_scope'
|
||||||
|
};
|
||||||
|
|
||||||
|
export const modelSourceValueMap = {
|
||||||
|
[modelSourceMap.huggingface_value]: modelSourceMap.huggingface,
|
||||||
|
[modelSourceMap.ollama_library_value]: modelSourceMap.ollama_library,
|
||||||
|
[modelSourceMap.s3_value]: modelSourceMap.s3,
|
||||||
|
[modelSourceMap.modelscope_value]: modelSourceMap.modelScope
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InstanceStatusMap = {
|
export const InstanceStatusMap = {
|
||||||
@@ -148,6 +157,13 @@ export const ModelSortType = {
|
|||||||
lastModified: 'lastModified'
|
lastModified: 'lastModified'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ModelScopeSortType = {
|
||||||
|
[ModelSortType.trendingScore]: 'Default',
|
||||||
|
[ModelSortType.likes]: 'StarsCount',
|
||||||
|
[ModelSortType.downloads]: 'DownloadsCount',
|
||||||
|
[ModelSortType.lastModified]: 'GmtModified'
|
||||||
|
};
|
||||||
|
|
||||||
export const placementStrategyOptions = [
|
export const placementStrategyOptions = [
|
||||||
{
|
{
|
||||||
label: 'Spread',
|
label: 'Spread',
|
||||||
@@ -158,3 +174,61 @@ export const placementStrategyOptions = [
|
|||||||
value: 'binpack'
|
value: 'binpack'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const sourceRepoConfig = {
|
||||||
|
[modelSourceMap.huggingface_value]: {
|
||||||
|
repo_id: 'huggingface_repo_id',
|
||||||
|
file_name: 'huggingface_filename'
|
||||||
|
},
|
||||||
|
|
||||||
|
[modelSourceMap.modelscope_value]: {
|
||||||
|
repo_id: 'model_scope_model_id',
|
||||||
|
file_name: 'model_scope_file_path'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSourceRepoConfigValue = (
|
||||||
|
source: string,
|
||||||
|
data: any
|
||||||
|
): {
|
||||||
|
values: Record<string, any>;
|
||||||
|
omits: string[];
|
||||||
|
} => {
|
||||||
|
const config: Record<string, any> = sourceRepoConfig[source] || {};
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
const omits: string[] = [];
|
||||||
|
Object.keys(config)?.forEach((key: string) => {
|
||||||
|
if (config[key]) {
|
||||||
|
result[config[key]] = data[key];
|
||||||
|
omits.push(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: result,
|
||||||
|
omits: omits
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setSourceRepoConfigValue = (
|
||||||
|
source: string,
|
||||||
|
data: any
|
||||||
|
): {
|
||||||
|
values: Record<string, any>;
|
||||||
|
omits: string[];
|
||||||
|
} => {
|
||||||
|
const config: Record<string, any> = sourceRepoConfig[source] || {};
|
||||||
|
const result: Record<string, any> = {};
|
||||||
|
const omits: string[] = [];
|
||||||
|
Object.keys(config)?.forEach((key: string) => {
|
||||||
|
if (config[key]) {
|
||||||
|
result[key] = data[config[key]];
|
||||||
|
omits.push(config[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
values: result,
|
||||||
|
omits: omits
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ export interface ListItem {
|
|||||||
huggingface_file_name: string;
|
huggingface_file_name: string;
|
||||||
huggingface_filename: string;
|
huggingface_filename: string;
|
||||||
ollama_library_model_name: string;
|
ollama_library_model_name: string;
|
||||||
|
model_scope_file_path: string;
|
||||||
|
model_scope_model_id: string;
|
||||||
embedding_only?: boolean;
|
embedding_only?: boolean;
|
||||||
ready_replicas: number;
|
ready_replicas: number;
|
||||||
replicas: number;
|
replicas: number;
|
||||||
@@ -23,11 +25,15 @@ export interface ListItem {
|
|||||||
|
|
||||||
export interface FormData {
|
export interface FormData {
|
||||||
source: string;
|
source: string;
|
||||||
|
repo_id: string;
|
||||||
|
file_name: string;
|
||||||
huggingface_repo_id: string;
|
huggingface_repo_id: string;
|
||||||
huggingface_filename: string;
|
huggingface_filename: string;
|
||||||
s3_address: string;
|
s3_address: string;
|
||||||
ollama_library_model_name: 'string';
|
ollama_library_model_name: 'string';
|
||||||
distributed_inference_across_workers?: boolean;
|
distributed_inference_across_workers?: boolean;
|
||||||
|
model_scope_model_id?: string;
|
||||||
|
model_scope_file_path?: string;
|
||||||
gpu_selector?: {
|
gpu_selector?: {
|
||||||
worker_name: string;
|
worker_name: string;
|
||||||
gpu_index: number;
|
gpu_index: number;
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import ReferenceParams from './reference-params';
|
|||||||
import ViewCodeModal from './view-code-modal';
|
import ViewCodeModal from './view-code-modal';
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
parameters?: any;
|
|
||||||
modelList: Global.BaseOption<string>[];
|
modelList: Global.BaseOption<string>[];
|
||||||
ref?: any;
|
ref?: any;
|
||||||
}
|
}
|
||||||
@@ -142,10 +141,6 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
setMessageList((pre) => {
|
|
||||||
return [...pre, ...currentMessageRef.current];
|
|
||||||
});
|
|
||||||
|
|
||||||
contentRef.current = '';
|
contentRef.current = '';
|
||||||
const formatMessages = _.map(
|
const formatMessages = _.map(
|
||||||
[...messageList, ...currentMessageRef.current],
|
[...messageList, ...currentMessageRef.current],
|
||||||
@@ -207,6 +202,9 @@ const GroundLeft: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error=====', error);
|
console.log('error=====', error);
|
||||||
|
setMessageList((pre) => {
|
||||||
|
return [...pre, ...currentMessageRef.current];
|
||||||
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ const MultiCompare: React.FC<MultiCompareProps> = ({ modelList }) => {
|
|||||||
span: 12,
|
span: 12,
|
||||||
count: 2
|
count: 2
|
||||||
});
|
});
|
||||||
const cacheModelInstanceList = useRef<any[]>([]);
|
|
||||||
const modelsCounterMap = useRef<Record<string, number>>({});
|
const modelsCounterMap = useRef<Record<string, number>>({});
|
||||||
const modelRefs = useRef<any>({});
|
const modelRefs = useRef<any>({});
|
||||||
const boxHeight = 'calc(100vh - 72px)';
|
const boxHeight = 'calc(100vh - 72px)';
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const contentRef = useRef<any>('');
|
const contentRef = useRef<any>('');
|
||||||
const controllerRef = useRef<any>(null);
|
const controllerRef = useRef<any>(null);
|
||||||
const currentMessageRef = useRef<MessageItem>({} as MessageItem);
|
const currentMessageRef = useRef<MessageItem[]>([]);
|
||||||
|
|
||||||
const setMessageId = () => {
|
const setMessageId = () => {
|
||||||
messageId.current = messageId.current + 1;
|
messageId.current = messageId.current + 1;
|
||||||
@@ -94,6 +94,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
console.log('currentMessage==========5', messageList);
|
console.log('currentMessage==========5', messageList);
|
||||||
setMessageList([
|
setMessageList([
|
||||||
...messageList,
|
...messageList,
|
||||||
|
...currentMessageRef.current,
|
||||||
{
|
{
|
||||||
role: Roles.Assistant,
|
role: Roles.Assistant,
|
||||||
content: contentRef.current,
|
content: contentRef.current,
|
||||||
@@ -102,13 +103,8 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitMessage = async (currentParams: {
|
const submitMessage = async (currentMessage?: Omit<MessageItem, 'uid'>) => {
|
||||||
parameters: Record<string, any>;
|
if (!params.model) return;
|
||||||
currentMessage: Omit<MessageItem, 'uid'>;
|
|
||||||
}) => {
|
|
||||||
console.log('currentMessage==========3', currentParams);
|
|
||||||
const { parameters, currentMessage } = currentParams;
|
|
||||||
if (!parameters.model) return;
|
|
||||||
try {
|
try {
|
||||||
setLoadingStatus(instanceId, true);
|
setLoadingStatus(instanceId, true);
|
||||||
setMessageId();
|
setMessageId();
|
||||||
@@ -116,26 +112,18 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
controllerRef.current?.abort?.();
|
controllerRef.current?.abort?.();
|
||||||
controllerRef.current = new AbortController();
|
controllerRef.current = new AbortController();
|
||||||
const signal = controllerRef.current.signal;
|
const signal = controllerRef.current.signal;
|
||||||
currentMessageRef.current = {
|
currentMessageRef.current = currentMessage
|
||||||
...currentMessage,
|
? [
|
||||||
uid: messageId.current
|
{
|
||||||
};
|
...currentMessage,
|
||||||
setMessageList((preList) => {
|
uid: messageId.current
|
||||||
return [
|
}
|
||||||
...preList,
|
]
|
||||||
{
|
: [];
|
||||||
...currentMessageRef.current
|
console.log('currentMessageRef.current 1:', currentMessageRef.current);
|
||||||
}
|
|
||||||
];
|
|
||||||
});
|
|
||||||
console.log('currentMessage==========4', messageList);
|
console.log('currentMessage==========4', messageList);
|
||||||
const messages = _.map(
|
const messages = _.map(
|
||||||
[
|
[...messageList, ...currentMessageRef.current],
|
||||||
...messageList,
|
|
||||||
{
|
|
||||||
...currentMessageRef.current
|
|
||||||
}
|
|
||||||
],
|
|
||||||
(item: MessageItem) => {
|
(item: MessageItem) => {
|
||||||
return {
|
return {
|
||||||
role: item.role,
|
role: item.role,
|
||||||
@@ -184,7 +172,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
...formatMessages
|
...formatMessages
|
||||||
]
|
]
|
||||||
: [...formatMessages],
|
: [...formatMessages],
|
||||||
...parameters,
|
...params,
|
||||||
stream: true
|
stream: true
|
||||||
};
|
};
|
||||||
// ============== payload end ================
|
// ============== payload end ================
|
||||||
@@ -204,6 +192,9 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
});
|
});
|
||||||
setLoadingStatus(instanceId, false);
|
setLoadingStatus(instanceId, false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
setMessageList((preList) => {
|
||||||
|
return [...preList, ...currentMessageRef.current];
|
||||||
|
});
|
||||||
setLoadingStatus(instanceId, false);
|
setLoadingStatus(instanceId, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -222,7 +213,8 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
content: string;
|
content: string;
|
||||||
}) => {
|
}) => {
|
||||||
console.log('currentMessage==========2', currentMessage);
|
console.log('currentMessage==========2', currentMessage);
|
||||||
submitMessage({ parameters: params, currentMessage });
|
const currentMsg = currentMessage.content ? currentMessage : undefined;
|
||||||
|
submitMessage(currentMsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleApplyToAllModels = (e: any) => {
|
const handleApplyToAllModels = (e: any) => {
|
||||||
@@ -260,7 +252,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
setMessageList([]);
|
setMessageList([]);
|
||||||
setTokenResult(null);
|
setTokenResult(null);
|
||||||
setSystemMessage('');
|
setSystemMessage('');
|
||||||
currentMessageRef.current = {} as MessageItem;
|
currentMessageRef.current = [];
|
||||||
console.log('clear message', systemMessage);
|
console.log('clear message', systemMessage);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -277,7 +269,7 @@ const ModelItem: React.FC<ModelItemProps> = forwardRef(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePresetMessageList = (list: MessageItem[]) => {
|
const handlePresetMessageList = (list: MessageItem[]) => {
|
||||||
currentMessageRef.current = {} as MessageItem;
|
currentMessageRef.current = [];
|
||||||
const messages = _.map(list, (item: Omit<MessageItem, 'uid'>) => {
|
const messages = _.map(list, (item: Omit<MessageItem, 'uid'>) => {
|
||||||
setMessageId();
|
setMessageId();
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { clearAtomStorage } from '@/atoms/utils';
|
|||||||
import { RequestConfig, history } from '@umijs/max';
|
import { RequestConfig, history } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
|
||||||
const NoBaseURLAPIs = ['/auth', '/v1-openai', '/version'];
|
const NoBaseURLAPIs = ['/auth', '/v1-openai', '/version', '/proxy'];
|
||||||
|
|
||||||
export const requestConfig: RequestConfig = {
|
export const requestConfig: RequestConfig = {
|
||||||
errorConfig: {
|
errorConfig: {
|
||||||
|
|||||||
Reference in New Issue
Block a user