-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathCargo.toml
More file actions
152 lines (140 loc) · 7.16 KB
/
Copy pathCargo.toml
File metadata and controls
152 lines (140 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
[package]
name = "franken_ocr"
version = "0.7.2"
edition = "2024"
license = "LicenseRef-MIT-OpenAI-Anthropic-Rider"
description = "Pure-Rust, CPU-hyper-optimized runner for the Baidu Unlimited-OCR model (single-binary CLI: focr)"
readme = "README.md"
# Two binaries from one ENTRYPOINT (the shared `franken_ocr::cli_main` in the
# lib), but each from its OWN thin shim file so no source is shared across build
# targets (a file in two `[[bin]]` paths trips a cargo "present in multiple build
# targets" warning). The long name builds from `src/main.rs`; the short `focr`
# alias — the name agents and humans actually type — builds from
# `src/bin/focr.rs`. Both are one-line shims that just call `cli_main()`.
# Declaring them explicitly also disables the implicit package-named bin.
[[bin]]
name = "franken_ocr"
path = "src/main.rs"
[[bin]]
name = "focr"
path = "src/bin/focr.rs"
[dependencies]
clap = { version = "4.5", features = ["derive", "env"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
thiserror = "2"
anyhow = "1"
# ── Phase 1+ engine substrate (bd-223.1 + engine wiring). ──
# These mirror the PROVEN franken_whisper dep block (they are PROVEN to compile
# together there). See PROPOSED_ARCHITECTURE.md §2/§5 and the truth-pack spec.
#
# asupersync: orchestration/cancellation/IO only — the engine owns exactly one
# Runtime below the sync public API (plan §3.3). default-features=false keeps the
# surface minimal. The sibling ../asupersync checkout at 0.3.8 satisfies
# ">=0.3.5,<0.4".
asupersync = { version = ">=0.3.5, <0.4", default-features = false, features = [
"tls-webpki-roots",
] }
# Ctrl+C -> cooperative shutdown (bd-223.2): the CLI installs the handler; the
# library exposes request_shutdown() so embedders can drive it themselves.
ctrlc = "3.4"
# Physical-core count for the FOCR_THREADS budget (hyperthreads oversubscribe
# the int8 GEMMs — plan §7.5; logical count stays a robot diagnostic only).
num_cpus = "1.16"
# FrankenTorch compute kernels for the in-process native OCR engine: int8 dynamic
# linear (SDOT/VNNI), GEMM/sgemm, conv2d (im2col), sdpa, rms_norm, layer_norm.
ft-kernel-cpu = { path = "../frankentorch/crates/ft-kernel-cpu" }
# TensorMeta / DType / Device / Float16 — the meta types the kernel entrypoints take.
ft-core = { path = "../frankentorch/crates/ft-core" }
# Direct dep on `half` (the same crate ft-core re-exports as `Float16`) for its
# SIMD bulk f16->f32 dequant; `std` enables the runtime aarch64 fp16 / x86 f16c
# vector paths. Pinned to ft-core's major version.
half = { version = "2", features = ["std"] }
# Durable run state + telemetry on frankensqlite — NEVER rusqlite (plan §10).
fsqlite = { path = "../frankensqlite/crates/fsqlite" }
fsqlite-types = { path = "../frankensqlite/crates/fsqlite-types" }
# Image decode/resize/normalize/pad/tile — the preprocess front end (plan §6.2).
image = "0.25"
# Native PDF page rasterization (src/pdf.rs): `focr ocr file.pdf` extracts each
# page's image XObject and decodes it through the same pipeline a PNG takes — no
# out-of-band poppler/pdftoppm. `lopdf` is the container/xref/object/stream parser
# (pure Rust, no FFI); we write the image-codec dispatch ourselves. default-features
# are off to drop the date/serde/tokio surface (chrono/jiff/time/rayon) the
# scanned-image path never touches; the mandatory parser+crypto core stays.
lopdf = { version = "0.43", default-features = false }
# Pure-Rust CCITT Group 4 (T.6) fax decoder for bilevel scanned PDFs (the common
# black-and-white scan filter). Already in the lock graph; no FFI.
fax = "0.2"
# Bounded zlib inflate for the sole-FlateDecode image path (src/pdf.rs): lopdf's
# `Stream::decompressed_content` materializes the FULL inflated output before any
# length check, so a tiny "zip bomb" stream (KBs inflating to GBs) is an OOM/DoS
# vector. For a sole FlateDecode with no predictor we inflate it ourselves under an
# explicit cap and reject overruns. Already in the lock graph (via lopdf/png/tiff);
# declaring it a direct dep unifies on the same 1.x — no new crate, no FFI
# (pure-Rust miniz_oxide backend).
flate2 = "1"
# Data-parallel fan-out for the bespoke single-token (m=1) decode GEMV kernels
# (src/native_engine/decoder.rs `gemv`): the prefill GEMM is already threaded in
# ft-kernel-cpu, but the decode GEMV falls below its threading threshold and was
# running single-threaded. Already in the lock graph via ft-kernel-cpu.
rayon = "1"
# Provenance hashing for `focr convert`: the deterministic sha256 of the source
# safetensors shard, stamped into the `.focrq` header (`source_sha256`) so a
# converted artifact is traceable to its bf16 origin. Pure-Rust RustCrypto, no
# framework. Used by lib code (src/quant/convert.rs) — must be a normal dependency,
# not dev-only, or the lib fails to build outside the test profile.
sha2 = "0.10"
# RunStore run ids (bd-223.4).
uuid = { version = "1", features = ["v4"] }
# Currently-unwired opt-in: declaring the feature makes `#[cfg(feature =
# "mimalloc")]` in benches/support/perf_harness.rs a KNOWN cfg (no unexpected-cfg
# warning). Empty on purpose — no dependency is pulled in until the allocator is
# actually wired behind `--features mimalloc`.
# Opt-in read-only weight mmap (bd-2mo.22): `FOCR_MMAP=1` lets deployments with
# trusted immutable artifact inodes page multi-GB blobs lazily. Owned bytes are
# the safe default; the single unsafe map call lives in weights.rs's audited
# island.
memmap2 = "0.9"
[dev-dependencies]
# Property-based test plumbing (bd-10sb.1): generator-driven invariants for
# the SIMD==scalar / i32-overflow / preprocess-geometry / parser-robustness
# properties in tests/property_suite.rs. Dev-only — the shipping binary's
# dependency block is unchanged.
proptest = "1"
[features]
mimalloc = []
# The current asupersync 0.3.8 build input is not yet on crates.io (the index
# tops out at 0.3.6); it lives in the sibling `../asupersync` checkout.
# Patch crates-io to that path so the whole dependency graph —
# franken_ocr's direct dep AND the fsqlite/frankentorch path-deps that pin
# `0.3.4` — unifies on the single local 0.3.8 (which satisfies both ^0.3.4 and
# >=0.3.5,<0.4). One asupersync in the tree; no version skew.
[patch.crates-io]
asupersync = { path = "../asupersync" }
[lints.rust]
unsafe_code = "deny"
# Profiling build: full optimization + symbols/frame pointers so samplers
# (samply/Instruments) can attribute frames. NEVER profile the size-optimized
# `release` profile (strip=true → useless flamegraphs). See plan §9.1.
[profile.release-perf]
inherits = "release"
opt-level = 3
lto = "thin"
codegen-units = 1
debug = "line-tables-only"
strip = false
[profile.release]
opt-level = 3
lto = true
codegen-units = 1
panic = "abort"
strip = true
# Dev/test builds: keep OUR crate at opt-level 0 (fast rebuilds, full debug),
# but compile the kernel backend optimized — an unoptimized ft-kernel-cpu makes
# every real-geometry vision/decoder unit test ~50x slower (a single synthetic
# SigLIP forward took ~87s at opt0 vs ~2s at opt3). debug_assertions stay ON
# (the dev profile flag, independent of opt-level), and opt-level changes no
# IEEE semantics — no numerics drift vs release.
[profile.dev.package.ft-kernel-cpu]
opt-level = 3
debug-assertions = false