R92 A2 修复发票 OCR provider 与二进制写库

这个提交包含在:
2026-05-05 22:16:13 +08:00
父节点 fced77a567
当前提交 abba3371dd
共修改 7 个文件,包含 113 行新增和 17 行删除
+25 -8
查看文件
@@ -4,6 +4,16 @@ const { buildMissingRequiredOcrError, runOcrForInvoice } = require("../services/
const { readFileBuffer } = require("../services/storage");
const OCR_DUPLICATE_ERROR = "duplicate_invoice_code_number";
const SUPPORTED_OCR_PROVIDERS = new Set(["tencent", "mock"]);
function getEffectiveOcrProvider(config) {
const provider = config?.ocrProvider;
if (!SUPPORTED_OCR_PROVIDERS.has(provider)) {
throw new Error(`Unsupported OCR provider: ${provider}`);
}
return provider;
}
function trimErrorMessage(error) {
const code = typeof error?.code === "string" ? error.code : null;
@@ -59,7 +69,7 @@ async function claimPendingInvoices(prisma, config, workerId) {
ocr_lock_owner = ${workerId}
FROM candidates
WHERE i.id = candidates.id
RETURNING i.id, i.file_sha256, i.ocr_type, i.storage_path, i.mime_type, i.ocr_attempts
RETURNING i.id, i.file_sha256, i.ocr_provider, i.ocr_type, i.storage_path, i.mime_type, i.ocr_attempts
`;
}
@@ -89,10 +99,11 @@ async function findDuplicateInvoice(prisma, invoiceId, invoiceCode, invoiceNumbe
}
async function getOrCreateOcrResult(prisma, config, claimedInvoice, imageBase64) {
const ocrProvider = getEffectiveOcrProvider(config);
const where = {
file_sha256_ocr_provider_ocr_type: {
file_sha256: claimedInvoice.file_sha256,
ocr_provider: "tencent",
ocr_provider: ocrProvider,
ocr_type: claimedInvoice.ocr_type,
},
};
@@ -123,7 +134,7 @@ async function getOrCreateOcrResult(prisma, config, claimedInvoice, imageBase64)
const created = await prisma.ocrResult.create({
data: {
file_sha256: claimedInvoice.file_sha256,
ocr_provider: "tencent",
ocr_provider: ocrProvider,
ocr_type: claimedInvoice.ocr_type,
result_json: normalized,
},
@@ -160,12 +171,13 @@ async function getOrCreateOcrResult(prisma, config, claimedInvoice, imageBase64)
}
}
async function markInvoiceAsDuplicate(prisma, invoiceId, normalized, ocrResultId) {
async function markInvoiceAsDuplicate(prisma, config, invoiceId, normalized, ocrResultId) {
const now = new Date();
await prisma.invoicePool.update({
where: { id: invoiceId },
data: {
status: "ocr_failed",
ocr_provider: getEffectiveOcrProvider(config),
ocr_result_id: ocrResultId,
invoice_code: normalized.invoiceCode ?? null,
invoice_number: normalized.invoiceNumber ?? null,
@@ -184,12 +196,13 @@ async function markInvoiceAsDuplicate(prisma, invoiceId, normalized, ocrResultId
});
}
async function markInvoiceAsAvailable(prisma, invoiceId, normalized, ocrResultId) {
async function markInvoiceAsAvailable(prisma, config, invoiceId, normalized, ocrResultId) {
const now = new Date();
await prisma.invoicePool.update({
where: { id: invoiceId },
data: {
status: "available",
ocr_provider: getEffectiveOcrProvider(config),
ocr_result_id: ocrResultId,
invoice_code: normalized.invoiceCode ?? null,
invoice_number: normalized.invoiceNumber ?? null,
@@ -208,12 +221,13 @@ async function markInvoiceAsAvailable(prisma, invoiceId, normalized, ocrResultId
});
}
async function markInvoiceAsQualityFailed(prisma, invoiceId, normalized, ocrResultId, errorMessage) {
async function markInvoiceAsQualityFailed(prisma, config, invoiceId, normalized, ocrResultId, errorMessage) {
const now = new Date();
await prisma.invoicePool.update({
where: { id: invoiceId },
data: {
status: "ocr_failed",
ocr_provider: getEffectiveOcrProvider(config),
ocr_result_id: ocrResultId,
invoice_code: normalized.invoiceCode ?? null,
invoice_number: normalized.invoiceNumber ?? null,
@@ -241,6 +255,7 @@ async function markInvoiceAsFailed(prisma, claimedInvoice, errorMessage, config)
where: { id: claimedInvoice.id },
data: {
status: isTerminal ? "ocr_failed" : "pending_ocr",
ocr_provider: getEffectiveOcrProvider(config),
ocr_attempts: nextAttempts,
ocr_last_error: errorMessage,
ocr_completed_at: isTerminal ? now : null,
@@ -269,6 +284,7 @@ async function processClaimedInvoice(prisma, config, claimedInvoice, workerId, l
if (qualityError) {
await markInvoiceAsQualityFailed(
prisma,
config,
claimedInvoice.id,
normalized,
ocrResultId,
@@ -295,7 +311,7 @@ async function processClaimedInvoice(prisma, config, claimedInvoice, workerId, l
);
if (duplicate) {
await markInvoiceAsDuplicate(prisma, claimedInvoice.id, normalized, ocrResultId);
await markInvoiceAsDuplicate(prisma, config, claimedInvoice.id, normalized, ocrResultId);
logger.warn(
{
invoiceId: claimedInvoice.id,
@@ -308,7 +324,7 @@ async function processClaimedInvoice(prisma, config, claimedInvoice, workerId, l
return { outcome: "duplicate" };
}
await markInvoiceAsAvailable(prisma, claimedInvoice.id, normalized, ocrResultId);
await markInvoiceAsAvailable(prisma, config, claimedInvoice.id, normalized, ocrResultId);
return { outcome: "available" };
} catch (error) {
const message = trimErrorMessage(error);
@@ -427,6 +443,7 @@ function startOcrJob(fastify) {
module.exports = {
OCR_DUPLICATE_ERROR,
claimPendingInvoices,
getEffectiveOcrProvider,
markInvoiceAsQualityFailed,
runOcrOnce,
startOcrJob,