文件
hyb-oa/scripts/qa/check-pending-ocr.mjs
T

79 行
2.2 KiB
JavaScript

#!/usr/bin/env node
import process from "node:process";
import { PrismaClient } from "../../server/node_modules/@prisma/client/index.js";
function parseThresholds() {
const arg = process.argv.find((item) => item.startsWith("--thresholds="));
const raw = arg ? arg.slice("--thresholds=".length) : "2,5,10";
return raw
.split(",")
.map((item) => Number(item.trim()))
.filter((item) => Number.isFinite(item) && item > 0)
.sort((a, b) => a - b);
}
function minutesAgo(minutes) {
return new Date(Date.now() - minutes * 60_000);
}
async function main() {
if (!process.env.DATABASE_URL) {
console.log("[pending-ocr][SKIP] missing DATABASE_URL");
return;
}
const thresholds = parseThresholds();
const prisma = new PrismaClient();
try {
const summary = [];
for (const minutes of thresholds) {
const where = {
status: "pending_ocr",
created_at: { lte: minutesAgo(minutes) },
};
const count = await prisma.invoicePool.count({ where });
const rows = await prisma.invoicePool.findMany({
where,
orderBy: { created_at: "asc" },
take: 50,
select: {
id: true,
created_at: true,
updated_at: true,
ocr_attempts: true,
ocr_last_requested_at: true,
ocr_last_error: true,
ocr_locked_at: true,
ocr_lock_owner: true,
},
});
summary.push({
thresholdMinutes: minutes,
count,
sampleLimit: 50,
items: rows.map((item) => ({
id: item.id,
createdAt: item.created_at?.toISOString?.() ?? null,
updatedAt: item.updated_at?.toISOString?.() ?? null,
attempts: item.ocr_attempts ?? 0,
lastRequestedAt: item.ocr_last_requested_at?.toISOString?.() ?? null,
lastError: item.ocr_last_error ?? null,
lockedAt: item.ocr_locked_at?.toISOString?.() ?? null,
lockOwner: item.ocr_lock_owner ?? null,
})),
});
}
console.log(JSON.stringify({ ok: true, thresholds: summary }, null, 2));
} finally {
await prisma.$disconnect();
}
}
main().catch((error) => {
console.error(`[pending-ocr][FAIL] ${error instanceof Error ? error.message : String(error)}`);
process.exit(1);
});