@stabrise/scaledp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +218 -0
- package/dist/box-DAfzwfhA.d.ts +119 -0
- package/dist/config-g6IrKlDC.d.ts +80 -0
- package/dist/data-to-image-DoZ4jQ3R.js +54 -0
- package/dist/data-to-image-DoZ4jQ3R.js.map +1 -0
- package/dist/detect/index.d.ts +71 -0
- package/dist/detect/index.js +2 -0
- package/dist/detect-q8AI_Jdj.js +274 -0
- package/dist/detect-q8AI_Jdj.js.map +1 -0
- package/dist/detector-output-C0Qt-jEq.d.ts +13 -0
- package/dist/detector-output-lyF1Mqb8.js +13 -0
- package/dist/detector-output-lyF1Mqb8.js.map +1 -0
- package/dist/display/index.d.ts +66 -0
- package/dist/display/index.js +237 -0
- package/dist/display/index.js.map +1 -0
- package/dist/document-B8I61TiY.d.ts +16 -0
- package/dist/entity-CedtRhU1.d.ts +22 -0
- package/dist/entity-D6Hxaugj.js +13 -0
- package/dist/entity-D6Hxaugj.js.map +1 -0
- package/dist/image-CAH2rLv9.js +511 -0
- package/dist/image-CAH2rLv9.js.map +1 -0
- package/dist/image-Dc5TSg46.d.ts +18 -0
- package/dist/image-DoZDJkcR.js +37 -0
- package/dist/image-DoZDJkcR.js.map +1 -0
- package/dist/image-draw-boxes-De0QbFv9.js +285 -0
- package/dist/image-draw-boxes-De0QbFv9.js.map +1 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +11 -0
- package/dist/model-cache-BEaqqRZ9.js +182 -0
- package/dist/model-cache-BEaqqRZ9.js.map +1 -0
- package/dist/model-cache-BhFYpfZz.d.ts +36 -0
- package/dist/ner/index.d.ts +293 -0
- package/dist/ner/index.js +2 -0
- package/dist/ner-SsZLZ6ed.js +1028 -0
- package/dist/ner-SsZLZ6ed.js.map +1 -0
- package/dist/ocr/index.d.ts +440 -0
- package/dist/ocr/index.js +3 -0
- package/dist/ocr-OHX2WM3e.js +1294 -0
- package/dist/ocr-OHX2WM3e.js.map +1 -0
- package/dist/ort-CXDoPrtw.js +73 -0
- package/dist/ort-CXDoPrtw.js.map +1 -0
- package/dist/params-DapwK9Ns.js +37 -0
- package/dist/params-DapwK9Ns.js.map +1 -0
- package/dist/pdf/index.d.ts +123 -0
- package/dist/pdf/index.js +2 -0
- package/dist/pdf-BQl0dneD.js +417 -0
- package/dist/pdf-BQl0dneD.js.map +1 -0
- package/dist/pipeline-DACqGkpN.js +240 -0
- package/dist/pipeline-DACqGkpN.js.map +1 -0
- package/dist/pipeline-DeLO-OCE.d.ts +139 -0
- package/dist/registry/index.d.ts +169 -0
- package/dist/registry/index.js +1061 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/text-ahMLpxN9.js +109 -0
- package/dist/text-ahMLpxN9.js.map +1 -0
- package/dist/worker/index.d.ts +105 -0
- package/dist/worker/index.js +180 -0
- package/dist/worker/index.js.map +1 -0
- package/package.json +135 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { _ as assertPositiveInt, a as PipelineOptions, c as RowTime, d as StageDescriptor, f as toRows, g as assertInRange, h as Validator, i as PipelineInput, l as Stage, m as BaseStageParams, n as ExecutionTime, o as ROW_TIME_COL, p as BASE_STAGE_DEFAULTS, r as Pipeline, s as Row, t as EXECUTION_TIME_COL, u as StageContext, v as resolveParams } from "./pipeline-DeLO-OCE.js";
|
|
2
|
+
import { S as polygonPerimeter, _ as RotatedRect, a as bbox, b as minAreaRect, c as boxIou, d as isRotated, f as mergeBoxes, g as Point, h as shape, i as ROTATION_EPSILON_DEGREES, l as createBox, m as scaleBox, n as Box, o as boxFromBBox, p as mergeOverlappingBoxes, r as BoxShape, s as boxFromPolygon, t as BBox, u as isOnSameLine, v as boxPoints, x as polygonArea, y as convexHull } from "./box-DAfzwfhA.js";
|
|
3
|
+
import { n as createDetectorOutput, t as DetectorOutput } from "./detector-output-C0Qt-jEq.js";
|
|
4
|
+
import { n as createDocument, r as mergeDocuments, t as Document } from "./document-B8I61TiY.js";
|
|
5
|
+
import { n as NerOutput, r as createNerOutput, t as Entity } from "./entity-CedtRhU1.js";
|
|
6
|
+
import { n as ScaleDpImage, r as createImage, t as ImageFormat } from "./image-Dc5TSg46.js";
|
|
7
|
+
import { a as getConfig, i as defaultNumThreads, n as ScaleDpConfig, o as resetConfig, r as configure, s as resolveNumThreads, t as ModelProgress } from "./config-g6IrKlDC.js";
|
|
8
|
+
import { a as ensureModelFiles, c as isCached, i as cacheKey, n as ModelFiles, o as evict, r as ModelSpec, s as fileUrl, t as ModelFile } from "./model-cache-BhFYpfZz.js";
|
|
9
|
+
//#region src/core/errors.d.ts
|
|
10
|
+
/**
|
|
11
|
+
* ScaleDP stages never throw by default: a failure is captured into the output
|
|
12
|
+
* schema's `exception` field so a pipeline always completes and partial results
|
|
13
|
+
* survive. `propagateError: true` opts a stage into throwing instead.
|
|
14
|
+
*/
|
|
15
|
+
declare class ScaleDpError extends Error {
|
|
16
|
+
readonly stage: string;
|
|
17
|
+
readonly cause?: unknown | undefined;
|
|
18
|
+
constructor(message: string, stage: string, cause?: unknown | undefined);
|
|
19
|
+
}
|
|
20
|
+
declare class ImageError extends ScaleDpError {
|
|
21
|
+
readonly name = "ImageError";
|
|
22
|
+
}
|
|
23
|
+
declare class OcrError extends ScaleDpError {
|
|
24
|
+
readonly name = "OcrError";
|
|
25
|
+
}
|
|
26
|
+
declare class DetectionError extends ScaleDpError {
|
|
27
|
+
readonly name = "DetectionError";
|
|
28
|
+
}
|
|
29
|
+
declare class NerError extends ScaleDpError {
|
|
30
|
+
readonly name = "NerError";
|
|
31
|
+
}
|
|
32
|
+
declare class ConfigError extends ScaleDpError {
|
|
33
|
+
readonly name = "ConfigError";
|
|
34
|
+
}
|
|
35
|
+
/** Render a caught value the way Python writes a traceback into `exception`. */
|
|
36
|
+
declare function formatException(stage: string, error: unknown): string;
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/core/image.d.ts
|
|
39
|
+
interface Size {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
}
|
|
43
|
+
declare function createCanvas(width: number, height: number): OffscreenCanvas;
|
|
44
|
+
declare function context2d(canvas: OffscreenCanvas): OffscreenCanvasRenderingContext2D;
|
|
45
|
+
declare function decodeImage(data: Uint8Array | Blob): Promise<ImageBitmap>;
|
|
46
|
+
declare function toImageData(source: ImageBitmap | OffscreenCanvas): ImageData;
|
|
47
|
+
declare function imageDataToCanvas(image: ImageData): OffscreenCanvas;
|
|
48
|
+
declare function encodeImage(source: ImageData | OffscreenCanvas, type?: 'image/png' | 'image/webp' | 'image/jpeg', quality?: number): Promise<Uint8Array>;
|
|
49
|
+
/** Read the intrinsic size of encoded image bytes without keeping the bitmap. */
|
|
50
|
+
declare function probeImageSize(data: Uint8Array | Blob): Promise<Size>;
|
|
51
|
+
interface LetterboxResult {
|
|
52
|
+
canvas: OffscreenCanvas;
|
|
53
|
+
/** Uniform scale applied to the source. */
|
|
54
|
+
scale: number;
|
|
55
|
+
/** Size the source occupies inside the target canvas. */
|
|
56
|
+
resized: Size;
|
|
57
|
+
/** Original source size. */
|
|
58
|
+
source: Size;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Fit an image into `target` preserving aspect ratio.
|
|
62
|
+
*
|
|
63
|
+
* `padding: 'end'` pads bottom and right only, matching PaddleOCR's detection
|
|
64
|
+
* preprocessing -- coordinates then restore by dividing by `scale`, with no
|
|
65
|
+
* offset to subtract. `padding: 'center'` centres the image, matching the YOLO
|
|
66
|
+
* preprocessing, where the pad offsets must be subtracted before unscaling.
|
|
67
|
+
*/
|
|
68
|
+
declare function letterbox(source: ImageBitmap | OffscreenCanvas, target: Size, opts?: {
|
|
69
|
+
padding?: 'end' | 'center';
|
|
70
|
+
fill?: string;
|
|
71
|
+
}): LetterboxResult;
|
|
72
|
+
/** Uniform resize by a scale factor. */
|
|
73
|
+
declare function resize(source: ImageBitmap | OffscreenCanvas, factor: number): OffscreenCanvas;
|
|
74
|
+
/**
|
|
75
|
+
* Crop a box out of an image, straightening it if it is rotated.
|
|
76
|
+
*
|
|
77
|
+
* Port of `TesseractRecognizer._prepare_box_for_ocr`. For upright boxes this is
|
|
78
|
+
* a plain crop; for rotated ones it applies the affine transform that maps the
|
|
79
|
+
* box's own corners onto the destination rectangle, which is what makes a
|
|
80
|
+
* recognizer see level text.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* The transform `cropBox` applies, as a function from crop pixel to source
|
|
84
|
+
* pixel.
|
|
85
|
+
*
|
|
86
|
+
* Kept separate so anything that needs to map *back* -- word boxes recognised
|
|
87
|
+
* inside a crop, say -- uses the same geometry the crop was made with, rather
|
|
88
|
+
* than a second copy of it that can drift.
|
|
89
|
+
*/
|
|
90
|
+
interface CropGeometry {
|
|
91
|
+
/** The box after scaling and padding, in source coordinates. */
|
|
92
|
+
scaled: Box;
|
|
93
|
+
width: number;
|
|
94
|
+
height: number;
|
|
95
|
+
/** Crop pixel -> source pixel. */
|
|
96
|
+
map: (x: number, y: number) => Point;
|
|
97
|
+
}
|
|
98
|
+
declare function cropGeometry(box: Box, opts?: {
|
|
99
|
+
scaleFactor?: number;
|
|
100
|
+
padding?: number;
|
|
101
|
+
}): CropGeometry;
|
|
102
|
+
declare function cropBox(source: ImageBitmap | OffscreenCanvas, box: Box, opts?: {
|
|
103
|
+
scaleFactor?: number;
|
|
104
|
+
padding?: number;
|
|
105
|
+
}): OffscreenCanvas;
|
|
106
|
+
/**
|
|
107
|
+
* Build an NCHW float32 tensor from an image.
|
|
108
|
+
*
|
|
109
|
+
* `bgr` exists because ScaleDP's DBNet path converts RGB->BGR and never swaps
|
|
110
|
+
* back, so the model is fed BGR channels against RGB ImageNet statistics.
|
|
111
|
+
* Replicating that quirk is required for box parity.
|
|
112
|
+
*/
|
|
113
|
+
declare function toNchwFloat32(image: ImageData, opts?: {
|
|
114
|
+
mean?: readonly number[];
|
|
115
|
+
std?: readonly number[];
|
|
116
|
+
scale?: number;
|
|
117
|
+
bgr?: boolean;
|
|
118
|
+
}): Float32Array;
|
|
119
|
+
declare const IMAGENET_MEAN: readonly [0.485, 0.456, 0.406];
|
|
120
|
+
declare const IMAGENET_STD: readonly [0.229, 0.224, 0.225];
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/core/text.d.ts
|
|
123
|
+
/**
|
|
124
|
+
* Arrange items into groups whose successive elements differ by no more than
|
|
125
|
+
* `maxGap`. Unlike Python's `cluster`, this does not sort the caller's array
|
|
126
|
+
* in place.
|
|
127
|
+
*/
|
|
128
|
+
declare function cluster<T>(items: readonly T[], maxGap: number, key?: (item: T) => number): T[][];
|
|
129
|
+
/**
|
|
130
|
+
* A robust central value: drop the first and last quartile, then take the mode.
|
|
131
|
+
*
|
|
132
|
+
* Trimming the tails is what makes this survive OCR outliers -- a single giant
|
|
133
|
+
* heading would otherwise skew a plain mean. Always returns a truncated
|
|
134
|
+
* integer, matching Python's `int(...)` wrapper.
|
|
135
|
+
*/
|
|
136
|
+
declare function getSize<T>(items: readonly T[], key?: (item: T) => number): number;
|
|
137
|
+
/**
|
|
138
|
+
* Median-ish width of a single character, used to size inter-word gaps.
|
|
139
|
+
* Takes grouped lines, matching Python's signature.
|
|
140
|
+
*/
|
|
141
|
+
declare function getCharacterWidth(lines: readonly (readonly Box[])[]): number;
|
|
142
|
+
/**
|
|
143
|
+
* Group boxes into text lines, each sorted left to right.
|
|
144
|
+
*
|
|
145
|
+
* `lineTolerance` of 0 means "derive it": a third of the typical character
|
|
146
|
+
* height -- tight enough to keep adjacent lines apart, loose enough to tolerate
|
|
147
|
+
* baseline jitter.
|
|
148
|
+
*/
|
|
149
|
+
declare function groupBoxesIntoLines(boxes: readonly Box[], lineTolerance?: number): Box[][];
|
|
150
|
+
/**
|
|
151
|
+
* Render grouped lines back to text, preserving horizontal spacing and blank
|
|
152
|
+
* lines.
|
|
153
|
+
*
|
|
154
|
+
* Each line is indented from x = 0, so the left margin is preserved rather than
|
|
155
|
+
* every line being flushed left. Vertical gaps wider than two character heights
|
|
156
|
+
* become blank lines. The running `y` starts at 0, which means the first line is
|
|
157
|
+
* measured against the top of the page -- that is Python's behaviour and it is
|
|
158
|
+
* what makes a top margin survive.
|
|
159
|
+
*/
|
|
160
|
+
declare function linesToFormattedText(lines: readonly (readonly Box[])[], characterHeight: number): string;
|
|
161
|
+
/** Rebuild layout-preserving text straight from a flat box list. */
|
|
162
|
+
declare function boxesToFormattedText(boxes: readonly Box[], lineTolerance?: number): string;
|
|
163
|
+
/** Plain reading-order join, the default when `keepFormatting` is off. */
|
|
164
|
+
declare function boxesToText(boxes: readonly Box[], separator?: string): string;
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region src/stages/data-to-image.d.ts
|
|
167
|
+
interface DataToImageParams extends BaseStageParams {
|
|
168
|
+
/** Encoding recorded on the output; the bytes are passed through unchanged. */
|
|
169
|
+
imageType: ImageFormat;
|
|
170
|
+
/** DPI to record when the row carries no `resolution` field. */
|
|
171
|
+
resolution: number;
|
|
172
|
+
}
|
|
173
|
+
declare const DATA_TO_IMAGE_DEFAULTS: DataToImageParams;
|
|
174
|
+
declare class DataToImage extends Stage<DataToImageParams> {
|
|
175
|
+
readonly name = "DataToImage";
|
|
176
|
+
constructor(options?: Partial<DataToImageParams>);
|
|
177
|
+
protected apply(input: unknown, row: Row): Promise<ScaleDpImage>;
|
|
178
|
+
protected onError(message: string, row: Row): ScaleDpImage;
|
|
179
|
+
}
|
|
180
|
+
/** Coerce any accepted binary representation into bytes. */
|
|
181
|
+
declare function toBytes(input: unknown): Uint8Array;
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/stages/image-crop-boxes.d.ts
|
|
184
|
+
interface ImageCropBoxesParams extends BaseStageParams {
|
|
185
|
+
/** [imageColumn, boxColumn]. */
|
|
186
|
+
inputCols: string[];
|
|
187
|
+
imageType: ImageFormat;
|
|
188
|
+
/** Grow each box by this many pixels before cropping. */
|
|
189
|
+
padding: number;
|
|
190
|
+
/** Maximum crops per page; 0 means all of them. */
|
|
191
|
+
limit: number;
|
|
192
|
+
/** Rotate portrait crops a quarter turn, so text reads horizontally. */
|
|
193
|
+
autoRotate: boolean;
|
|
194
|
+
/** Emit the whole page when nothing was detected, instead of failing. */
|
|
195
|
+
returnEmpty: boolean;
|
|
196
|
+
/** Column to write the source box alongside each crop. */
|
|
197
|
+
boxCol: string;
|
|
198
|
+
}
|
|
199
|
+
declare const IMAGE_CROP_BOXES_DEFAULTS: ImageCropBoxesParams;
|
|
200
|
+
declare class ImageCropBoxes extends Stage<ImageCropBoxesParams> {
|
|
201
|
+
readonly name = "ImageCropBoxes";
|
|
202
|
+
constructor(options?: Partial<ImageCropBoxesParams>);
|
|
203
|
+
protected expand(_input: unknown, row: Row, ctx: StageContext): Promise<Row[]>;
|
|
204
|
+
protected apply(): Promise<never>;
|
|
205
|
+
protected onError(message: string, row: Row): ScaleDpImage;
|
|
206
|
+
}
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/stages/image-draw-boxes.d.ts
|
|
209
|
+
interface ImageDrawBoxesParams extends BaseStageParams {
|
|
210
|
+
/**
|
|
211
|
+
* First entry is the image; the rest are box or entity sources. `inputCol`
|
|
212
|
+
* is inherited and unused here -- multi-input stages address their columns
|
|
213
|
+
* through this list, as they do in Python.
|
|
214
|
+
*/
|
|
215
|
+
inputCols: string[];
|
|
216
|
+
imageType: ImageFormat;
|
|
217
|
+
/** Fill boxes as well as outlining them. */
|
|
218
|
+
filled: boolean;
|
|
219
|
+
/** Fixed colour for every box. Unset colours by group instead. */
|
|
220
|
+
color: string | null;
|
|
221
|
+
lineWidth: number;
|
|
222
|
+
textSize: number;
|
|
223
|
+
/**
|
|
224
|
+
* Box or entity fields to render as a label above each box, joined by ':'.
|
|
225
|
+
* e.g. ['entity_group'] or ['text', 'score'].
|
|
226
|
+
*/
|
|
227
|
+
displayDataList: string[];
|
|
228
|
+
/** Grow each box by this many pixels before drawing. */
|
|
229
|
+
padding: number;
|
|
230
|
+
/** Only draw these entity groups; empty draws all. */
|
|
231
|
+
whiteList: string[];
|
|
232
|
+
/** Never draw these entity groups. */
|
|
233
|
+
blackList: string[];
|
|
234
|
+
}
|
|
235
|
+
declare const IMAGE_DRAW_BOXES_DEFAULTS: ImageDrawBoxesParams;
|
|
236
|
+
/**
|
|
237
|
+
* A stable colour per group name.
|
|
238
|
+
*
|
|
239
|
+
* Python picks a random colour per group, which changes on every run and makes
|
|
240
|
+
* two renders of the same document impossible to compare. Hashing the name
|
|
241
|
+
* instead keeps 'PERSON' the same colour everywhere, and the fixed saturation
|
|
242
|
+
* and lightness keep every colour legible on a white page.
|
|
243
|
+
*/
|
|
244
|
+
declare function colorForGroup(name: string): string;
|
|
245
|
+
declare class ImageDrawBoxes extends Stage<ImageDrawBoxesParams> {
|
|
246
|
+
readonly name = "ImageDrawBoxes";
|
|
247
|
+
constructor(options?: Partial<ImageDrawBoxesParams>);
|
|
248
|
+
/** The base class drives `apply` off inputCol; this stage reads several. */
|
|
249
|
+
protected apply(_input: unknown, row: Row): Promise<ScaleDpImage>;
|
|
250
|
+
private drawBoxes;
|
|
251
|
+
private drawEntities;
|
|
252
|
+
private drawBox;
|
|
253
|
+
/**
|
|
254
|
+
* The label chip, anchored to the box's own top edge.
|
|
255
|
+
*
|
|
256
|
+
* Python places it at `box.x, box.y`, which is the corner of the *axis-
|
|
257
|
+
* aligned envelope*. For an upright box that is the top-left corner and the
|
|
258
|
+
* label sits where you expect; for a rotated one the envelope corner can be
|
|
259
|
+
* a long way off the box -- a vertical line's label lands beside its middle,
|
|
260
|
+
* detached from the box it names. Here the chip is drawn in the box's own
|
|
261
|
+
* frame instead, so it rides the top edge at the box's angle whatever that
|
|
262
|
+
* angle is. Upright boxes come out exactly where Python puts them.
|
|
263
|
+
*/
|
|
264
|
+
private drawLabel;
|
|
265
|
+
protected onError(message: string, row: Row): ScaleDpImage;
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
268
|
+
export { BASE_STAGE_DEFAULTS, BBox, type BaseStageParams, Box, BoxShape, ConfigError, CropGeometry, DATA_TO_IMAGE_DEFAULTS, DataToImage, type DataToImageParams, DetectionError, DetectorOutput, Document, EXECUTION_TIME_COL, Entity, type ExecutionTime, IMAGENET_MEAN, IMAGENET_STD, IMAGE_CROP_BOXES_DEFAULTS, IMAGE_DRAW_BOXES_DEFAULTS, ImageCropBoxes, type ImageCropBoxesParams, ImageDrawBoxes, type ImageDrawBoxesParams, ImageError, ImageFormat, LetterboxResult, type ModelFile, type ModelFiles, type ModelProgress, type ModelSpec, NerError, NerOutput, OcrError, Pipeline, type PipelineInput, type PipelineOptions, Point, ROTATION_EPSILON_DEGREES, ROW_TIME_COL, RotatedRect, type Row, type RowTime, type ScaleDpConfig, ScaleDpError, ScaleDpImage, Size, Stage, type StageContext, type StageDescriptor, type Validator, assertInRange, assertPositiveInt, bbox, boxFromBBox, boxFromPolygon, boxIou, boxPoints, boxesToFormattedText, boxesToText, cacheKey, cluster, colorForGroup, configure, context2d, convexHull, createBox, createCanvas, createDetectorOutput, createDocument, createImage, createNerOutput, cropBox, cropGeometry, decodeImage, defaultNumThreads, encodeImage, ensureModelFiles, evict, fileUrl, formatException, getCharacterWidth, getConfig, getSize, groupBoxesIntoLines, imageDataToCanvas, isCached, isOnSameLine, isRotated, letterbox, linesToFormattedText, mergeBoxes, mergeDocuments, mergeOverlappingBoxes, minAreaRect, polygonArea, polygonPerimeter, probeImageSize, resetConfig, resize, resolveNumThreads, resolveParams, scaleBox, shape, toBytes, toImageData, toNchwFloat32, toRows };
|
|
269
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { _ as resolveNumThreads, a as toRows, c as ImageError, d as ScaleDpError, f as formatException, g as resetConfig, h as getConfig, i as Stage, l as NerError, m as defaultNumThreads, n as Pipeline, o as ConfigError, p as configure, r as ROW_TIME_COL, s as DetectionError, t as EXECUTION_TIME_COL, u as OcrError } from "./pipeline-DACqGkpN.js";
|
|
2
|
+
import { A as polygonArea, C as mergeBoxes, D as boxPoints, E as shape, O as convexHull, S as isRotated, T as scaleBox, _ as boxFromBBox, a as cropBox, b as createBox, c as encodeImage, d as probeImageSize, f as resize, g as bbox, h as ROTATION_EPSILON_DEGREES, i as createCanvas, j as polygonPerimeter, k as minAreaRect, l as imageDataToCanvas, m as toNchwFloat32, n as IMAGENET_STD, o as cropGeometry, p as toImageData, r as context2d, s as decodeImage, t as IMAGENET_MEAN, u as letterbox, v as boxFromPolygon, w as mergeOverlappingBoxes, x as isOnSameLine, y as boxIou } from "./image-CAH2rLv9.js";
|
|
3
|
+
import { a as isCached, i as fileUrl, n as ensureModelFiles, r as evict, t as cacheKey } from "./model-cache-BEaqqRZ9.js";
|
|
4
|
+
import { i as resolveParams, n as assertInRange, r as assertPositiveInt, t as BASE_STAGE_DEFAULTS } from "./params-DapwK9Ns.js";
|
|
5
|
+
import { a as getSize, i as getCharacterWidth, n as boxesToText, o as groupBoxesIntoLines, r as cluster, s as linesToFormattedText, t as boxesToFormattedText } from "./text-ahMLpxN9.js";
|
|
6
|
+
import { t as createDetectorOutput } from "./detector-output-lyF1Mqb8.js";
|
|
7
|
+
import { n as createDocument, r as mergeDocuments, t as createImage } from "./image-DoZDJkcR.js";
|
|
8
|
+
import { t as createNerOutput } from "./entity-D6Hxaugj.js";
|
|
9
|
+
import { n as DataToImage, r as toBytes, t as DATA_TO_IMAGE_DEFAULTS } from "./data-to-image-DoZ4jQ3R.js";
|
|
10
|
+
import { a as ImageCropBoxes, i as IMAGE_CROP_BOXES_DEFAULTS, n as ImageDrawBoxes, r as colorForGroup, t as IMAGE_DRAW_BOXES_DEFAULTS } from "./image-draw-boxes-De0QbFv9.js";
|
|
11
|
+
export { BASE_STAGE_DEFAULTS, ConfigError, DATA_TO_IMAGE_DEFAULTS, DataToImage, DetectionError, EXECUTION_TIME_COL, IMAGENET_MEAN, IMAGENET_STD, IMAGE_CROP_BOXES_DEFAULTS, IMAGE_DRAW_BOXES_DEFAULTS, ImageCropBoxes, ImageDrawBoxes, ImageError, NerError, OcrError, Pipeline, ROTATION_EPSILON_DEGREES, ROW_TIME_COL, ScaleDpError, Stage, assertInRange, assertPositiveInt, bbox, boxFromBBox, boxFromPolygon, boxIou, boxPoints, boxesToFormattedText, boxesToText, cacheKey, cluster, colorForGroup, configure, context2d, convexHull, createBox, createCanvas, createDetectorOutput, createDocument, createImage, createNerOutput, cropBox, cropGeometry, decodeImage, defaultNumThreads, encodeImage, ensureModelFiles, evict, fileUrl, formatException, getCharacterWidth, getConfig, getSize, groupBoxesIntoLines, imageDataToCanvas, isCached, isOnSameLine, isRotated, letterbox, linesToFormattedText, mergeBoxes, mergeDocuments, mergeOverlappingBoxes, minAreaRect, polygonArea, polygonPerimeter, probeImageSize, resetConfig, resize, resolveNumThreads, resolveParams, scaleBox, shape, toBytes, toImageData, toNchwFloat32, toRows };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { h as getConfig } from "./pipeline-DACqGkpN.js";
|
|
2
|
+
//#region src/core/model-cache.ts
|
|
3
|
+
/**
|
|
4
|
+
* Model file fetching with IndexedDB persistence and streaming progress.
|
|
5
|
+
*
|
|
6
|
+
* The pdftools prototype implements this twice -- once for GLiNER and once for
|
|
7
|
+
* PaddleOCR -- differing only in where sizes come from and whether an auth
|
|
8
|
+
* token is attached. Both behaviours are folded in here: sizes come from a HEAD
|
|
9
|
+
* request (real percentages, rather than the hardcoded byte counts the GLiNER
|
|
10
|
+
* copy used) with a declared `approxBytes` as fallback.
|
|
11
|
+
*/
|
|
12
|
+
const STORE = "files";
|
|
13
|
+
const DB_VERSION = 1;
|
|
14
|
+
function openDb(name) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const request = indexedDB.open(name, DB_VERSION);
|
|
17
|
+
request.onupgradeneeded = () => {
|
|
18
|
+
const db = request.result;
|
|
19
|
+
if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);
|
|
20
|
+
};
|
|
21
|
+
request.onsuccess = () => resolve(request.result);
|
|
22
|
+
request.onerror = () => reject(request.error);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Run one store operation.
|
|
27
|
+
*
|
|
28
|
+
* Writes resolve on transaction *commit*, not on request success -- a request
|
|
29
|
+
* succeeding only means it was queued, so resolving there would report a
|
|
30
|
+
* durable write that a later abort could still roll back.
|
|
31
|
+
*/
|
|
32
|
+
async function withStore(mode, fn) {
|
|
33
|
+
const db = await openDb(getConfig().cacheDbName);
|
|
34
|
+
try {
|
|
35
|
+
return await new Promise((resolve, reject) => {
|
|
36
|
+
const tx = db.transaction(STORE, mode);
|
|
37
|
+
const request = fn(tx.objectStore(STORE));
|
|
38
|
+
request.onerror = () => reject(request.error);
|
|
39
|
+
if (mode === "readonly") request.onsuccess = () => resolve(request.result);
|
|
40
|
+
else {
|
|
41
|
+
tx.oncomplete = () => resolve(request.result);
|
|
42
|
+
tx.onabort = () => reject(tx.error);
|
|
43
|
+
tx.onerror = () => reject(tx.error);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
} finally {
|
|
47
|
+
db.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const cacheAvailable = () => getConfig().cache === "indexeddb" && typeof indexedDB !== "undefined";
|
|
51
|
+
function cacheKey(spec, path) {
|
|
52
|
+
return `${spec.repo}@${spec.revision ?? "main"}/${path}`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve a repo-relative path to a URL under the configured model host.
|
|
56
|
+
*
|
|
57
|
+
* A path that is already absolute is returned untouched -- some catalogues
|
|
58
|
+
* (ppu-paddle-ocr's, for one) publish full URLs against their own host, and
|
|
59
|
+
* rewriting those against `modelHost` would point at files that do not exist.
|
|
60
|
+
*/
|
|
61
|
+
function fileUrl(spec, path) {
|
|
62
|
+
if (/^https?:\/\//.test(path)) return path;
|
|
63
|
+
const { modelHost } = getConfig();
|
|
64
|
+
const host = modelHost.replace(/\/+$/, "");
|
|
65
|
+
if (!/^https?:\/\/(?:[^/]*\.)?huggingface\.co/.test(host)) return `${host}/${spec.repo}/${path}`;
|
|
66
|
+
return `${host}/${spec.repo}/resolve/${spec.revision ?? "main"}/${path}`;
|
|
67
|
+
}
|
|
68
|
+
async function authHeaders(repo) {
|
|
69
|
+
const auth = getConfig().auth;
|
|
70
|
+
if (!auth) return void 0;
|
|
71
|
+
const token = await auth(repo);
|
|
72
|
+
return token ? { Authorization: `Bearer ${token}` } : void 0;
|
|
73
|
+
}
|
|
74
|
+
/** Fetch a URL as an ArrayBuffer, reporting each chunk's byte length. */
|
|
75
|
+
async function fetchWithProgress(url, headers, onChunk, signal) {
|
|
76
|
+
const response = await fetch(url, {
|
|
77
|
+
headers,
|
|
78
|
+
signal
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
81
|
+
if (!response.body) {
|
|
82
|
+
const buffer = await response.arrayBuffer();
|
|
83
|
+
onChunk(buffer.byteLength);
|
|
84
|
+
return buffer;
|
|
85
|
+
}
|
|
86
|
+
const reader = response.body.getReader();
|
|
87
|
+
const chunks = [];
|
|
88
|
+
let total = 0;
|
|
89
|
+
for (;;) {
|
|
90
|
+
const { done, value } = await reader.read();
|
|
91
|
+
if (done) break;
|
|
92
|
+
if (!value) continue;
|
|
93
|
+
chunks.push(value);
|
|
94
|
+
total += value.byteLength;
|
|
95
|
+
onChunk(value.byteLength);
|
|
96
|
+
}
|
|
97
|
+
const out = new Uint8Array(total);
|
|
98
|
+
let offset = 0;
|
|
99
|
+
for (const chunk of chunks) {
|
|
100
|
+
out.set(chunk, offset);
|
|
101
|
+
offset += chunk.byteLength;
|
|
102
|
+
}
|
|
103
|
+
return out.buffer;
|
|
104
|
+
}
|
|
105
|
+
/** Byte size from a HEAD request, falling back to the declared estimate. */
|
|
106
|
+
async function contentLength(url, headers, fallback) {
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
method: "HEAD",
|
|
110
|
+
headers
|
|
111
|
+
});
|
|
112
|
+
return Number(response.headers.get("content-length") ?? 0) || fallback;
|
|
113
|
+
} catch {
|
|
114
|
+
return fallback;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function isCached(spec) {
|
|
118
|
+
if (!cacheAvailable()) return false;
|
|
119
|
+
for (const file of spec.files) if (!await withStore("readonly", (s) => s.get(cacheKey(spec, file.path)))) return false;
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
async function evict(spec) {
|
|
123
|
+
if (!cacheAvailable()) return;
|
|
124
|
+
for (const file of spec.files) await withStore("readwrite", (s) => s.delete(cacheKey(spec, file.path)));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Ensure every file in `spec` is available, downloading and caching what is
|
|
128
|
+
* missing. Returns buffers keyed by repo-relative path.
|
|
129
|
+
*
|
|
130
|
+
* Progress is aggregate across the files still to fetch; already-cached files
|
|
131
|
+
* count as instantly complete.
|
|
132
|
+
*/
|
|
133
|
+
async function ensureModelFiles(spec, signal) {
|
|
134
|
+
const { onProgress } = getConfig();
|
|
135
|
+
const usable = cacheAvailable();
|
|
136
|
+
const result = {};
|
|
137
|
+
const missing = [];
|
|
138
|
+
for (const file of spec.files) {
|
|
139
|
+
const hit = usable ? await withStore("readonly", (s) => s.get(cacheKey(spec, file.path))) : void 0;
|
|
140
|
+
if (hit) result[file.path] = hit;
|
|
141
|
+
else missing.push(file);
|
|
142
|
+
}
|
|
143
|
+
if (missing.length === 0) {
|
|
144
|
+
onProgress?.({
|
|
145
|
+
repo: spec.repo,
|
|
146
|
+
file: "",
|
|
147
|
+
loaded: 0,
|
|
148
|
+
total: 0,
|
|
149
|
+
phase: "ready"
|
|
150
|
+
});
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
const headers = await authHeaders(spec.repo);
|
|
154
|
+
const total = (await Promise.all(missing.map((file) => file.approxBytes ? Promise.resolve(file.approxBytes) : contentLength(fileUrl(spec, file.path), headers, 0)))).reduce((sum, size) => sum + size, 0);
|
|
155
|
+
let loaded = 0;
|
|
156
|
+
for (const file of missing) {
|
|
157
|
+
const buffer = await fetchWithProgress(fileUrl(spec, file.path), headers, (bytes) => {
|
|
158
|
+
loaded += bytes;
|
|
159
|
+
onProgress?.({
|
|
160
|
+
repo: spec.repo,
|
|
161
|
+
file: file.path,
|
|
162
|
+
loaded,
|
|
163
|
+
total,
|
|
164
|
+
phase: "downloading"
|
|
165
|
+
});
|
|
166
|
+
}, signal);
|
|
167
|
+
if (usable) await withStore("readwrite", (s) => s.put(buffer, cacheKey(spec, file.path)));
|
|
168
|
+
result[file.path] = buffer;
|
|
169
|
+
}
|
|
170
|
+
onProgress?.({
|
|
171
|
+
repo: spec.repo,
|
|
172
|
+
file: "",
|
|
173
|
+
loaded: total,
|
|
174
|
+
total,
|
|
175
|
+
phase: "initializing"
|
|
176
|
+
});
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
//#endregion
|
|
180
|
+
export { isCached as a, fileUrl as i, ensureModelFiles as n, evict as r, cacheKey as t };
|
|
181
|
+
|
|
182
|
+
//# sourceMappingURL=model-cache-BEaqqRZ9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-cache-BEaqqRZ9.js","names":[],"sources":["../src/core/model-cache.ts"],"sourcesContent":["/**\n * Model file fetching with IndexedDB persistence and streaming progress.\n *\n * The pdftools prototype implements this twice -- once for GLiNER and once for\n * PaddleOCR -- differing only in where sizes come from and whether an auth\n * token is attached. Both behaviours are folded in here: sizes come from a HEAD\n * request (real percentages, rather than the hardcoded byte counts the GLiNER\n * copy used) with a declared `approxBytes` as fallback.\n */\n\nimport { getConfig, type ModelProgress } from './config.js'\n\nconst STORE = 'files'\nconst DB_VERSION = 1\n\nexport interface ModelFile {\n /** Repo-relative path, e.g. 'onnx/model_quantized.onnx'. */\n path: string\n /** Fallback size used for progress when the server sends no content-length. */\n approxBytes?: number\n}\n\nexport interface ModelSpec {\n /** Hugging Face repo id, e.g. 'onnx-community/gliner_multi_pii-v1'. */\n repo: string\n revision?: string\n files: ModelFile[]\n}\n\nexport type ModelFiles = Record<string, ArrayBuffer>\n\nfunction openDb(name: string): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(name, DB_VERSION)\n request.onupgradeneeded = () => {\n const db = request.result\n if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE)\n }\n request.onsuccess = () => resolve(request.result)\n request.onerror = () => reject(request.error)\n })\n}\n\n/**\n * Run one store operation.\n *\n * Writes resolve on transaction *commit*, not on request success -- a request\n * succeeding only means it was queued, so resolving there would report a\n * durable write that a later abort could still roll back.\n */\nasync function withStore<T>(\n mode: IDBTransactionMode,\n fn: (store: IDBObjectStore) => IDBRequest<T>\n): Promise<T> {\n const db = await openDb(getConfig().cacheDbName)\n try {\n return await new Promise<T>((resolve, reject) => {\n const tx = db.transaction(STORE, mode)\n const request = fn(tx.objectStore(STORE))\n request.onerror = () => reject(request.error)\n if (mode === 'readonly') {\n request.onsuccess = () => resolve(request.result)\n } else {\n tx.oncomplete = () => resolve(request.result)\n tx.onabort = () => reject(tx.error)\n tx.onerror = () => reject(tx.error)\n }\n })\n } finally {\n db.close()\n }\n}\n\nconst cacheAvailable = (): boolean => getConfig().cache === 'indexeddb' && typeof indexedDB !== 'undefined'\n\nexport function cacheKey(spec: ModelSpec, path: string): string {\n return `${spec.repo}@${spec.revision ?? 'main'}/${path}`\n}\n\n/**\n * Resolve a repo-relative path to a URL under the configured model host.\n *\n * A path that is already absolute is returned untouched -- some catalogues\n * (ppu-paddle-ocr's, for one) publish full URLs against their own host, and\n * rewriting those against `modelHost` would point at files that do not exist.\n */\nexport function fileUrl(spec: ModelSpec, path: string): string {\n if (/^https?:\\/\\//.test(path)) return path\n\n const { modelHost } = getConfig()\n const host = modelHost.replace(/\\/+$/, '')\n // A bare directory host (self-hosting) has no HF resolve/<revision> segment.\n if (!/^https?:\\/\\/(?:[^/]*\\.)?huggingface\\.co/.test(host)) {\n return `${host}/${spec.repo}/${path}`\n }\n return `${host}/${spec.repo}/resolve/${spec.revision ?? 'main'}/${path}`\n}\n\nasync function authHeaders(repo: string): Promise<HeadersInit | undefined> {\n const auth = getConfig().auth\n if (!auth) return undefined\n const token = await auth(repo)\n return token ? { Authorization: `Bearer ${token}` } : undefined\n}\n\n/** Fetch a URL as an ArrayBuffer, reporting each chunk's byte length. */\nasync function fetchWithProgress(\n url: string,\n headers: HeadersInit | undefined,\n onChunk: (bytes: number) => void,\n signal?: AbortSignal\n): Promise<ArrayBuffer> {\n const response = await fetch(url, { headers, signal })\n if (!response.ok) {\n throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`)\n }\n if (!response.body) {\n const buffer = await response.arrayBuffer()\n onChunk(buffer.byteLength)\n return buffer\n }\n\n const reader = response.body.getReader()\n const chunks: Uint8Array[] = []\n let total = 0\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (!value) continue\n chunks.push(value)\n total += value.byteLength\n onChunk(value.byteLength)\n }\n\n const out = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n out.set(chunk, offset)\n offset += chunk.byteLength\n }\n return out.buffer\n}\n\n/** Byte size from a HEAD request, falling back to the declared estimate. */\nasync function contentLength(\n url: string,\n headers: HeadersInit | undefined,\n fallback: number\n): Promise<number> {\n try {\n const response = await fetch(url, { method: 'HEAD', headers })\n return Number(response.headers.get('content-length') ?? 0) || fallback\n } catch {\n return fallback\n }\n}\n\nexport async function isCached(spec: ModelSpec): Promise<boolean> {\n if (!cacheAvailable()) return false\n for (const file of spec.files) {\n const hit = await withStore('readonly', (s) => s.get(cacheKey(spec, file.path)))\n if (!hit) return false\n }\n return true\n}\n\nexport async function evict(spec: ModelSpec): Promise<void> {\n if (!cacheAvailable()) return\n for (const file of spec.files) {\n await withStore('readwrite', (s) => s.delete(cacheKey(spec, file.path)))\n }\n}\n\n/**\n * Ensure every file in `spec` is available, downloading and caching what is\n * missing. Returns buffers keyed by repo-relative path.\n *\n * Progress is aggregate across the files still to fetch; already-cached files\n * count as instantly complete.\n */\nexport async function ensureModelFiles(spec: ModelSpec, signal?: AbortSignal): Promise<ModelFiles> {\n const { onProgress } = getConfig()\n const usable = cacheAvailable()\n const result: ModelFiles = {}\n const missing: ModelFile[] = []\n\n for (const file of spec.files) {\n const hit = usable\n ? await withStore<ArrayBuffer | undefined>('readonly', (s) => s.get(cacheKey(spec, file.path)))\n : undefined\n if (hit) result[file.path] = hit\n else missing.push(file)\n }\n\n if (missing.length === 0) {\n onProgress?.({ repo: spec.repo, file: '', loaded: 0, total: 0, phase: 'ready' })\n return result\n }\n\n const headers = await authHeaders(spec.repo)\n\n // Size everything up front so progress is a real percentage rather than a\n // byte count climbing toward an unknown ceiling.\n //\n // A declared `approxBytes` is used as-is: a HEAD costs a full round-trip per\n // file (and on Hugging Face it follows a redirect to the CDN), which doubles\n // the request count for a download that is already the slow part. Only\n // files with no estimate are probed, and those probes run together.\n const sizes = await Promise.all(\n missing.map((file) =>\n file.approxBytes\n ? Promise.resolve(file.approxBytes)\n : contentLength(fileUrl(spec, file.path), headers, 0)\n )\n )\n const total = sizes.reduce((sum, size) => sum + size, 0)\n\n let loaded = 0\n for (const file of missing) {\n const buffer = await fetchWithProgress(\n fileUrl(spec, file.path),\n headers,\n (bytes) => {\n loaded += bytes\n onProgress?.({\n repo: spec.repo,\n file: file.path,\n loaded,\n total,\n phase: 'downloading',\n })\n },\n signal\n )\n if (usable) {\n await withStore('readwrite', (s) => s.put(buffer, cacheKey(spec, file.path)))\n }\n result[file.path] = buffer\n }\n\n onProgress?.({ repo: spec.repo, file: '', loaded: total, total, phase: 'initializing' })\n return result\n}\n\nexport type { ModelProgress }\n"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/core/model-cache.d.ts
|
|
2
|
+
interface ModelFile {
|
|
3
|
+
/** Repo-relative path, e.g. 'onnx/model_quantized.onnx'. */
|
|
4
|
+
path: string;
|
|
5
|
+
/** Fallback size used for progress when the server sends no content-length. */
|
|
6
|
+
approxBytes?: number;
|
|
7
|
+
}
|
|
8
|
+
interface ModelSpec {
|
|
9
|
+
/** Hugging Face repo id, e.g. 'onnx-community/gliner_multi_pii-v1'. */
|
|
10
|
+
repo: string;
|
|
11
|
+
revision?: string;
|
|
12
|
+
files: ModelFile[];
|
|
13
|
+
}
|
|
14
|
+
type ModelFiles = Record<string, ArrayBuffer>;
|
|
15
|
+
declare function cacheKey(spec: ModelSpec, path: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a repo-relative path to a URL under the configured model host.
|
|
18
|
+
*
|
|
19
|
+
* A path that is already absolute is returned untouched -- some catalogues
|
|
20
|
+
* (ppu-paddle-ocr's, for one) publish full URLs against their own host, and
|
|
21
|
+
* rewriting those against `modelHost` would point at files that do not exist.
|
|
22
|
+
*/
|
|
23
|
+
declare function fileUrl(spec: ModelSpec, path: string): string;
|
|
24
|
+
declare function isCached(spec: ModelSpec): Promise<boolean>;
|
|
25
|
+
declare function evict(spec: ModelSpec): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Ensure every file in `spec` is available, downloading and caching what is
|
|
28
|
+
* missing. Returns buffers keyed by repo-relative path.
|
|
29
|
+
*
|
|
30
|
+
* Progress is aggregate across the files still to fetch; already-cached files
|
|
31
|
+
* count as instantly complete.
|
|
32
|
+
*/
|
|
33
|
+
declare function ensureModelFiles(spec: ModelSpec, signal?: AbortSignal): Promise<ModelFiles>;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { ensureModelFiles as a, isCached as c, cacheKey as i, ModelFiles as n, evict as o, ModelSpec as r, fileUrl as s, ModelFile as t };
|
|
36
|
+
//# sourceMappingURL=model-cache-BhFYpfZz.d.ts.map
|