// The OCR job: what `files.processors` enqueues once per matching upload. // // The tenant comes from the container, never from the payload (a module cannot mint a system // actor, decision AT-F6), so a payload that named another organization would change nothing. import { internal, type JobDef } from "@conusai-kit/core" import { OBJECT_STORE } from "@conusai-kit/data" import { type ProcessorJobPayload, processorJobPayloadSchema } from "@conusai-kit/files" import { DOCUMENT_OCR, DOCUMENTS_SCOPE } from "../core/ports.js" import { processDocument } from "../core/process.js" import { DOCUMENT_EXCLUDED_PAGE_CLASSES, DOCUMENT_MODEL, MODEL_GATEWAY, modelLineExtractor } from "./model-extractor.js" import { documentsDeps } from "./procedures.js" export const ocrJob: JobDef = { payload: processorJobPayloadSchema, async handler(payload, ctx) { const scope = ctx.container.resolve(DOCUMENTS_SCOPE) if (scope.level !== "project") throw internal(`a documents job runs in a project scope, not a ${scope.level} one`) await processDocument( { ...documentsDeps(ctx.container), store: ctx.container.resolve(OBJECT_STORE), ocr: ctx.container.resolve(DOCUMENT_OCR), // The model behind the platform's AI gateway, which the composition root binds with its model id. extractor: modelLineExtractor({ gateway: ctx.container.resolve(MODEL_GATEWAY), model: ctx.container.resolve(DOCUMENT_MODEL), ...(ctx.container.has(DOCUMENT_EXCLUDED_PAGE_CLASSES) ? { excludedPageClasses: ctx.container.resolve(DOCUMENT_EXCLUDED_PAGE_CLASSES) } : {}), }), ...(ctx.signal ? { signal: ctx.signal } : {}), }, scope, payload, ) }, }