55 lines
2.3 KiB
TypeScript
55 lines
2.3 KiB
TypeScript
// What the extraction does with one page, decided from the reader's own classification (ocr-service
|
|
// OCR3.15) and nothing the model says: whether the page is read at all, whether the model is shown the
|
|
// image besides the text, and which of the page's lines make up the text it is shown.
|
|
//
|
|
// scan the recognised text is a reading, not a record: image and text, the text marked as low trust
|
|
// table image and text: the grid is better read than recognised
|
|
// text text alone, unless the page is weak by the reader's own measure (isWeakPage)
|
|
// drawing left out by default: tens of thousands of characters of labels, no specification in them
|
|
// empty left out by default
|
|
//
|
|
// A class in `excluded` is never read, whatever the rule above; the deployment chooses the list.
|
|
|
|
import type { PageClass } from "../contract/index.js"
|
|
import type { ReadPage } from "./ports.js"
|
|
import { isWeakPage } from "./verify.js"
|
|
|
|
export type PagePlan =
|
|
| { readonly kind: "skip" }
|
|
| {
|
|
readonly kind: "read"
|
|
/** The model should be shown the page image besides the text. */
|
|
readonly image: boolean
|
|
/** The text is a recognition of an image and may be wrong: the prompt says so, and the image wins. */
|
|
readonly lowTrustText: boolean
|
|
}
|
|
|
|
export function planPage(page: ReadPage, excluded: readonly PageClass[]): PagePlan {
|
|
if (excluded.includes(page.class)) return { kind: "skip" }
|
|
switch (page.class) {
|
|
case "scan":
|
|
return { kind: "read", image: true, lowTrustText: true }
|
|
case "table":
|
|
case "drawing":
|
|
return { kind: "read", image: true, lowTrustText: page.source === "ocr" }
|
|
case "text":
|
|
return { kind: "read", image: isWeakPage(page), lowTrustText: false }
|
|
case "empty":
|
|
return { kind: "read", image: false, lowTrustText: false }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The text of a page as the model is shown it: the lines in reading order without the ones the reader
|
|
* flagged as repeating on most pages (a running header, a footer, a page stamp), which are the
|
|
* document's furniture and not its content. A page the reader returned no lines for is its text as is.
|
|
*/
|
|
export function promptTextOf(page: ReadPage): string {
|
|
if (page.lines.length === 0) return page.text
|
|
return [...page.lines]
|
|
.sort((a, b) => a.order - b.order)
|
|
.filter((line) => !line.repeated)
|
|
.map((line) => line.text)
|
|
.join("\n")
|
|
}
|