paper-burner/js/process/ocr.js

84 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// process/ocr.js
/**
* 处理 OCR (光学字符识别) API 返回的 JSON 响应,从中提取 Markdown 文本和图片数据。
*
* 主要逻辑:
* 1. **遍历页面**:迭代 `ocrResponse.pages` 数组中的每个页面对象。
* 2. **提取图片**
* - 如果 `page.images` 存在且为数组,则遍历其中的每个图片对象。
* - 对于每个图片,如果包含 `id` 和 `image_base64` 数据,则将其作为一个对象 `{ id, data }` 添加到 `imagesData` 数组中。
* - 同时,为当前页面创建一个 `pageImages` 映射,键为图片 ID值为 Markdown 中引用的相对路径 (如 `images/IMAGE_ID.png`)。
* 3. **处理页面 Markdown**
* - 获取 `page.markdown` 内容。
* - **图片路径替换**:遍历 `pageImages` 映射,使用正则表达式将 Markdown 中对原始图片 ID 的引用 (如 `![alt](IMAGE_ID)`)
* 替换为新的相对路径 (如 `![alt](images/IMAGE_ID.png)`)。这里会使用全局的 `escapeRegex` 函数(如果可用)来确保图片 ID 中的特殊字符被正确转义,
* 避免正则表达式执行错误。如果 `altText` 为空则使用图片ID作为默认的 alt 文本。
* 4. **合并 Markdown**:将处理后的每个页面的 Markdown 内容追加到 `markdownContent` 字符串后,并用两个换行符分隔。
* 5. **返回结果**:返回一个包含 `markdown` (合并后的完整 Markdown 文本) 和 `images` (提取的图片数据数组) 的对象。
* 6. **错误处理**:如果在处理过程中发生任何错误,则记录错误日志,并返回一个包含错误信息的 Markdown 内容和空图片数组的对象。
*
* @param {Object} ocrResponse - OCR API 返回的原始 JSON 对象。
* 通常包含一个 `pages` 数组,每个页面对象包含 `markdown` 文本和可选的 `images` 数组。
* @returns {Object} 一个包含处理结果的对象,结构为:
* `{ markdown: string, images: Array<{id: string, data: string}> }`。
* `markdown` 是从所有页面提取并处理图片引用后的合并文本。
* `images` 是一个包含所有提取到的图片数据的数组,每个图片对象有 `id` 和 `data` (Base64 编码的图片字符串)。
*/
function processOcrResults(ocrResponse) {
let markdownContent = '';
let imagesData = [];
try {
for (const page of ocrResponse.pages) {
const pageImages = {};
if (page.images && Array.isArray(page.images)) {
for (const img of page.images) {
if (img.id && img.image_base64) {
const imgId = img.id;
const imgData = img.image_base64;
imagesData.push({ id: imgId, data: imgData });
// 记录图片 ID 到 markdown 路径的映射
// 检查 imgId 是否已包含扩展名,避免双重扩展名问题(如 img-0.jpeg.png
const imgPath = /\.[a-z0-9]+$/i.test(imgId)
? `images/${imgId}`
: `images/${imgId}.png`;
pageImages[imgId] = imgPath;
}
}
}
let pageMarkdown = page.markdown || '';
// 修正正则表达式转义,所有 \\ 都要写成 \\\\,否则括号不匹配
for (const [imgName, imgPath] of Object.entries(pageImages)) {
// 使用全局函数 escapeRegex
const escapedImgName = typeof escapeRegex === 'function' ?
escapeRegex(imgName) :
imgName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const imgRegex = new RegExp(`!\\[([^\\]]*?)\\]\\(${escapedImgName}\\)`, 'g');
pageMarkdown = pageMarkdown.replace(imgRegex, (match, altText) => {
const finalAltText = altText || imgName;
return `![${finalAltText}](${imgPath})`;
});
}
markdownContent += pageMarkdown + '\n\n';
}
return { markdown: markdownContent.trim(), images: imagesData };
} catch (error) {
console.error('处理OCR结果时出错:', error);
if (typeof addProgressLog === "function") {
addProgressLog(`错误:处理 OCR 结果失败 - ${error.message}`);
}
return { markdown: `[错误处理OCR结果时发生错误 - ${error.message}]`, images: [] };
}
}
// 将函数添加到processModule对象
if (typeof processModule !== 'undefined') {
processModule.processOcrResults = processOcrResults;
}