Feat: Add mineru as a model manufacturer to the system. #10621 (#11903)

### What problem does this PR solve?

Feat: Add mineru as a model manufacturer to the system. #10621

### Type of change


- [x] New Feature (non-breaking change which adds functionality)

---------

Co-authored-by: balibabu <assassin_cike@163.com>
This commit is contained in:
balibabu
2025-12-11 17:37:10 +08:00
committed by GitHub
parent e9710b7aa9
commit 22a51a3868
15 changed files with 296 additions and 8 deletions

View File

@ -0,0 +1,22 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.2314 3.36021C20.2314 4.11144 19.6199 4.72043 18.8657 4.72043C18.1115 4.72043 17.5 4.11144 17.5 3.36021C17.5 2.60899 18.1115 2 18.8657 2C19.6199 2 20.2314 2.60899 20.2314 3.36021Z" fill="url(#paint0_linear_1151_8035)"/>
<path d="M20.2314 3.36021C20.2314 4.11144 19.6199 4.72043 18.8657 4.72043C18.1115 4.72043 17.5 4.11144 17.5 3.36021C17.5 2.60899 18.1115 2 18.8657 2C19.6199 2 20.2314 2.60899 20.2314 3.36021Z" fill="#010101"/>
<path d="M15.5887 4.72056C15.5887 5.4718 14.9773 6.08078 14.2231 6.08078C13.4688 6.08078 12.8574 5.4718 12.8574 4.72056C12.8574 3.96934 13.4688 3.36035 14.2231 3.36035C14.9773 3.36035 15.5887 3.96934 15.5887 4.72056Z" fill="url(#paint1_linear_1151_8035)"/>
<path d="M15.5887 4.72056C15.5887 5.4718 14.9773 6.08078 14.2231 6.08078C13.4688 6.08078 12.8574 5.4718 12.8574 4.72056C12.8574 3.96934 13.4688 3.36035 14.2231 3.36035C14.9773 3.36035 15.5887 3.96934 15.5887 4.72056Z" fill="#010101"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.78915 11.1888C7.78915 13.5517 8.95326 15.6437 10.7413 16.927C11.8105 15.9726 12.4832 14.5866 12.4832 13.0441V9.2336C12.4832 8.65972 12.8718 8.15804 13.4293 8.01257L20.4114 6.19033C21.2147 5.98069 22 6.5843 22 7.41139V12.0478C22 17.5442 17.5265 21.9998 12.0082 21.9998H11.9918C6.4735 21.9998 2 17.5442 2 12.0478V8.8481C2 8.27204 2.39155 7.76904 2.95168 7.62557L6.20613 6.79194C7.00807 6.58652 7.78915 7.18972 7.78915 8.01444V11.1888ZM3.4484 12.0478C3.4484 13.963 4.08358 15.7303 5.15556 17.1522C5.65521 17.815 6.41799 18.2567 7.24973 18.2567C8.0415 18.2567 8.79224 18.0815 9.46491 17.768C7.55744 16.2072 6.34075 13.8395 6.34075 11.1888V8.24701L3.4484 8.98791V12.0478Z" fill="url(#paint2_linear_1151_8035)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.78915 11.1888C7.78915 13.5517 8.95326 15.6437 10.7413 16.927C11.8105 15.9726 12.4832 14.5866 12.4832 13.0441V9.2336C12.4832 8.65972 12.8718 8.15804 13.4293 8.01257L20.4114 6.19033C21.2147 5.98069 22 6.5843 22 7.41139V12.0478C22 17.5442 17.5265 21.9998 12.0082 21.9998H11.9918C6.4735 21.9998 2 17.5442 2 12.0478V8.8481C2 8.27204 2.39155 7.76904 2.95168 7.62557L6.20613 6.79194C7.00807 6.58652 7.78915 7.18972 7.78915 8.01444V11.1888ZM3.4484 12.0478C3.4484 13.963 4.08358 15.7303 5.15556 17.1522C5.65521 17.815 6.41799 18.2567 7.24973 18.2567C8.0415 18.2567 8.79224 18.0815 9.46491 17.768C7.55744 16.2072 6.34075 13.8395 6.34075 11.1888V8.24701L3.4484 8.98791V12.0478Z" fill="#010101"/>
<defs>
<linearGradient id="paint0_linear_1151_8035" x1="14.5453" y1="8.14096" x2="13.2718" y2="19.9129" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
<linearGradient id="paint1_linear_1151_8035" x1="14.5459" y1="8.1411" x2="13.2725" y2="19.9131" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
<linearGradient id="paint2_linear_1151_8035" x1="14.5456" y1="8.14075" x2="13.2722" y2="19.9127" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,22 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.2314 3.36021C20.2314 4.11144 19.6199 4.72043 18.8657 4.72043C18.1115 4.72043 17.5 4.11144 17.5 3.36021C17.5 2.60899 18.1115 2 18.8657 2C19.6199 2 20.2314 2.60899 20.2314 3.36021Z" fill="url(#paint0_linear_1151_8043)"/>
<path d="M20.2314 3.36021C20.2314 4.11144 19.6199 4.72043 18.8657 4.72043C18.1115 4.72043 17.5 4.11144 17.5 3.36021C17.5 2.60899 18.1115 2 18.8657 2C19.6199 2 20.2314 2.60899 20.2314 3.36021Z" fill="white"/>
<path d="M15.5887 4.72056C15.5887 5.4718 14.9773 6.08078 14.2231 6.08078C13.4688 6.08078 12.8574 5.4718 12.8574 4.72056C12.8574 3.96934 13.4688 3.36035 14.2231 3.36035C14.9773 3.36035 15.5887 3.96934 15.5887 4.72056Z" fill="url(#paint1_linear_1151_8043)"/>
<path d="M15.5887 4.72056C15.5887 5.4718 14.9773 6.08078 14.2231 6.08078C13.4688 6.08078 12.8574 5.4718 12.8574 4.72056C12.8574 3.96934 13.4688 3.36035 14.2231 3.36035C14.9773 3.36035 15.5887 3.96934 15.5887 4.72056Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.78915 11.1888C7.78915 13.5517 8.95326 15.6437 10.7413 16.927C11.8105 15.9726 12.4832 14.5866 12.4832 13.0441V9.2336C12.4832 8.65972 12.8718 8.15804 13.4293 8.01257L20.4114 6.19033C21.2147 5.98069 22 6.5843 22 7.41139V12.0478C22 17.5442 17.5265 21.9998 12.0082 21.9998H11.9918C6.4735 21.9998 2 17.5442 2 12.0478V8.8481C2 8.27204 2.39155 7.76904 2.95168 7.62557L6.20613 6.79194C7.00807 6.58652 7.78915 7.18972 7.78915 8.01444V11.1888ZM3.4484 12.0478C3.4484 13.963 4.08358 15.7303 5.15556 17.1522C5.65521 17.815 6.41799 18.2567 7.24973 18.2567C8.0415 18.2567 8.79224 18.0815 9.46491 17.768C7.55744 16.2072 6.34075 13.8395 6.34075 11.1888V8.24701L3.4484 8.98791V12.0478Z" fill="url(#paint2_linear_1151_8043)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.78915 11.1888C7.78915 13.5517 8.95326 15.6437 10.7413 16.927C11.8105 15.9726 12.4832 14.5866 12.4832 13.0441V9.2336C12.4832 8.65972 12.8718 8.15804 13.4293 8.01257L20.4114 6.19033C21.2147 5.98069 22 6.5843 22 7.41139V12.0478C22 17.5442 17.5265 21.9998 12.0082 21.9998H11.9918C6.4735 21.9998 2 17.5442 2 12.0478V8.8481C2 8.27204 2.39155 7.76904 2.95168 7.62557L6.20613 6.79194C7.00807 6.58652 7.78915 7.18972 7.78915 8.01444V11.1888ZM3.4484 12.0478C3.4484 13.963 4.08358 15.7303 5.15556 17.1522C5.65521 17.815 6.41799 18.2567 7.24973 18.2567C8.0415 18.2567 8.79224 18.0815 9.46491 17.768C7.55744 16.2072 6.34075 13.8395 6.34075 11.1888V8.24701L3.4484 8.98791V12.0478Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_1151_8043" x1="14.5453" y1="8.14096" x2="13.2718" y2="19.9129" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
<linearGradient id="paint1_linear_1151_8043" x1="14.5459" y1="8.1411" x2="13.2725" y2="19.9131" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
<linearGradient id="paint2_linear_1151_8043" x1="14.5456" y1="8.14075" x2="13.2722" y2="19.9127" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#2E2E2E"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -17,7 +17,6 @@ import {
export const enum ParseDocumentType {
DeepDOC = 'DeepDOC',
PlainText = 'Plain Text',
MinerU = 'MinerU',
Docling = 'Docling',
TCADPParser = 'TCADP Parser',
}
@ -44,7 +43,6 @@ export function LayoutRecognizeFormField({
: [
ParseDocumentType.DeepDOC,
ParseDocumentType.PlainText,
ParseDocumentType.MinerU,
ParseDocumentType.Docling,
ParseDocumentType.TCADPParser,
].map((x) => ({
@ -52,7 +50,10 @@ export function LayoutRecognizeFormField({
value: x,
}));
const image2TextList = allOptions[LlmModelType.Image2text].map((x) => {
const image2TextList = [
...allOptions[LlmModelType.Image2text],
...allOptions[LlmModelType.Ocr],
].map((x) => {
return {
...x,
options: x.options.map((y) => {

View File

@ -69,6 +69,7 @@ export const LlmIcon = ({
LLMFactory.TogetherAI,
LLMFactory.Meituan,
LLMFactory.Longcat,
LLMFactory.MinerU,
];
let icon = useMemo(() => {
const icontemp = IconMap[name as keyof typeof IconMap];
@ -88,6 +89,7 @@ export const LlmIcon = ({
// LLMFactory.MiniMax,
LLMFactory.Gemini,
LLMFactory.StepFun,
LLMFactory.MinerU,
// LLMFactory.DeerAPI,
];
if (svgIcons.includes(name as LLMFactory)) {

View File

@ -62,6 +62,7 @@ export enum LlmModelType {
Speech2text = 'speech2text',
Rerank = 'rerank',
TTS = 'tts',
Ocr = 'ocr',
}
export enum KnowledgeSearchParams {

View File

@ -60,6 +60,7 @@ export enum LLMFactory {
DeerAPI = 'DeerAPI',
JiekouAI = 'Jiekou.AI',
Builtin = 'Builtin',
MinerU = 'MinerU',
}
// Please lowercase the file name
@ -125,6 +126,7 @@ export const IconMap = {
[LLMFactory.DeerAPI]: 'deerapi',
[LLMFactory.JiekouAI]: 'jiekouai',
[LLMFactory.Builtin]: 'builtin',
[LLMFactory.MinerU]: 'mineru',
};
export const APIMapUrl = {

View File

@ -147,6 +147,7 @@ export const useSelectLlmOptionsByModelType = () => {
),
[LlmModelType.Rerank]: groupOptionsByModelType(LlmModelType.Rerank),
[LlmModelType.TTS]: groupOptionsByModelType(LlmModelType.TTS),
[LlmModelType.Ocr]: groupOptionsByModelType(LlmModelType.Ocr),
};
};
@ -245,7 +246,7 @@ export const useSelectLlmList = () => {
name: key,
logo: factoryList.find((x) => x.name === key)?.logo ?? '',
...value,
llm: value.llm.map((x) => ({ ...x, name: x.name })),
llm: value.llm?.map((x) => ({ ...x, name: x.name })),
}));
}, [myLlmList, factoryList]);

View File

@ -3,7 +3,7 @@ export interface IAddLlmRequestBody {
llm_name: string;
model_type: string;
api_base?: string; // chat|embedding|speech2text|image2text
api_key: string;
api_key: string | Record<string, any>;
max_tokens: number;
}

View File

@ -1064,6 +1064,21 @@ Example: Virtual Hosted Style`,
modelsToBeAddedTooltip:
'If your model provider is not listed but claims to be "OpenAI-compatible", select the OpenAI-API-compatible card to add the relevant model(s). ',
mcp: 'MCP',
mineru: {
modelNameRequired: 'Model name is required',
apiserver: 'MinerU API Server Configuration',
outputDir: 'MinerU Output Directory Path',
backend: 'MinerU Processing Backend Type',
serverUrl: 'MinerU Server URL Address',
deleteOutput: 'Delete Output Files After Processing',
selectBackend: 'Select processing backend',
backendOptions: {
pipeline: 'Standard Pipeline Processing',
vlmTransformers: 'Vision Language Model with Transformers',
vlmVllmEngine: 'Vision Language Model with vLLM Engine',
vlmHttpClient: 'Vision Language Model via HTTP Client',
},
},
},
message: {
registered: 'Registered!',

View File

@ -936,6 +936,21 @@ General实体和关系提取提示来自 GitHub - microsoft/graphrag基于
modelsToBeAddedTooltip:
'如果你的模型供应商在这里没有列出,但是宣称 OpenAI-compatible可以通过选择卡片 OpenAI-API-compatible 设置相关模型。',
mcp: 'MCP',
mineru: {
modelNameRequired: '模型名称为必填项',
apiserver: 'MinerU API服务器配置',
outputDir: 'MinerU输出目录路径',
backend: 'MinerU处理后端类型',
serverUrl: 'MinerU服务器URL地址',
deleteOutput: '处理完成后删除输出文件',
selectBackend: '选择处理后端',
backendOptions: {
pipeline: '标准流水线处理',
vlmTransformers: '基于Transformers的视觉语言模型',
vlmVllmEngine: '基于vLLM引擎的视觉语言模型',
vlmHttpClient: '通过HTTP客户端连接的视觉语言模型',
},
},
},
message: {
registered: '注册成功',

View File

@ -73,7 +73,7 @@ export const ModelProviderCard: FC<IModelCardProps> = ({
{/* Header */}
<div className="flex h-16 items-center justify-between p-4 cursor-pointer transition-colors text-text-secondary">
<div className="flex items-center space-x-3">
<LlmIcon name={item.name} />
<LlmIcon name={item.name} width={32} />
<div>
<div className="font-medium text-xl text-text-primary">
{item.name}

View File

@ -9,7 +9,7 @@ export const UsedModel = ({
handleAddModel: (factory: string) => void;
handleEditModel: (model: any, factory: LlmItem) => void;
}) => {
const { factoryList, myLlmList: llmList, loading } = useSelectLlmList();
const { myLlmList: llmList } = useSelectLlmList();
return (
<div className="flex flex-col w-full gap-5 mb-4">
<div className="text-text-primary text-2xl font-medium mb-2 mt-4">

View File

@ -1,3 +1,4 @@
import { LLMFactory } from '@/constants/llm';
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
import {
IApiKeySavingParams,
@ -16,6 +17,7 @@ import { getRealModelName } from '@/utils/llm-util';
import { useQueryClient } from '@tanstack/react-query';
import { useCallback, useState } from 'react';
import { ApiKeyPostBody } from '../interface';
import { MinerUFormValues } from './modal/mineru-modal';
type SavingParamsState = Omit<IApiKeySavingParams, 'api_key'>;
@ -459,3 +461,42 @@ export const useHandleDeleteFactory = (llmFactory: string) => {
return { handleDeleteFactory, deleteFactory };
};
export const useSubmitMinerU = () => {
const { addLlm, loading } = useAddLlm();
const {
visible: mineruVisible,
hideModal: hideMineruModal,
showModal: showMineruModal,
} = useSetModalState();
const onMineruOk = useCallback(
async (payload: MinerUFormValues) => {
const cfg = {
...payload,
mineru_delete_output: payload.mineru_delete_output ?? true ? '1' : '0',
};
const req: IAddLlmRequestBody = {
llm_factory: LLMFactory.MinerU,
llm_name: payload.llm_name,
model_type: 'ocr',
api_key: cfg,
api_base: '',
max_tokens: 0,
};
const ret = await addLlm(req);
if (ret === 0) {
hideMineruModal();
}
},
[addLlm, hideMineruModal],
);
return {
mineruVisible,
hideMineruModal,
showMineruModal,
onMineruOk,
mineruLoading: loading,
};
};

View File

@ -13,6 +13,7 @@ import {
useSubmitFishAudio,
useSubmitGoogle,
useSubmitHunyuan,
useSubmitMinerU,
useSubmitOllama,
useSubmitSpark,
useSubmitSystemModelSetting,
@ -26,6 +27,7 @@ import BedrockModal from './modal/bedrock-modal';
import FishAudioModal from './modal/fish-audio-modal';
import GoogleModal from './modal/google-modal';
import HunyuanModal from './modal/hunyuan-modal';
import MinerUModal from './modal/mineru-modal';
import TencentCloudModal from './modal/next-tencent-modal';
import OllamaModal from './modal/ollama-modal';
import SparkModal from './modal/spark-modal';
@ -128,6 +130,14 @@ const ModelProviders = () => {
AzureAddingLoading,
} = useSubmitAzure();
const {
mineruVisible,
hideMineruModal,
showMineruModal,
onMineruOk,
mineruLoading,
} = useSubmitMinerU();
const ModalMap = useMemo(
() => ({
[LLMFactory.Bedrock]: showBedrockAddingModal,
@ -139,17 +149,19 @@ const ModelProviders = () => {
[LLMFactory.TencentCloud]: showTencentCloudAddingModal,
[LLMFactory.GoogleCloud]: showGoogleAddingModal,
[LLMFactory.AzureOpenAI]: showAzureAddingModal,
[LLMFactory.MinerU]: showMineruModal,
}),
[
showBedrockAddingModal,
showVolcAddingModal,
showHunyuanAddingModal,
showTencentCloudAddingModal,
showSparkAddingModal,
showyiyanAddingModal,
showFishAudioAddingModal,
showTencentCloudAddingModal,
showGoogleAddingModal,
showAzureAddingModal,
showMineruModal,
],
);
@ -289,6 +301,12 @@ const ModelProviders = () => {
loading={AzureAddingLoading}
llmFactory={LLMFactory.AzureOpenAI}
></AzureOpenAIModal>
<MinerUModal
visible={mineruVisible}
hideModal={hideMineruModal}
onOk={onMineruOk}
loading={mineruLoading}
></MinerUModal>
</div>
);
};

View File

@ -0,0 +1,148 @@
import { RAGFlowFormItem } from '@/components/ragflow-form';
import { ButtonLoading } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
import { Form } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { RAGFlowSelect } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { LLMFactory } from '@/constants/llm';
import { IModalProps } from '@/interfaces/common';
import { buildOptions } from '@/utils/form';
import { zodResolver } from '@hookform/resolvers/zod';
import { t } from 'i18next';
import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { z } from 'zod';
import { LLMHeader } from '../../components/llm-header';
const FormSchema = z.object({
llm_name: z.string().min(1, {
message: t('setting.mineru.modelNameRequired'),
}),
mineru_apiserver: z.string().optional(),
mineru_output_dir: z.string().optional(),
mineru_backend: z.enum([
'pipeline',
'vlm-transformers',
'vlm-vllm-engine',
'vlm-http-client',
]),
mineru_server_url: z.string().optional(),
mineru_delete_output: z.boolean(),
});
export type MinerUFormValues = z.infer<typeof FormSchema>;
const MinerUModal = ({
visible,
hideModal,
onOk,
loading,
}: IModalProps<MinerUFormValues>) => {
const { t } = useTranslation();
const backendOptions = buildOptions([
'pipeline',
'vlm-transformers',
'vlm-vllm-engine',
'vlm-http-client',
]);
const form = useForm<MinerUFormValues>({
resolver: zodResolver(FormSchema),
defaultValues: {
mineru_backend: 'pipeline',
mineru_delete_output: true,
},
});
const handleOk = async (values: MinerUFormValues) => {
const ret = await onOk?.(values as any);
if (ret) {
hideModal?.();
}
};
return (
<Dialog open={visible} onOpenChange={hideModal}>
<DialogContent>
<DialogHeader>
<DialogTitle>
<LLMHeader name={LLMFactory.MinerU} />
</DialogTitle>
</DialogHeader>
<Form {...form}>
<form
onSubmit={form.handleSubmit(handleOk)}
className="space-y-6"
id="mineru-form"
>
<RAGFlowFormItem
name="llm_name"
label={t('setting.modelName')}
required
>
<Input placeholder="mineru-from-env-1" />
</RAGFlowFormItem>
<RAGFlowFormItem
name="mineru_apiserver"
label={t('setting.mineru.apiserver')}
>
<Input placeholder="http://host.docker.internal:9987" />
</RAGFlowFormItem>
<RAGFlowFormItem
name="mineru_output_dir"
label={t('setting.mineru.outputDir')}
>
<Input placeholder="/tmp/mineru" />
</RAGFlowFormItem>
<RAGFlowFormItem
name="mineru_backend"
label={t('setting.mineru.backend')}
>
{(field) => (
<RAGFlowSelect
value={field.value}
onChange={field.onChange}
options={backendOptions}
placeholder={t('setting.mineru.selectBackend')}
/>
)}
</RAGFlowFormItem>
<RAGFlowFormItem
name="mineru_server_url"
label={t('setting.mineru.serverUrl')}
>
<Input placeholder="http://your-vllm-server:30000" />
</RAGFlowFormItem>
<RAGFlowFormItem
name="mineru_delete_output"
label={t('setting.mineru.deleteOutput')}
labelClassName="!mb-0"
>
{(field) => (
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
)}
</RAGFlowFormItem>
</form>
</Form>
<DialogFooter>
<ButtonLoading type="submit" form="mineru-form" loading={loading}>
{t('common.save', 'Save')}
</ButtonLoading>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
export default MinerUModal;