|
3 | 3 | //! The docling.rs counterpart of `docling.cli.main`; `docling-rs serve` |
4 | 4 | //! (with `--features serve`) starts the HTTP conversion API. |
5 | 5 | //! |
6 | | -//! Usage: docling-rs [--strict] [--to md|json] [--pages A-B] [--images MODE] [--fetch-images] [--no-stream] [--no-table-former] [--no-ocr] [--ocr-lang en|ch] [--asr-model PRESET] [--video-frames N] [--use-web-browser] [--enrich-picture-classes] [--enrich-code] [--enrich-formula] <input-file> |
| 6 | +//! Usage: docling-rs [--strict] [--to md|json] [--pages A-B] [--images MODE] [--fetch-images] [--no-stream] [--no-table-former] [--no-ocr] [--ocr-lang en|ch] [--pipeline standard|vlm] [--vlm-endpoint URL] [--vlm-model NAME] [--asr-model PRESET] [--video-frames N] [--use-web-browser] [--enrich-picture-classes] [--enrich-code] [--enrich-formula] <input-file> |
7 | 7 | //! --to md|json output format (default: md). `json` emits docling-core's |
8 | 8 | //! native DoclingDocument JSON (export_to_dict). |
9 | 9 | //! --pages A-B convert only PDF pages A through B (1-based, inclusive; |
@@ -95,6 +95,9 @@ fn main() -> ExitCode { |
95 | 95 | let mut bench_warm: Option<usize> = None; |
96 | 96 | let mut pages: Option<(usize, usize)> = None; |
97 | 97 | let mut ocr_lang: Option<String> = None; |
| 98 | + let mut pipeline: Option<String> = None; |
| 99 | + let mut vlm_endpoint: Option<String> = None; |
| 100 | + let mut vlm_model: Option<String> = None; |
98 | 101 | let mut path: Option<String> = None; |
99 | 102 | let mut args = std::env::args().skip(1); |
100 | 103 | while let Some(arg) = args.next() { |
@@ -145,6 +148,22 @@ fn main() -> ExitCode { |
145 | 148 | return ExitCode::from(2); |
146 | 149 | } |
147 | 150 | }, |
| 151 | + // Pipeline selection (#77): `standard` (default, the ML stack) or |
| 152 | + // `vlm` — render pages and convert them through a remote |
| 153 | + // OpenAI-compatible vision endpoint returning DocLang. |
| 154 | + "--pipeline" => match args.next() { |
| 155 | + Some(v) if matches!(v.trim(), "standard" | "vlm") => pipeline = Some(v), |
| 156 | + Some(v) => { |
| 157 | + eprintln!("error: --pipeline {v:?} is not standard|vlm"); |
| 158 | + return ExitCode::from(2); |
| 159 | + } |
| 160 | + None => { |
| 161 | + eprintln!("error: --pipeline needs a value (standard|vlm)"); |
| 162 | + return ExitCode::from(2); |
| 163 | + } |
| 164 | + }, |
| 165 | + "--vlm-endpoint" => vlm_endpoint = args.next(), |
| 166 | + "--vlm-model" => vlm_model = args.next(), |
148 | 167 | // Hidden benchmarking aid: load the PDF/image pipeline once, then time |
149 | 168 | // N warm conversions (models already loaded), printing the avg seconds |
150 | 169 | // per conversion to stdout. This is the startup-excluded counterpart to |
@@ -213,6 +232,29 @@ fn main() -> ExitCode { |
213 | 232 | }; |
214 | 233 | } |
215 | 234 |
|
| 235 | + // #77: the remote-VLM pipeline replaces the whole ML stack — convert, |
| 236 | + // then fall through to the regular output selection (md/json/dclx/chunks |
| 237 | + // all work; there is no page-streaming, the endpoint is the bottleneck). |
| 238 | + if pipeline.as_deref() == Some("vlm") { |
| 239 | + let mut opts = match docling::vlm::VlmOptions::resolve(vlm_endpoint, vlm_model) { |
| 240 | + Ok(o) => o, |
| 241 | + Err(e) => { |
| 242 | + eprintln!("error: {e}"); |
| 243 | + return ExitCode::from(2); |
| 244 | + } |
| 245 | + }; |
| 246 | + opts.page_range = pages; |
| 247 | + let mut document = match docling::vlm::convert_vlm(&source, &opts) { |
| 248 | + Ok(doc) => doc, |
| 249 | + Err(e) => { |
| 250 | + eprintln!("error: {e}"); |
| 251 | + return ExitCode::FAILURE; |
| 252 | + } |
| 253 | + }; |
| 254 | + document.strict_markdown = strict; |
| 255 | + return output_document(document, &to, image_mode, &path); |
| 256 | + } |
| 257 | + |
216 | 258 | let mut converter = DocumentConverter::new() |
217 | 259 | .strict(strict) |
218 | 260 | .asr_model(asr_model.clone()) |
@@ -281,7 +323,17 @@ fn main() -> ExitCode { |
281 | 323 | return ExitCode::FAILURE; |
282 | 324 | } |
283 | 325 | }; |
| 326 | + output_document(document, &to, image_mode, &path) |
| 327 | +} |
284 | 328 |
|
| 329 | +/// The buffered output tail shared by the standard (non-streaming) and VLM |
| 330 | +/// paths: `--to` selection, image sidecars, exit code. |
| 331 | +fn output_document( |
| 332 | + document: docling::DoclingDocument, |
| 333 | + to: &str, |
| 334 | + image_mode: ImageMode, |
| 335 | + path: &str, |
| 336 | +) -> ExitCode { |
285 | 337 | if to == "json" { |
286 | 338 | println!("{}", document.export_to_json()); |
287 | 339 | return ExitCode::SUCCESS; |
|
0 commit comments