@@ -6,7 +6,7 @@ use oar_ocr::predictors::TableStructureRecognitionPredictor;
66use crate :: error:: ExtractError ;
77use crate :: formula:: FormulaPredictor ;
88use crate :: glm_ocr:: { GlmOcrConfig , GlmOcrPredictor } ;
9- use crate :: Quality ;
9+ use crate :: { FormulaModel , TableModel } ;
1010
1111/// Model file metadata for download.
1212struct ModelFile {
@@ -90,14 +90,14 @@ const SLANEXT_WIRED: ModelFile = ModelFile {
9090/// Resolved paths to all required model files.
9191pub struct ModelPaths {
9292 pub layout : PathBuf ,
93- pub slanet_plus : PathBuf ,
94- pub table_dict : PathBuf ,
95- pub formula_encoder : PathBuf ,
96- pub formula_decoder : PathBuf ,
97- pub formula_tokenizer : PathBuf ,
98- // Quality-mode extras
93+ pub slanet_plus : Option < PathBuf > ,
94+ pub table_dict : Option < PathBuf > ,
95+ pub formula_encoder : Option < PathBuf > ,
96+ pub formula_decoder : Option < PathBuf > ,
97+ pub formula_tokenizer : Option < PathBuf > ,
9998 pub table_classifier : Option < PathBuf > ,
10099 pub slanext_wired : Option < PathBuf > ,
100+ pub glm_ocr : Option < GlmOcrModelPaths > ,
101101}
102102
103103/// Resolved paths for GLM-OCR models (separate from pipeline models).
@@ -120,31 +120,50 @@ pub fn default_cache_dir() -> PathBuf {
120120 . join ( "models" )
121121}
122122
123- /// Ensure all models for the given quality mode are downloaded and return their paths .
123+ /// Ensure all models for the selected formula/table engines are downloaded.
124124pub fn ensure_models (
125- quality : Quality ,
125+ formula : FormulaModel ,
126+ table : TableModel ,
126127 cache_dir : & Path ,
127128) -> Result < ModelPaths , ExtractError > {
128129 std:: fs:: create_dir_all ( cache_dir) ?;
129130
130- // Always required
131+ // Layout detection is always required
131132 let layout = ensure_model ( cache_dir, & LAYOUT_MODEL ) ?;
132- let slanet_plus = ensure_model ( cache_dir, & SLANET_PLUS ) ?;
133- let table_dict = ensure_model ( cache_dir, & TABLE_DICT ) ?;
134- let formula_tokenizer = ensure_model ( cache_dir, & FORMULA_TOKENIZER ) ?;
135-
136- // Formula encoder/decoder (no auto-download, just check existence)
137- let formula_encoder = ensure_local_model ( cache_dir, & FORMULA_ENCODER ) ?;
138- let formula_decoder = ensure_local_model ( cache_dir, & FORMULA_DECODER ) ?;
139-
140- // Table models selected by --quality
141- let ( table_classifier, slanext_wired) = match quality {
142- Quality :: Fast => ( None , None ) ,
143- Quality :: Quality => {
133+
134+ // Formula models (only for pp-formulanet)
135+ let ( formula_encoder, formula_decoder, formula_tokenizer) = match formula {
136+ FormulaModel :: PpFormulanet => {
137+ let enc = ensure_local_model ( cache_dir, & FORMULA_ENCODER ) ?;
138+ let dec = ensure_local_model ( cache_dir, & FORMULA_DECODER ) ?;
139+ let tok = ensure_model ( cache_dir, & FORMULA_TOKENIZER ) ?;
140+ ( Some ( enc) , Some ( dec) , Some ( tok) )
141+ }
142+ FormulaModel :: GlmOcr => ( None , None , None ) ,
143+ } ;
144+
145+ // Table models (only for slanet variants)
146+ let ( slanet_plus, table_dict, table_classifier, slanext_wired) = match table {
147+ TableModel :: SlanetPlus => {
148+ let slanet = ensure_model ( cache_dir, & SLANET_PLUS ) ?;
149+ let dict = ensure_model ( cache_dir, & TABLE_DICT ) ?;
150+ ( Some ( slanet) , Some ( dict) , None , None )
151+ }
152+ TableModel :: SlanextWired => {
153+ let slanet = ensure_model ( cache_dir, & SLANET_PLUS ) ?;
154+ let dict = ensure_model ( cache_dir, & TABLE_DICT ) ?;
144155 let classifier = ensure_model ( cache_dir, & TABLE_CLASSIFIER ) ?;
145156 let wired = ensure_model ( cache_dir, & SLANEXT_WIRED ) ?;
146- ( Some ( classifier) , Some ( wired) )
157+ ( Some ( slanet ) , Some ( dict ) , Some ( classifier) , Some ( wired) )
147158 }
159+ TableModel :: GlmOcr => ( None , None , None , None ) ,
160+ } ;
161+
162+ // GLM-OCR models (needed if either formula or table uses glm-ocr)
163+ let glm_ocr = if formula == FormulaModel :: GlmOcr || table == TableModel :: GlmOcr {
164+ Some ( ensure_glm_ocr_models ( cache_dir) ?)
165+ } else {
166+ None
148167 } ;
149168
150169 Ok ( ModelPaths {
@@ -156,6 +175,7 @@ pub fn ensure_models(
156175 formula_tokenizer,
157176 table_classifier,
158177 slanext_wired,
178+ glm_ocr,
159179 } )
160180}
161181
@@ -393,21 +413,27 @@ fn platform_execution_providers() -> Vec<OrtExecutionProvider> {
393413pub fn build_formula_predictor (
394414 paths : & ModelPaths ,
395415) -> Result < FormulaPredictor , ExtractError > {
396- FormulaPredictor :: new (
397- & paths. formula_encoder ,
398- & paths. formula_decoder ,
399- & paths. formula_tokenizer ,
400- )
416+ let enc = paths. formula_encoder . as_ref ( )
417+ . ok_or_else ( || ExtractError :: Model ( "formula_encoder path missing" . into ( ) ) ) ?;
418+ let dec = paths. formula_decoder . as_ref ( )
419+ . ok_or_else ( || ExtractError :: Model ( "formula_decoder path missing" . into ( ) ) ) ?;
420+ let tok = paths. formula_tokenizer . as_ref ( )
421+ . ok_or_else ( || ExtractError :: Model ( "formula_tokenizer path missing" . into ( ) ) ) ?;
422+ FormulaPredictor :: new ( enc, dec, tok)
401423}
402424
403425/// Build a standalone table structure recognition predictor.
404426pub fn build_table_predictor (
405427 paths : & ModelPaths ,
406428) -> Result < TableStructureRecognitionPredictor , ExtractError > {
429+ let dict = paths. table_dict . as_ref ( )
430+ . ok_or_else ( || ExtractError :: Model ( "table_dict path missing" . into ( ) ) ) ?;
431+ let slanet = paths. slanet_plus . as_ref ( )
432+ . ok_or_else ( || ExtractError :: Model ( "slanet_plus path missing" . into ( ) ) ) ?;
407433 let config = ort_config ( ) ;
408434 TableStructureRecognitionPredictor :: builder ( )
409- . dict_path ( & paths . table_dict )
435+ . dict_path ( dict )
410436 . with_ort_config ( config)
411- . build ( & paths . slanet_plus )
437+ . build ( slanet )
412438 . map_err ( |e| ExtractError :: Model ( format ! ( "Failed to build table predictor: {e}" ) ) )
413439}
0 commit comments