Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.onnx filter=lfs diff=lfs merge=lfs -text
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ model-archive/
*.pt
test_data/*

models/
models/*
!models/table-transformer-structure-recognition_fp16.onnx

**/.env
**/examples/
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added examples/sample-tables.pdf
Binary file not shown.
23 changes: 20 additions & 3 deletions ferrules-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ fn parse_ep_args(args: &Args) -> Vec<OrtExecutionProvider> {
#[tokio::main(flavor = "multi_thread")]
async fn main() {
let args = Args::parse();
if args.debug || std::env::var("RUST_LOG").is_ok() {
tracing_subscriber::fmt::init();
}

// Check providers
let providers = parse_ep_args(&args);
Expand All @@ -239,8 +242,6 @@ async fn main() {
inter_threads: args.inter_threads,
opt_level: args.graph_opt_level.map(|v| v.try_into().unwrap()),
};
// Global tasks
let parser = FerrulesParser::new(ort_config);

let page_range = match args.page_range {
Some(ref page_range_str) => match parse_page_range(page_range_str) {
Expand All @@ -263,10 +264,12 @@ async fn main() {
},
None => None,
};

let pb = setup_progress_bar(&args.file_path, None, page_range.clone());
let pbc = pb.clone();

// Global tasks
let parser = FerrulesParser::new(ort_config);

let doc_name = args
.file_path
.file_name()
Expand Down Expand Up @@ -440,6 +443,20 @@ async fn main() {
],
);
}
ferrules_core::error::FerrulesError::TableTransformerModelError(e) => {
format_error(
"Table Transformation Failed",
"Failed to process table using the vision model.",
vec![
("Error", e),
("File", args.file_path.display().to_string()),
(
"Suggestion",
"Check if the model files are present and valid.".to_string(),
),
],
);
}
}
std::process::exit(1);
}
Expand Down
3 changes: 2 additions & 1 deletion ferrules-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ itertools = "0.14.0"
futures = "0.3.31"
colored = "3.0.0"
dirs = "6.0.0"
half = "2.4.1"
anyhow = { workspace = true }
uuid = { workspace = true }
tracing = { workspace = true }
Expand Down Expand Up @@ -39,7 +40,7 @@ regex = "1.11.1"
html2md = "0.2.15"

[target.'cfg(target_os = "macos")'.dependencies]
ort = { version = "=2.0.0-rc.9", features = ["coreml", "fetch-models"] }
ort = { version = "=2.0.0-rc.9", features = ["coreml", "fetch-models", "half"] }
objc2 = { version = "^0.5.2" }
objc2-foundation = { version = "^0.2.2" }
objc2-vision = { version = "^0.2.2", features = [
Expand Down
60 changes: 57 additions & 3 deletions ferrules-core/src/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,46 @@ pub struct List {
pub(crate) items: Vec<String>,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub enum TableAlgorithm {
#[default]
Unknown,
Lattice,
Stream,
Vision,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TableBlock {
pub(crate) id: usize,
pub(crate) caption: Option<String>,
pub rows: Vec<TableRow>,
pub has_borders: bool,
pub algorithm: TableAlgorithm,
}

impl TableBlock {
pub(crate) fn path(&self) -> String {
format!("table_{}.png", self.id)
}
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TableRow {
pub cells: Vec<TableCell>,
pub is_header: bool,
pub bbox: BBox,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct TableCell {
pub content: Vec<Block>,
pub text: String,
pub row_span: u8,
pub col_span: u8,
pub bbox: BBox,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Title {
pub level: TitleLevel,
Expand All @@ -43,7 +83,7 @@ pub enum BlockType {
ListBlock(List),
TextBlock(TextBlock),
Image(ImageBlock),
Table,
Table(TableBlock),
}

impl std::fmt::Display for BlockType {
Expand Down Expand Up @@ -121,7 +161,21 @@ impl Block {
}
BlockType::Title(_title) => todo!(),
BlockType::Image(_image_block) => todo!(),
BlockType::Table => todo!(),
BlockType::Table(table) => {
if let ElementType::Table(incoming_table_opt) = &element.kind {
self.bbox.merge(&element.bbox);
if let Some(incoming_table) = incoming_table_opt {
table.rows.extend(incoming_table.rows.clone());
}
Ok(())
} else {
Err(FerrulesError::BlockMergeError {
element,
block_id: self.id,
kind: self.kind.clone(),
})
}
}
}
}

Expand All @@ -133,7 +187,7 @@ impl Block {
BlockType::Title(_) => "TITLE",
BlockType::ListBlock(_) => "LIST",
BlockType::Image(_) => "IMAGE",
BlockType::Table => "TABLE",
BlockType::Table(_) => "TABLE",
}
}
}
Loading
Loading