unparser_shared/ai.rs
1//! VLM-based image understanding and AI-assisted markdown refine — active only when
2//! a caller supplies an [`AiConfig`]. Neither capability touches the network unless
3//! called explicitly; there is no ambient behavior change for a caller that never
4//! constructs a config.
5//!
6//! # The two capabilities
7//!
8//! | Capability | Input → output | Where a caller wires it |
9//! |---|---|---|
10//! | [`understand_image`] | image bytes → structured content or a description | The parsing stage, for an image whose surrounding text extraction produced nothing (or, at a caller's option, every embedded image) |
11//! | [`refine_markdown`] | markdown → markdown | Render post-processing, after [`crate::refine::refine`] (feature `refine`) if that runs too |
12//!
13//! # Why this lives here and not in `crate::refine` or the crate root
14//!
15//! The crate root ([`crate::ffi`], [`crate::kind`], [`crate::scaffold`]) is linked
16//! unconditionally by three published cdylibs and stays dependency-free by design —
17//! an HTTP client and JSON serialization do not belong there. [`crate::refine`]
18//! guarantees losslessness and idempotence for a deterministic pass; a generative
19//! call cannot honor either invariant, so it is a separate feature rather than a
20//! mode of that one.
21//!
22//! # Native only
23//!
24//! This feature is not available on `wasm32-unknown-unknown`: its HTTP client
25//! (`ureq`) does not build for that target. A browser caller would need `fetch` JS
26//! interop, which is not implemented here — see the crate's CI, which checks
27//! `refine` on wasm32 but does not attempt `ai` there.
28//!
29//! # What this module does not do
30//!
31//! It does not decide *which* images to send, or *when* a page's extracted text
32//! counts as "nothing" — those are domain judgments that belong to a caller
33//! (`unpdf`'s wiring, say), not to this crate. [`AiConfig::image_scope`] exists so a
34//! caller can carry that decision alongside the rest of the configuration; this
35//! module never reads it.
36
37mod config;
38mod error;
39mod http;
40mod image;
41mod refine;
42
43pub use config::{AiConfig, ImageScope};
44pub use error::Error;
45pub use image::{
46 understand_image, ContentBlock, ImageContext, ImageUnderstanding, TableBlock, TableCellBlock,
47};
48pub use refine::{refine_markdown, RefineAiOptions};