Merge remote changes with RAG service optimization

- Keep user's RAG service integration for faster extraction
- Add remote's word_ai_service support
- Preserve user's parallel extraction and field header optimizations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dj
2026-04-14 17:25:13 +08:00
14 changed files with 2057 additions and 83 deletions

View File

@@ -807,6 +807,41 @@ export const backendApi = {
}
},
/**
* 填充原始模板并导出
*
* 直接打开原始模板文件,将数据填入模板的表格/单元格中,然后导出
* 适用于比赛场景:保持原始模板格式不变
*/
async fillAndExportTemplate(
templatePath: string,
filledData: Record<string, any>,
format: 'xlsx' | 'docx' = 'xlsx'
): Promise<Blob> {
const url = `${BACKEND_BASE_URL}/templates/fill-and-export`;
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
template_path: templatePath,
filled_data: filledData,
format,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || '填充模板失败');
}
return await response.blob();
} catch (error) {
console.error('填充模板失败:', error);
throw error;
}
},
// ==================== Excel 专用接口 (保留兼容) ====================
/**
@@ -1204,6 +1239,48 @@ export const aiApi = {
}
},
/**
* 上传并使用 AI 分析 TXT 文本文件,提取结构化数据
*/
async analyzeTxt(
file: File
): Promise<{
success: boolean;
filename?: string;
structured_data?: {
table?: {
columns?: string[];
rows?: string[][];
};
summary?: string;
key_value_pairs?: Array<{ key: string; value: string }>;
numeric_data?: Array<{ name: string; value: number; unit?: string }>;
};
error?: string;
}> {
const formData = new FormData();
formData.append('file', file);
const url = `${BACKEND_BASE_URL}/ai/analyze/txt`;
try {
const response = await fetch(url, {
method: 'POST',
body: formData,
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'TXT AI 分析失败');
}
return await response.json();
} catch (error) {
console.error('TXT AI 分析失败:', error);
throw error;
}
},
/**
* 生成统计信息和图表
*/
@@ -1302,4 +1379,84 @@ export const aiApi = {
throw error;
}
},
// ==================== Word AI 解析 ====================
/**
* 使用 AI 解析 Word 文档,提取结构化数据
*/
async analyzeWordWithAI(
file: File,
userHint: string = ''
): Promise<{
success: boolean;
type?: string;
headers?: string[];
rows?: string[][];
key_values?: Record<string, string>;
list_items?: string[];
summary?: string;
error?: string;
}> {
const formData = new FormData();
formData.append('file', file);
if (userHint) {
formData.append('user_hint', userHint);
}
const url = `${BACKEND_BASE_URL}/ai/analyze/word`;
try {
const response = await fetch(url, {
method: 'POST',
body: formData,
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Word AI 解析失败');
}
return await response.json();
} catch (error) {
console.error('Word AI 解析失败:', error);
throw error;
}
},
/**
* 使用 AI 解析 Word 文档并填写模板
* 一次性完成AI解析 + 填表
*/
async fillTemplateFromWordAI(
file: File,
templateFields: TemplateField[],
userHint: string = ''
): Promise<FillResult> {
const formData = new FormData();
formData.append('file', file);
formData.append('template_fields', JSON.stringify(templateFields));
if (userHint) {
formData.append('user_hint', userHint);
}
const url = `${BACKEND_BASE_URL}/ai/analyze/word/fill-template`;
try {
const response = await fetch(url, {
method: 'POST',
body: formData,
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || 'Word AI 填表失败');
}
return await response.json();
} catch (error) {
console.error('Word AI 填表失败:', error);
throw error;
}
},
};

View File

@@ -245,13 +245,27 @@ const TemplateFill: React.FC = () => {
};
const handleExport = async () => {
if (!templateFile || !filledResult) return;
if (!templateFile || !filledResult) {
console.error('handleExport 失败: templateFile=', templateFile, 'filledResult=', filledResult);
toast.error('数据不完整,无法导出');
return;
}
console.log('=== handleExport 调试 ===');
console.log('templateFile:', templateFile);
console.log('templateId:', templateId);
console.log('filledResult:', filledResult);
console.log('filledResult.filled_data:', filledResult.filled_data);
console.log('=========================');
const ext = templateFile.name.split('.').pop()?.toLowerCase();
try {
const blob = await backendApi.exportFilledTemplate(
templateId || 'temp',
// 使用新的 fillAndExportTemplate 直接填充原始模板
const blob = await backendApi.fillAndExportTemplate(
templateId || '',
filledResult.filled_data || {},
'xlsx'
ext === 'docx' ? 'docx' : 'xlsx'
);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
@@ -261,6 +275,7 @@ const TemplateFill: React.FC = () => {
URL.revokeObjectURL(url);
toast.success('导出成功');
} catch (err: any) {
console.error('导出失败:', err);
toast.error('导出失败: ' + (err.message || '未知错误'));
}
};