Update server.js via upload script - 2026-07-29 11:19:26
This commit is contained in:
parent
0808063a2e
commit
857b2d4378
21
server.js
21
server.js
|
|
@ -613,9 +613,11 @@ app.post('/api/ai/parse-catalog', requireAuth, aiLimiter, (req, res) => {
|
|||
try {
|
||||
tmpDir = fs.mkdtempSync(path.join(OCR_TMP_ROOT, 'catalog-ocr-'));
|
||||
const imagePaths = [];
|
||||
const htmlTextParts = []; // HTML文件不用OCR,直接读文字内容(保留表格标签结构,AI能看懂rowspan这种分组关系)
|
||||
for (const file of req.files) {
|
||||
const isPdf = (file.mimetype || '').includes('pdf') || file.originalname.toLowerCase().endsWith('.pdf');
|
||||
const isImage = (file.mimetype || '').startsWith('image/');
|
||||
const isHtml = (file.mimetype || '').includes('html') || /\.html?$/i.test(file.originalname);
|
||||
if (isPdf) {
|
||||
const pdfSubDir = fs.mkdtempSync(path.join(tmpDir, 'pdf-'));
|
||||
const pages = await renderPdfToImages(file.buffer, pdfSubDir);
|
||||
|
|
@ -625,13 +627,24 @@ app.post('/api/ai/parse-catalog', requireAuth, aiLimiter, (req, res) => {
|
|||
const imgPath = path.join(tmpDir, `img_${imagePaths.length}${ext}`);
|
||||
fs.writeFileSync(imgPath, file.buffer);
|
||||
imagePaths.push(imgPath);
|
||||
} else if (isHtml) {
|
||||
const raw = file.buffer.toString('utf8');
|
||||
// 只去掉 <style>/<script> 这种纯样式/脚本内容(对AI提取参数没用、白白占token),
|
||||
// 保留其余全部HTML标签结构——比如 rowspan 属性能直接告诉AI"这几行同属一个分组",
|
||||
// 这比OCR识别出来的一堆无结构纯文字准确得多。
|
||||
const cleaned = raw
|
||||
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
||||
.replace(/<script[\s\S]*?<\/script>/gi, '')
|
||||
.trim();
|
||||
if (cleaned) htmlTextParts.push(cleaned);
|
||||
} else {
|
||||
return res.status(400).json({ error: `不支持的文件类型:${file.originalname}(只支持PDF或图片)` });
|
||||
return res.status(400).json({ error: `不支持的文件类型:${file.originalname}(只支持PDF、图片或HTML)` });
|
||||
}
|
||||
}
|
||||
|
||||
const text = await ocrImages(imagePaths);
|
||||
if (!text) return res.status(400).json({ error: 'OCR没有识别到任何文字,请确认文件清晰、内容完整' });
|
||||
const ocrText = imagePaths.length ? await ocrImages(imagePaths) : '';
|
||||
const text = [ocrText, ...htmlTextParts].filter(Boolean).join('\n\n--- 下一份文件 ---\n\n');
|
||||
if (!text) return res.status(400).json({ error: '没有识别/读取到任何文字内容,请确认文件清晰、内容完整' });
|
||||
|
||||
// 识别出来的文本太长就截断,避免超出模型输出预算;产品目录类文档核心信息通常靠前
|
||||
const MAX_CHARS = 24000;
|
||||
|
|
@ -642,7 +655,7 @@ app.post('/api/ai/parse-catalog', requireAuth, aiLimiter, (req, res) => {
|
|||
if (hintBrand) hintLines.push(`品牌:${hintBrand}`);
|
||||
if (hintType) hintLines.push(`细分品类:${hintType}`);
|
||||
const userContent = hintLines.length
|
||||
? `【用户已确认以下信息,直接使用,不用自己判断】\n${hintLines.join('\n')}\n\n【以下是OCR识别出的文档内容】\n${clippedText}`
|
||||
? `【用户已确认以下信息,直接使用,不用自己判断】\n${hintLines.join('\n')}\n\n【以下是文档内容,可能是OCR识别结果、也可能是直接提取的HTML源码——HTML里的表格标签结构(比如rowspan)请重点利用,能帮助你判断字段的分组归属】\n${clippedText}`
|
||||
: clippedText;
|
||||
|
||||
const content = await callDeepSeekWithRetry(cfg.apiKey, [
|
||||
|
|
|
|||
Loading…
Reference in New Issue