85 lines
3.9 KiB
TypeScript
85 lines
3.9 KiB
TypeScript
// What an extracted line is, as the proposal that carries it and as the reviewer sees it.
|
|
|
|
import { z } from "zod"
|
|
import { LINE_NOTES, LINE_STATUSES, LINE_VERIFICATIONS } from "./constants.js"
|
|
|
|
/** The proposal target this module contributes to `proposals.targets`: the writer of approved lines. */
|
|
export const LINE_TARGET_KEY = "documents.line"
|
|
|
|
/** The `files.processors` key and the job it names. */
|
|
export const PROCESSOR_KEY = "documents.ocr"
|
|
export const OCR_JOB = "documents.ocr"
|
|
|
|
/** The audit events of this module, declared in its manifest. */
|
|
export const EXPORT_CREATED = "documents.export_created"
|
|
export const LINE_EDITED = "documents.line_edited"
|
|
|
|
/** The content types the module reads. Spreadsheets are the customer's own extraction, not the template's. */
|
|
export const READABLE_CONTENT_TYPES = ["application/pdf", "image/png", "image/jpeg"] as const
|
|
|
|
/**
|
|
* The change a proposal carries and approval writes. `lineKey` is derived from the document and the
|
|
* line's position, so an extraction retried after a crash adds nothing a person already decided.
|
|
*/
|
|
export const lineChangeSchema = z
|
|
.object({
|
|
lineKey: z.string().regex(/^[0-9a-f]{64}$/, "a lower-case hex SHA-256"),
|
|
label: z.string().min(1).max(200),
|
|
value: z.string().min(1).max(2_000),
|
|
page: z.number().int().min(1),
|
|
/** Where the line sits in the document's reading order: what a review and an export sort by. */
|
|
position: z.number().int().min(0),
|
|
quote: z.string().min(1).max(2_000),
|
|
/** The reader's confidence in the words the line was read from, 0 to 1; a reviewer sorts by it. */
|
|
confidence: z.number().min(0).max(1),
|
|
/** `needs_review` when the quote was not found on the page it cites (see `LINE_VERIFICATIONS`). */
|
|
verification: z.enum(LINE_VERIFICATIONS),
|
|
/** Why a reviewer should look at the line besides `verification`; absent when there is nothing to add. */
|
|
note: z.enum(LINE_NOTES).optional(),
|
|
/** True once a reviewer has corrected the label or the value (the proposals module records who and when). */
|
|
edited: z.boolean(),
|
|
})
|
|
.strict()
|
|
|
|
export type LineChange = z.output<typeof lineChangeSchema>
|
|
|
|
/**
|
|
* What a model is asked to return for one page: the line schema above, cut to the fields a model can
|
|
* know. The page is the question's, not the answer's (a model that cites a page may cite the wrong
|
|
* one), the position and the key are the code's, and a confidence is measured from the reader, not
|
|
* asked of the model. The JSON Schema sent to the gateway is derived from this.
|
|
*/
|
|
export const modelLineSchema = lineChangeSchema.pick({ label: true, value: true, quote: true }).strict()
|
|
|
|
export const MAX_MODEL_LINES = 200
|
|
|
|
export const modelLinesSchema = z.object({ lines: z.array(modelLineSchema).max(MAX_MODEL_LINES) }).strict()
|
|
|
|
export type ModelLines = z.output<typeof modelLinesSchema>
|
|
|
|
/** One line as the review screen shows it: the change, where it was read, and what was decided. */
|
|
export const lineViewSchema = z.object({
|
|
/** The proposal's id: it is what approve, reject and edit are called with. */
|
|
lineId: z.string(),
|
|
/** The proposal version the reviewer saw; approval pins to it to prevent approving a later edit. */
|
|
expectedVersion: z.number().int().min(1),
|
|
status: z.enum(LINE_STATUSES),
|
|
label: z.string(),
|
|
value: z.string(),
|
|
page: z.number().int(),
|
|
quote: z.string(),
|
|
box: z.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() }).nullable(),
|
|
confidence: z.number(),
|
|
verification: z.enum(LINE_VERIFICATIONS),
|
|
note: z.enum(LINE_NOTES).nullable(),
|
|
/** The reader's stable id of the block the quote sits in (`p{page}-b{n}`), when the reader gave one. */
|
|
blockId: z.string().nullable(),
|
|
edited: z.boolean(),
|
|
/** The model and version that produced the line: the disclosure Art. 50 asks for sits beside it. */
|
|
model: z.string(),
|
|
promptVersion: z.string(),
|
|
decidedAt: z.string().nullable(),
|
|
})
|
|
|
|
export type LineView = z.output<typeof lineViewSchema>
|