fix: 修改评查点设置中的多模态抽取设置的逻辑。
This commit is contained in:
@@ -54,14 +54,14 @@ export function ExtractionSettings({
|
||||
llm: initialData?.extraction_config?.llm ?? {
|
||||
fields: [],
|
||||
prompt_setting: {
|
||||
type: "system",
|
||||
type: "llm_default_prompt",
|
||||
template: "",
|
||||
},
|
||||
},
|
||||
vlm: initialData?.extraction_config?.vlm ?? {
|
||||
fields: [],
|
||||
prompt_setting: {
|
||||
type: "system",
|
||||
type: "vlm_default_prompt",
|
||||
template: "",
|
||||
},
|
||||
},
|
||||
@@ -84,11 +84,13 @@ export function ExtractionSettings({
|
||||
vlm: initialData?.extraction_config?.vlm?.fields || []
|
||||
});
|
||||
// VLM字段类型
|
||||
const [selectedVlmFieldType, setSelectedVlmFieldType] = useState('default');
|
||||
const [selectedVlmFieldType, setSelectedVlmFieldType] = useState('vlm_default_prompt');
|
||||
// 自定义字段的提示词模板
|
||||
const [customVlmPrompt, setCustomVlmPrompt] = useState('请识别文档中的印章信息,提取以下字段');
|
||||
// 提示词类型
|
||||
const [promptType, setPromptType] = useState({
|
||||
llm: initialData?.extraction_config?.llm?.prompt_setting?.type || 'system',
|
||||
vlm: initialData?.extraction_config?.vlm?.prompt_setting?.type || 'system'
|
||||
llm: initialData?.extraction_config?.llm?.prompt_setting?.type || 'llm_default_prompt',
|
||||
vlm: initialData?.extraction_config?.vlm?.prompt_setting?.type || 'vlm_default_prompt'
|
||||
});
|
||||
// 提示词模板
|
||||
const [selectedTemplate, setSelectedTemplate] = useState({
|
||||
@@ -115,6 +117,20 @@ export function ExtractionSettings({
|
||||
setCurrentTab(tab);
|
||||
};
|
||||
|
||||
// 初始化自定义字段的提示词
|
||||
useEffect(() => {
|
||||
// 在编辑模式下,如果有自定义类型的字段,加载其 template
|
||||
const vlmFields = initialData?.extraction_config?.vlm?.fields || [];
|
||||
const customField = vlmFields.find(
|
||||
(f: string | { name: string; type: string; template?: string }) =>
|
||||
typeof f === 'object' && f.type === 'custom' && f.template
|
||||
);
|
||||
|
||||
if (customField && typeof customField === 'object' && customField.template) {
|
||||
setCustomVlmPrompt(customField.template);
|
||||
}
|
||||
}, [initialData]);
|
||||
|
||||
// 自动保存字段变更状态
|
||||
// 这个效果确保添加字段后自动保存到组件状态,但不自动提交更新
|
||||
useEffect(() => {
|
||||
@@ -125,15 +141,15 @@ export function ExtractionSettings({
|
||||
const initialRegexFields = initialData?.extraction_config?.regex?.fields || [];
|
||||
const initialLlmPrompt = initialData?.extraction_config?.llm?.prompt_setting?.template || '';
|
||||
const initialVlmPrompt = initialData?.extraction_config?.vlm?.prompt_setting?.template || '';
|
||||
|
||||
|
||||
// 检查是否有实际变化
|
||||
const hasLlmFieldsChanged = JSON.stringify(fields.llm) !== JSON.stringify(initialLlmFields);
|
||||
const hasVlmFieldsChanged = JSON.stringify(fields.vlm) !== JSON.stringify(initialVlmFields);
|
||||
const hasRegexFieldsChanged = JSON.stringify(regexFields) !== JSON.stringify(initialRegexFields);
|
||||
const hasPromptContentChanged =
|
||||
promptContent.llm !== initialLlmPrompt ||
|
||||
const hasPromptContentChanged =
|
||||
promptContent.llm !== initialLlmPrompt ||
|
||||
promptContent.vlm !== initialVlmPrompt;
|
||||
|
||||
|
||||
// 只有实际发生变化时才设置为true
|
||||
if (hasLlmFieldsChanged || hasVlmFieldsChanged || hasRegexFieldsChanged || hasPromptContentChanged) {
|
||||
setHasPendingChanges(true);
|
||||
@@ -169,17 +185,26 @@ export function ExtractionSettings({
|
||||
} else {
|
||||
const newFields = [...fields.vlm];
|
||||
inputs.forEach(input => {
|
||||
const exists = newFields.some(field =>
|
||||
typeof field === 'string'
|
||||
? field === input
|
||||
const exists = newFields.some(field =>
|
||||
typeof field === 'string'
|
||||
? field === input
|
||||
: field.name === input
|
||||
);
|
||||
|
||||
|
||||
if (!exists) {
|
||||
newFields.push({
|
||||
name: input,
|
||||
type: selectedVlmFieldType as VLMFieldType
|
||||
});
|
||||
// 如果是自定义类型,添加 template 字段
|
||||
if (selectedVlmFieldType === 'custom') {
|
||||
newFields.push({
|
||||
name: input,
|
||||
type: selectedVlmFieldType as VLMFieldType,
|
||||
template: customVlmPrompt
|
||||
});
|
||||
} else {
|
||||
newFields.push({
|
||||
name: input,
|
||||
type: selectedVlmFieldType as VLMFieldType
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
setFields({ ...fields, vlm: newFields });
|
||||
@@ -190,7 +215,7 @@ export function ExtractionSettings({
|
||||
...inputValue,
|
||||
[type]: ''
|
||||
});
|
||||
|
||||
|
||||
setHasPendingChanges(true);
|
||||
};
|
||||
|
||||
@@ -218,46 +243,60 @@ export function ExtractionSettings({
|
||||
};
|
||||
|
||||
// 获取VLM字段信息
|
||||
const getFieldInfo = (fieldString: string) => {
|
||||
const parts = fieldString.split('_');
|
||||
const fieldName = parts[0];
|
||||
const fieldType = parts.length > 1 ? parts[1] : 'default';
|
||||
|
||||
let typeName, badgeClass;
|
||||
const getFieldInfo = (field: string | { name: string, type: string, template?: string }) => {
|
||||
let fieldName, fieldType, typeName, badgeClass;
|
||||
|
||||
if (typeof field === 'string') {
|
||||
const parts = field.split('_');
|
||||
fieldName = parts[0];
|
||||
fieldType = parts.length > 1 ? parts[1] : 'default';
|
||||
} else {
|
||||
fieldName = field.name;
|
||||
fieldType = field.type;
|
||||
}
|
||||
|
||||
switch (fieldType) {
|
||||
case 'currency':
|
||||
case 'vlm_default_prompt':
|
||||
typeName = '默认';
|
||||
badgeClass = 'bg-gray-100 text-gray-800';
|
||||
break;
|
||||
case 'vlm_currency_prompt':
|
||||
typeName = '货币';
|
||||
badgeClass = 'bg-green-100 text-green-800';
|
||||
break;
|
||||
case 'print':
|
||||
case 'vlm_print_prompt':
|
||||
typeName = '打印';
|
||||
badgeClass = 'bg-blue-100 text-blue-800';
|
||||
break;
|
||||
case 'seal':
|
||||
case 'vlm_seal_prompt':
|
||||
typeName = '印章';
|
||||
badgeClass = 'bg-red-100 text-red-800';
|
||||
break;
|
||||
case 'cross-seal':
|
||||
case 'vlm_acrossPageSeal_prompt':
|
||||
typeName = '骑缝章';
|
||||
badgeClass = 'bg-orange-100 text-orange-800';
|
||||
break;
|
||||
case 'english':
|
||||
case 'vlm_english_prompt':
|
||||
typeName = '英文';
|
||||
badgeClass = 'bg-purple-100 text-purple-800';
|
||||
break;
|
||||
case 'number':
|
||||
case 'vlm_number_prompt':
|
||||
typeName = '数字';
|
||||
badgeClass = 'bg-yellow-100 text-yellow-800';
|
||||
break;
|
||||
case 'handwriting':
|
||||
case 'vlm_handwriting_prompt':
|
||||
typeName = '手写';
|
||||
badgeClass = 'bg-pink-100 text-pink-800';
|
||||
break;
|
||||
case 'custom':
|
||||
typeName = '自定义';
|
||||
badgeClass = 'bg-indigo-100 text-indigo-800';
|
||||
break;
|
||||
default:
|
||||
typeName = '默认';
|
||||
badgeClass = 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
|
||||
|
||||
return { fieldName, fieldType, typeName, badgeClass };
|
||||
};
|
||||
|
||||
@@ -270,7 +309,12 @@ export function ExtractionSettings({
|
||||
value={value}
|
||||
onChange={(e) => handlePromptTypeChange(e, type)}
|
||||
>
|
||||
{EVALUATION_OPTIONS.promptTypeOptions.map((option) => (
|
||||
{type === 'llm' && EVALUATION_OPTIONS.llmPromptTypeOptions.map((option) => (
|
||||
<option key={`${type}-${option.value}`} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
{type === 'vlm' && EVALUATION_OPTIONS.vlmPromptTypeOptions.map((option) => (
|
||||
<option key={`${type}-${option.value}`} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
@@ -436,7 +480,18 @@ export function ExtractionSettings({
|
||||
const handleUpdateFields = () => {
|
||||
// 过滤掉没有字段名的正则字段
|
||||
const validRegexFields = regexFields.filter(field => field.field.trim() !== '');
|
||||
|
||||
|
||||
// 更新所有自定义类型字段的 template
|
||||
const updatedVlmFields = fields.vlm.map(field => {
|
||||
if (typeof field === 'object' && field.type === 'custom') {
|
||||
return {
|
||||
...field,
|
||||
template: customVlmPrompt
|
||||
};
|
||||
}
|
||||
return field;
|
||||
});
|
||||
|
||||
// 收集所有字段数据
|
||||
const updatedFormData = {
|
||||
...formData,
|
||||
@@ -444,14 +499,14 @@ export function ExtractionSettings({
|
||||
llm: {
|
||||
fields: fields.llm,
|
||||
prompt_setting: {
|
||||
type: promptType.llm,
|
||||
type: promptType.llm || 'llm_default_prompt',
|
||||
template: promptType.llm === 'custom' ? promptContent.llm : ''
|
||||
}
|
||||
},
|
||||
vlm: {
|
||||
fields: fields.vlm,
|
||||
fields: updatedVlmFields,
|
||||
prompt_setting: {
|
||||
type: promptType.vlm,
|
||||
type: promptType.vlm || 'vlm_default_prompt',
|
||||
template: promptType.vlm === 'custom' ? promptContent.vlm : ''
|
||||
}
|
||||
},
|
||||
@@ -620,7 +675,7 @@ export function ExtractionSettings({
|
||||
className="bg-gray-50 p-2 rounded text-xs text-gray-600 mb-2"
|
||||
id="llm-system-prompt-info"
|
||||
style={{
|
||||
display: promptType.llm === "system" ? "block" : "none",
|
||||
display: promptType.llm === "llm_default_prompt" ? "block" : "none",
|
||||
}}
|
||||
>
|
||||
系统将根据评查点类型和抽取目标自动生成适合的提示词,您无需额外配置。
|
||||
@@ -745,12 +800,7 @@ export function ExtractionSettings({
|
||||
</div>
|
||||
<div className="chips-container" id="fields-container-vlm">
|
||||
{fields.vlm.map((field, index) => {
|
||||
const { fieldName, fieldType, typeName, badgeClass } =
|
||||
getFieldInfo(
|
||||
typeof field === "string"
|
||||
? field
|
||||
: `${field.name}_${field.type}`
|
||||
);
|
||||
const { fieldName, fieldType, typeName, badgeClass } = getFieldInfo(field);
|
||||
return (
|
||||
<div className="chip" key={`vlm-field-${index}`}>
|
||||
{fieldName}
|
||||
@@ -781,115 +831,98 @@ export function ExtractionSettings({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-3 mt-3">
|
||||
<div className="col-span-1">
|
||||
<label
|
||||
className="form-label mb-1"
|
||||
htmlFor="multimodal-prompt-settings"
|
||||
>
|
||||
提示词设置
|
||||
</label>
|
||||
<div
|
||||
className="flex items-center mb-2"
|
||||
id="multimodal-prompt-settings"
|
||||
>
|
||||
{renderPromptTypeSelect(promptType.vlm, "vlm")}
|
||||
</div>
|
||||
<div
|
||||
className="bg-gray-50 p-2 rounded text-xs text-gray-600 mb-2"
|
||||
id="multimodal-system-prompt-info"
|
||||
style={{
|
||||
display: promptType.vlm === "system" ? "block" : "none",
|
||||
}}
|
||||
>
|
||||
系统将根据评查点类型和抽取目标自动生成适合的提示词,支持图表、印章等图像内容抽取。
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="multimodal-custom-prompt-container"
|
||||
style={{
|
||||
display: promptType.vlm === "custom" ? "block" : "none",
|
||||
}}
|
||||
className="border border-dashed border-gray-300 p-3 rounded-md"
|
||||
>
|
||||
<div className="mb-2">
|
||||
<label
|
||||
className="form-label mb-1 text-sm"
|
||||
htmlFor="multimodal-prompt-template"
|
||||
>
|
||||
选择提示词模板
|
||||
</label>
|
||||
<select
|
||||
className="form-select"
|
||||
id="multimodal-prompt-template"
|
||||
value={selectedTemplate.vlm}
|
||||
onChange={(e) => handleTemplateChange(e, "vlm")}
|
||||
>
|
||||
<option value="">请选择模板</option>
|
||||
<option value="7">多模态-印章识别模板</option>
|
||||
<option value="8">多模态-表格抽取模板</option>
|
||||
<option value="9">多模态-手写内容识别模板</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<label
|
||||
className="form-label mb-1 text-sm"
|
||||
htmlFor="multimodal-prompt-content"
|
||||
>
|
||||
提示词内容
|
||||
</label>
|
||||
<textarea
|
||||
className="form-textarea"
|
||||
id="multimodal-prompt-content"
|
||||
rows={4}
|
||||
placeholder="选择模板后自动填充,您也可以进行修改..."
|
||||
value={promptContent.vlm}
|
||||
onChange={(e) => handlePromptContentChange(e, "vlm")}
|
||||
readOnly={!selectedTemplate.vlm}
|
||||
></textarea>
|
||||
<div className="form-tip mt-1 bg-gray-50 p-2 rounded text-xs">
|
||||
<p className="mb-1">
|
||||
<strong>支持的变量</strong>
|
||||
(点击变量将其添加到提示词中):
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{[
|
||||
"docType",
|
||||
"fieldsList",
|
||||
"companyName",
|
||||
"documentId",
|
||||
"date",
|
||||
"industry",
|
||||
"contentType",
|
||||
"pageRange",
|
||||
"colorMode",
|
||||
"ocrText",
|
||||
].map((variable) => (
|
||||
<button
|
||||
key={variable}
|
||||
type="button"
|
||||
className="var-tag"
|
||||
onClick={() => applyVariableToPrompt(variable, "vlm")}
|
||||
>
|
||||
{variable=='docType' ? '文档类型:{docType}':
|
||||
variable=='fieldsList' ? '抽取字段列表:{fieldsList}':
|
||||
variable=='companyName' ? '公司名称:{companyName}':
|
||||
variable=='documentId' ? '文档编号:{documentId}':
|
||||
variable=='date' ? '日期:{date}':
|
||||
variable=='industry' ? '行业:{industry}':
|
||||
variable=='contentType' ? '内容类型:{contentType}':
|
||||
variable=='pageRange' ? '页面范围:{pageRange}':
|
||||
variable=='colorMode' ? '色彩模式:{colorMode}':
|
||||
variable=='ocrText' ? 'OCR文本:{ocrText}':
|
||||
variable}
|
||||
</button>
|
||||
))}
|
||||
{/* 只有当选择了自定义类型时才显示提示词设置 */}
|
||||
{selectedVlmFieldType === 'custom' && (
|
||||
<div className="grid grid-cols-1 gap-3 mt-3">
|
||||
<div className="col-span-1">
|
||||
<label
|
||||
className="form-label mb-1"
|
||||
htmlFor="multimodal-prompt-settings"
|
||||
>
|
||||
提示词设置
|
||||
</label>
|
||||
<div className="border border-dashed border-gray-300 p-3 rounded-md">
|
||||
<div className="mb-2">
|
||||
<label
|
||||
className="form-label mb-1 text-sm"
|
||||
htmlFor="multimodal-prompt-type"
|
||||
>
|
||||
提示词类型
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-input bg-gray-50"
|
||||
id="multimodal-prompt-type"
|
||||
value="使用自定义提示词"
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
<label
|
||||
className="form-label mb-1 text-sm"
|
||||
htmlFor="custom-vlm-prompt-content"
|
||||
>
|
||||
提示词内容
|
||||
</label>
|
||||
<textarea
|
||||
className="form-textarea"
|
||||
id="custom-vlm-prompt-content"
|
||||
rows={4}
|
||||
placeholder="请输入自定义提示词..."
|
||||
value={customVlmPrompt}
|
||||
onChange={(e) => {
|
||||
setCustomVlmPrompt(e.target.value);
|
||||
setHasPendingChanges(true);
|
||||
}}
|
||||
></textarea>
|
||||
<div className="form-tip mt-1 bg-gray-50 p-2 rounded text-xs">
|
||||
<p className="mb-1">
|
||||
<strong>支持的变量</strong>
|
||||
(点击变量将其添加到提示词中):
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{[
|
||||
"docType",
|
||||
"fieldsList",
|
||||
"companyName",
|
||||
"documentId",
|
||||
"date",
|
||||
"industry",
|
||||
"contentType",
|
||||
"pageRange",
|
||||
"colorMode",
|
||||
"ocrText",
|
||||
].map((variable) => (
|
||||
<button
|
||||
key={variable}
|
||||
type="button"
|
||||
className="var-tag"
|
||||
onClick={() => {
|
||||
const variableText = `\${${variable}}`;
|
||||
setCustomVlmPrompt(customVlmPrompt + variableText);
|
||||
setHasPendingChanges(true);
|
||||
}}
|
||||
>
|
||||
{variable=='docType' ? '文档类型:{docType}':
|
||||
variable=='fieldsList' ? '抽取字段列表:{fieldsList}':
|
||||
variable=='companyName' ? '公司名称:{companyName}':
|
||||
variable=='documentId' ? '文档编号:{documentId}':
|
||||
variable=='date' ? '日期:{date}':
|
||||
variable=='industry' ? '行业:{industry}':
|
||||
variable=='contentType' ? '内容类型:{contentType}':
|
||||
variable=='pageRange' ? '页面范围:{pageRange}':
|
||||
variable=='colorMode' ? '色彩模式:{colorMode}':
|
||||
variable=='ocrText' ? 'OCR文本:{ocrText}':
|
||||
variable}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user