/** * Load full QQ mailbox PDF text for sample mail body (一字不落). */ import { execFile } from "child_process"; import { promisify } from "util"; import path from "path"; import fs from "fs/promises"; const execFileAsync = promisify(execFile); async function listPdfs(root: string): Promise { const out: string[] = []; const stack = [root]; while (stack.length) { const cur = stack.pop()!; let entries; try { entries = await fs.readdir(cur, { withFileTypes: true }); } catch { continue; } for (const e of entries) { const full = path.join(cur, e.name); if (e.isDirectory()) stack.push(full); else if (/\.pdf$/i.test(e.name) && /邮箱/i.test(e.name)) out.push(full); } } return out; } /** Prefer *邮箱.pdf under sample dir; return extracted text or null */ export async function loadMailboxPdfBody( sampleDirAbs: string, ): Promise { const pdfs = await listPdfs(sampleDirAbs); if (!pdfs.length) return null; // Prefer QQ邮箱 / N邮箱 over other PDFs pdfs.sort((a, b) => { const score = (p: string) => { const n = path.basename(p); if (/^QQ/i.test(n)) return 0; if (/^\d邮箱/i.test(n)) return 1; return 2; }; return score(a) - score(b); }); const target = pdfs[0]; try { const script = path.join(process.cwd(), "scripts", "extract-pdf-text.py"); const { stdout } = await execFileAsync( "python", [script, target], { maxBuffer: 12_000_000, encoding: "utf8", windowsHide: true }, ); const t = (stdout || "").replace(/\r\n/g, "\n").trim(); return t.length > 20 ? t : null; } catch (err) { console.warn("loadMailboxPdfBody failed", target, err); return null; } }