chore: check compatibility ux

This commit is contained in:
jialin
2025-03-31 16:21:40 +08:00
parent bd6c689d91
commit f83e49bd3d
30 changed files with 1192 additions and 583 deletions
+84
View File
@@ -0,0 +1,84 @@
import SealSelect from '@/components/seal-form/seal-select';
import useAppUtils from '@/hooks/use-app-utils';
import { Form } from 'antd';
import React from 'react';
import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types';
const CatalogForm: React.FC = () => {
const formCtx = useFormContext();
const { getRuleMessage } = useAppUtils();
const {
isGGUF,
byBuiltIn,
sizeOptions,
quantizationOptions,
onSizeChange,
onQuantizationChange
} = formCtx;
const source = Form.useWatch('source');
console.log('HuggingFaceForm', { source, isGGUF });
if (!byBuiltIn && !sizeOptions?.length && !quantizationOptions?.length) {
return null;
}
const handleSizeChange = (val: any) => {
onSizeChange?.(val);
};
const handleOnQuantizationChange = (val: any) => {
onQuantizationChange?.(val);
};
return (
<>
{sizeOptions && sizeOptions?.length > 0 && (
<Form.Item<FormData>
name="size"
key="size"
rules={[
{
required: true,
message: getRuleMessage('input', 'size', false)
}
]}
>
<SealSelect
filterOption
onChange={handleSizeChange}
defaultActiveFirstOption
disabled={false}
options={sizeOptions}
label="Size"
required
></SealSelect>
</Form.Item>
)}
{quantizationOptions && quantizationOptions?.length > 0 && (
<Form.Item<FormData>
name="quantization"
key="quantization"
rules={[
{
required: true,
message: getRuleMessage('select', 'quantization', false)
}
]}
>
<SealSelect
filterOption
defaultActiveFirstOption
disabled={false}
options={quantizationOptions}
onChange={handleOnQuantizationChange}
label="Quantization"
required
></SealSelect>
</Form.Item>
)}
</>
);
};
export default CatalogForm;
+68
View File
@@ -0,0 +1,68 @@
import SealInput from '@/components/seal-form/seal-input';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import React from 'react';
import { modelSourceMap } from '../config';
import { useFormContext } from '../config/form-context';
import { FormData } from '../config/types';
const HuggingFaceForm: React.FC = () => {
const formCtx = useFormContext();
const { getRuleMessage } = useAppUtils();
const intl = useIntl();
const { isGGUF, byBuiltIn } = formCtx;
const source = Form.useWatch('source');
console.log('HuggingFaceForm', { source, isGGUF });
if (
![
modelSourceMap.huggingface_value,
modelSourceMap.modelscope_value
].includes(source) ||
byBuiltIn
) {
return null;
}
return (
<>
<Form.Item<FormData>
name="repo_id"
key="repo_id"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.repoid')
}
]}
>
<SealInput.Input
label={intl.formatMessage({ id: 'models.form.repoid' })}
required
disabled={true}
></SealInput.Input>
</Form.Item>
{isGGUF && (
<Form.Item<FormData>
name="file_name"
key="file_name"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.filename')
}
]}
>
<SealInput.Input
label={intl.formatMessage({ id: 'models.form.filename' })}
required
disabled={true}
></SealInput.Input>
</Form.Item>
)}
</>
);
};
export default HuggingFaceForm;
+79
View File
@@ -0,0 +1,79 @@
import SealAutoComplete from '@/components/seal-form/auto-complete';
import TooltipList from '@/components/tooltip-list';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form } from 'antd';
import _ from 'lodash';
import React, { useRef } from 'react';
import {
backendOptionsMap,
localPathTipsList,
modelSourceMap
} from '../config';
import { useFormContext, useFormInnerContext } from '../config/form-context';
import { FormData } from '../config/types';
const LocalPathForm: React.FC = () => {
const form = Form.useFormInstance();
const formCtx = useFormContext();
const formInnerCtx = useFormInnerContext();
const source = Form.useWatch('source', form);
const { onBackendChange } = formInnerCtx;
const { modelFileOptions, byBuiltIn } = formCtx;
const { getRuleMessage } = useAppUtils();
const intl = useIntl();
const localPathCache = useRef<string>(form.getFieldValue('local_path'));
if (![modelSourceMap.local_path_value].includes(source) || byBuiltIn) {
return null;
}
const handleLocalPathBlur = (e: any) => {
const value = e.target.value;
if (value === localPathCache.current && value) {
return;
}
const isEndwithGGUF = _.endsWith(value, '.gguf');
const isBlobFile = value.split('/').pop().includes('sha256');
let backend = backendOptionsMap.llamaBox;
if (!isEndwithGGUF && !isBlobFile) {
backend = backendOptionsMap.vllm;
}
form.setFieldValue('backend', backend);
onBackendChange?.(backend);
};
const handleOnFocus = () => {
localPathCache.current = form.getFieldValue('local_path');
};
return (
<>
<Form.Item<FormData>
name="local_path"
key="local_path"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.form.filePath')
}
]}
>
<SealAutoComplete
allowClear
required
filterOption
defaultActiveFirstOption
options={modelFileOptions}
onBlur={handleLocalPathBlur}
onFocus={handleOnFocus}
label={intl.formatMessage({ id: 'models.form.filePath' })}
description={<TooltipList list={localPathTipsList}></TooltipList>}
></SealAutoComplete>
</Form.Item>
</>
);
};
export default LocalPathForm;
@@ -0,0 +1,67 @@
import IconFont from '@/components/icon-font';
import SealAutoComplete from '@/components/seal-form/auto-complete';
import useAppUtils from '@/hooks/use-app-utils';
import { useIntl } from '@umijs/max';
import { Form, Typography } from 'antd';
import React from 'react';
import { modelSourceMap, ollamaModelOptions } from '../config';
import { useFormContext, useFormInnerContext } from '../config/form-context';
import { FormData } from '../config/types';
const OllamaForm: React.FC = () => {
const formCtx = useFormContext();
const formInnerCtx = useFormInnerContext();
const { byBuiltIn } = formCtx;
const { getRuleMessage } = useAppUtils();
const intl = useIntl();
const source = Form.useWatch('source');
const formInstance = Form.useFormInstance();
if (![modelSourceMap.ollama_library_value].includes(source) || byBuiltIn) {
return null;
}
return (
<>
<Form.Item<FormData>
name="ollama_library_model_name"
key="ollama_library_model_name"
rules={[
{
required: true,
message: getRuleMessage('input', 'models.table.name')
}
]}
>
<SealAutoComplete
allowClear
filterOption
defaultActiveFirstOption
disabled={false}
options={ollamaModelOptions}
description={
<span>
<span>
{intl.formatMessage({ id: 'models.form.ollamalink' })}
</span>
<Typography.Link
className="flex-center"
href="https://www.ollama.com/library"
target="_blank"
>
<IconFont
type="icon-external-link"
className="font-size-14"
></IconFont>
</Typography.Link>
</span>
}
label={intl.formatMessage({ id: 'model.form.ollama.model' })}
placeholder={intl.formatMessage({ id: 'model.form.ollamaholder' })}
required
></SealAutoComplete>
</Form.Item>
</>
);
};
export default OllamaForm;