Fix PDF page count detection and add processing diagnostics
The old getPdfPageCount used a fragile regex on raw PDF binary that could undercount pages, causing survey sides to be skipped entirely. Replaced with pdf-lib's PDFDocument.load() for reliable counting, with the old regex as a fallback. Added logging for page counts and pairing to diagnose missing backs. Made-with: Cursor
This commit is contained in:
parent
1d20932ef5
commit
393114e9be
4 changed files with 63 additions and 4 deletions
43
package-lock.json
generated
43
package-lock.json
generated
|
|
@ -29,6 +29,7 @@
|
|||
"mailparser": "^3.9.6",
|
||||
"next": "16.1.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pdf2pic": "^3.2.0",
|
||||
"pg": "^8.20.0",
|
||||
"prisma": "^7.4.2",
|
||||
|
|
@ -2994,6 +2995,24 @@
|
|||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@pdf-lib/standard-fonts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
|
||||
"integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^1.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@pdf-lib/upng": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
|
||||
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^1.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@pinojs/redact": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz",
|
||||
|
|
@ -10899,6 +10918,12 @@
|
|||
"integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parent-module": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||
|
|
@ -11007,6 +11032,24 @@
|
|||
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pdf-lib": {
|
||||
"version": "1.17.1",
|
||||
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
|
||||
"integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pdf-lib/standard-fonts": "^1.0.0",
|
||||
"@pdf-lib/upng": "^1.0.1",
|
||||
"pako": "^1.0.11",
|
||||
"tslib": "^1.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pdf-lib/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/pdf2pic": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pdf2pic/-/pdf2pic-3.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
"mailparser": "^3.9.6",
|
||||
"next": "16.1.6",
|
||||
"next-themes": "^0.4.6",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"pdf2pic": "^3.2.0",
|
||||
"pg": "^8.20.0",
|
||||
"prisma": "^7.4.2",
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ export async function processFile(
|
|||
const sourceKey = `sources/${jobId}/${fileName}`;
|
||||
await uploadBuffer(sourceKey, fileBuffer, isPdf ? "application/pdf" : "image/jpeg");
|
||||
|
||||
// Pair pages: page 1 = response card (back), page 2 = survey (front), etc.
|
||||
console.log(`[ocr] ${fileName}: ${pageImages.length} page(s) extracted, isPdf=${isPdf}`);
|
||||
|
||||
// Pair pages: page 1 = response card, page 2 = survey, etc.
|
||||
const pairs: { response?: typeof pageImages[0]; survey?: typeof pageImages[0] }[] = [];
|
||||
for (let i = 0; i < pageImages.length; i += 2) {
|
||||
pairs.push({
|
||||
|
|
@ -59,6 +61,8 @@ export async function processFile(
|
|||
pairs.push({ response: pageImages[0] });
|
||||
}
|
||||
|
||||
console.log(`[ocr] ${fileName}: ${pairs.length} card pair(s), pages per pair: ${pairs.map((p, i) => `pair ${i}: response=${p.response ? "yes" : "no"}, survey=${p.survey ? "yes" : "no"}`).join("; ")}`);
|
||||
|
||||
for (let pairIdx = 0; pairIdx < pairs.length; pairIdx++) {
|
||||
if (pairIdx > 0) await ocrDelay();
|
||||
const pair = pairs[pairIdx];
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { fromBuffer } from "pdf2pic";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import sharp from "sharp";
|
||||
|
||||
export interface PageImage {
|
||||
|
|
@ -57,9 +58,19 @@ export async function pdfToImages(pdfBuffer: Buffer): Promise<PageImage[]> {
|
|||
}
|
||||
|
||||
async function getPdfPageCount(pdfBuffer: Buffer): Promise<number> {
|
||||
const text = pdfBuffer.toString("latin1");
|
||||
const matches = text.match(/\/Type\s*\/Page(?!s)/g);
|
||||
return matches ? matches.length : 2;
|
||||
try {
|
||||
const doc = await PDFDocument.load(pdfBuffer, { ignoreEncryption: true });
|
||||
const count = doc.getPageCount();
|
||||
console.log(`[pdf] Page count (pdf-lib): ${count}`);
|
||||
return count;
|
||||
} catch (err) {
|
||||
console.warn("[pdf] pdf-lib page count failed, falling back to regex:", err);
|
||||
const text = pdfBuffer.toString("latin1");
|
||||
const matches = text.match(/\/Type\s*\/Page(?!s)/g);
|
||||
const count = matches ? matches.length : 2;
|
||||
console.log(`[pdf] Page count (regex fallback): ${count}`);
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
export async function imageToBase64(buffer: Buffer): Promise<string> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue