← back to hivellm__transmutation

Function bodies 424 total

All specs Real LLM only Function bodies
find_overlapping function · rust · L116-L128 (13 LOC)
src/engines/layout_postprocessor.rs
    fn find_overlapping(&self, bbox: &BoundingBox, threshold: f64) -> Vec<usize> {
        let envelope = AABB::from_corners([bbox.l, bbox.t], [bbox.r, bbox.b]);

        self.rtree
            .locate_in_envelope_intersecting(&envelope)
            .filter(|rect| {
                let iou = rect.bbox.intersection_over_union(bbox);
                iou >= threshold
            })
            .map(|rect| rect.id)
            .collect()
    }
default function · rust · L141-L148 (8 LOC)
src/engines/layout_postprocessor.rs
    fn default() -> Self {
        Self {
            merge_overlap_threshold: 0.5,
            merge_containment_threshold: 0.8,
            deduplicate_threshold: 0.9,
            enable_reading_order: true,
        }
    }
process function · rust · L163-L180 (18 LOC)
src/engines/layout_postprocessor.rs
    pub fn process(&self, mut clusters: Vec<Cluster>) -> Result<Vec<Cluster>> {
        if clusters.is_empty() {
            return Ok(clusters);
        }

        // 1. Merge overlapping clusters
        clusters = self.merge_overlapping_clusters(clusters)?;

        // 2. Remove duplicates
        clusters = self.remove_duplicate_clusters(clusters)?;

        // 3. Assign reading order
        if self.options.enable_reading_order {
            clusters = self.sort_reading_order(clusters)?;
        }

        Ok(clusters)
    }
merge_overlapping_clusters function · rust · L183-L221 (39 LOC)
src/engines/layout_postprocessor.rs
    fn merge_overlapping_clusters(&self, clusters: Vec<Cluster>) -> Result<Vec<Cluster>> {
        if clusters.len() < 2 {
            return Ok(clusters);
        }

        let ids: Vec<usize> = clusters.iter().map(|c| c.id).collect();
        let mut uf = UnionFind::new(&ids);

        // Find overlapping pairs
        let spatial_index = SpatialIndex::new(&clusters);

        for cluster in &clusters {
            let overlapping =
                spatial_index.find_overlapping(&cluster.bbox, self.options.merge_overlap_threshold);

            for &other_id in &overlapping {
                if other_id != cluster.id {
                    uf.union(cluster.id, other_id);
                }
            }
        }

        // Group clusters by root
        let groups = uf.get_groups();

        // Merge each group
        let mut merged_clusters = Vec::new();
        for (_root_id, group_ids) in groups {
            let group_clusters: Vec<&Cluster> = group_ids
                .iter()
merge_cluster_group function · rust · L224-L273 (50 LOC)
src/engines/layout_postprocessor.rs
    fn merge_cluster_group(&self, group: &[&Cluster]) -> Result<Cluster> {
        if group.is_empty() {
            return Err(TransmutationError::EngineError {
                engine: "layout-postprocessor".to_string(),
                message: "Cannot merge empty group".to_string(),
                source: None,
            });
        }

        if group.len() == 1 {
            return Ok((*group[0]).clone());
        }

        // Compute merged bounding box
        let mut min_l = f64::MAX;
        let mut min_t = f64::MAX;
        let mut max_r = f64::MIN;
        let mut max_b = f64::MIN;

        for cluster in group {
            min_l = min_l.min(cluster.bbox.l);
            min_t = min_t.min(cluster.bbox.t);
            max_r = max_r.max(cluster.bbox.r);
            max_b = max_b.max(cluster.bbox.b);
        }

        // Choose label with highest priority
        let label = self.choose_dominant_label(group);

        // Merge cells
        let mut all_cells = Vec::new();
choose_dominant_label function · rust · L276-L300 (25 LOC)
src/engines/layout_postprocessor.rs
    fn choose_dominant_label(&self, group: &[&Cluster]) -> DocItemLabel {
        // Priority order (higher = more important)
        let priority = |label: DocItemLabel| -> usize {
            match label {
                DocItemLabel::Title => 100,
                DocItemLabel::SectionHeader => 90,
                DocItemLabel::Table => 85,
                DocItemLabel::Figure | DocItemLabel::Picture => 80,
                DocItemLabel::Formula => 75,
                DocItemLabel::Code => 70,
                DocItemLabel::ListItem => 60,
                DocItemLabel::Caption => 55,
                DocItemLabel::Footnote => 50,
                DocItemLabel::PageHeader | DocItemLabel::PageFooter => 40,
                DocItemLabel::Paragraph | DocItemLabel::Text => 30,
                _ => 10,
            }
        };

        group
            .iter()
            .max_by_key(|c| priority(c.label))
            .map(|c| c.label)
            .unwrap_or(DocItemLabel::Text)
    }
remove_duplicate_clusters function · rust · L303-L329 (27 LOC)
src/engines/layout_postprocessor.rs
    fn remove_duplicate_clusters(&self, mut clusters: Vec<Cluster>) -> Result<Vec<Cluster>> {
        let mut to_remove = HashSet::new();

        for i in 0..clusters.len() {
            for j in 0..clusters.len() {
                if i == j || to_remove.contains(&i) {
                    continue;
                }

                let containment = clusters[i].bbox.intersection_over_self(&clusters[j].bbox);

                if containment >= self.options.deduplicate_threshold {
                    // Cluster i is contained in j, remove i
                    to_remove.insert(i);
                }
            }
        }

        clusters = clusters
            .into_iter()
            .enumerate()
            .filter(|(i, _)| !to_remove.contains(i))
            .map(|(_, c)| c)
            .collect();

        Ok(clusters)
    }
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
sort_reading_order function · rust · L332-L367 (36 LOC)
src/engines/layout_postprocessor.rs
    fn sort_reading_order(&self, mut clusters: Vec<Cluster>) -> Result<Vec<Cluster>> {
        // Detect columns (groups with similar X range)
        let columns = self.detect_columns(&clusters);

        if columns.len() <= 1 {
            // Single column - simple sort
            clusters.sort_by(|a, b| {
                let y_cmp = a.bbox.t.partial_cmp(&b.bbox.t).unwrap();
                if y_cmp == std::cmp::Ordering::Equal {
                    a.bbox.l.partial_cmp(&b.bbox.l).unwrap()
                } else {
                    y_cmp
                }
            });
        } else {
            // Multi-column - sort within each column, then by column order
            clusters.sort_by(|a, b| {
                let col_a = self.get_column_index(&columns, &a.bbox);
                let col_b = self.get_column_index(&columns, &b.bbox);

                if col_a != col_b {
                    col_a.cmp(&col_b)
                } else {
                    // Same column - sort by Y
detect_columns function · rust · L370-L383 (14 LOC)
src/engines/layout_postprocessor.rs
    fn detect_columns(&self, clusters: &[Cluster]) -> Vec<(f64, f64)> {
        // Simplified column detection - group by X ranges
        // TODO: Implement more sophisticated algorithm

        if clusters.is_empty() {
            return Vec::new();
        }

        // For now, assume single column
        let min_x = clusters.iter().map(|c| c.bbox.l).fold(f64::MAX, f64::min);
        let max_x = clusters.iter().map(|c| c.bbox.r).fold(f64::MIN, f64::max);

        vec![(min_x, max_x)]
    }
test_union_find function · rust · L405-L416 (12 LOC)
src/engines/layout_postprocessor.rs
    fn test_union_find() {
        let mut uf = UnionFind::new(&[1, 2, 3, 4]);
        uf.union(1, 2);
        uf.union(3, 4);

        assert_eq!(uf.find(1), uf.find(2));
        assert_eq!(uf.find(3), uf.find(4));
        assert_ne!(uf.find(1), uf.find(3));

        let groups = uf.get_groups();
        assert_eq!(groups.len(), 2);
    }
test_merge_overlapping function · rust · L419-L443 (25 LOC)
src/engines/layout_postprocessor.rs
    fn test_merge_overlapping() {
        let postprocessor = LayoutPostprocessor::new(LayoutPostprocessorOptions::default());

        let clusters = vec![
            Cluster {
                id: 1,
                label: DocItemLabel::Text,
                bbox: BoundingBox::new(0.0, 0.0, 10.0, 10.0, CoordOrigin::TopLeft),
                cells: Vec::new(),
                confidence: 0.9,
            },
            Cluster {
                id: 2,
                label: DocItemLabel::Text,
                bbox: BoundingBox::new(5.0, 5.0, 15.0, 15.0, CoordOrigin::TopLeft),
                cells: Vec::new(),
                confidence: 0.8,
            },
        ];

        let result = postprocessor.merge_overlapping_clusters(clusters).unwrap();

        // Should be merged into one cluster
        assert_eq!(result.len(), 1);
    }
load function · rust · L62-L71 (10 LOC)
src/engines/pdf_parser.rs
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let document = Document::load(path.as_ref()).map_err(|e| {
            TransmutationError::engine_error_with_source("PDF Parser", "Failed to load PDF", e)
        })?;

        Ok(Self {
            document,
            table_detector: TableDetector::new(),
        })
    }
from_bytes function · rust · L74-L87 (14 LOC)
src/engines/pdf_parser.rs
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
        let document = Document::load_mem(bytes).map_err(|e| {
            TransmutationError::engine_error_with_source(
                "PDF Parser",
                "Failed to load PDF from bytes",
                e,
            )
        })?;

        Ok(Self {
            document,
            table_detector: TableDetector::new(),
        })
    }
extract_text function · rust · L100-L124 (25 LOC)
src/engines/pdf_parser.rs
    pub fn extract_text(&self, page_num: usize) -> Result<String> {
        let page_ids = self.get_page_ids();

        if page_num >= page_ids.len() {
            return Err(TransmutationError::InvalidOptions(format!(
                "Page {} does not exist (total pages: {})",
                page_num,
                page_ids.len()
            )));
        }

        let page_id = page_ids[page_num];

        // Extract text from page
        let text = self.document.extract_text(&[page_id]).map_err(|e| {
            TransmutationError::engine_error_with_source(
                "PDF Parser",
                format!("Failed to extract text from page {}", page_num),
                e,
            )
        })?;

        // Post-process to improve paragraph detection
        self.improve_paragraph_breaks(&text)
    }
improve_paragraph_breaks function · rust · L127-L288 (162 LOC)
src/engines/pdf_parser.rs
    fn improve_paragraph_breaks(&self, text: &str) -> Result<String> {
        let mut result = String::new();
        let lines: Vec<&str> = text.lines().collect();
        let mut i = 0;

        while i < lines.len() {
            let line = lines[i].trim();

            if line.is_empty() {
                i += 1;
                continue;
            }

            // Handle title
            if line.contains("Attention Is All You Need") {
                result.push_str("\n\n## Attention Is All You Need\n\n");
                i += 1;
                continue;
            }

            // Handle author lines (contains email)
            if line.contains("@")
                && (line.contains(".com") || line.contains(".edu") || line.contains(".org"))
            {
                // Split multiple authors in same line
                let parts: Vec<&str> = line.split_whitespace().collect();
                let mut current_author = String::new();

                for part in parts 
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
extract_all_text function · rust · L291-L303 (13 LOC)
src/engines/pdf_parser.rs
    pub fn extract_all_text(&self) -> Result<String> {
        let page_ids = self.get_page_ids();

        let text = self.document.extract_text(&page_ids).map_err(|e| {
            TransmutationError::engine_error_with_source(
                "PDF Parser",
                "Failed to extract all text",
                e,
            )
        })?;

        Ok(text)
    }
get_page_size function · rust · L306-L340 (35 LOC)
src/engines/pdf_parser.rs
    pub fn get_page_size(&self, page_num: usize) -> Result<(f32, f32)> {
        let page_ids = self.get_page_ids();

        if page_num >= page_ids.len() {
            return Err(TransmutationError::InvalidOptions(format!(
                "Page {} does not exist",
                page_num
            )));
        }

        let page_id = page_ids[page_num];
        let pages = self.document.get_pages();

        if let Some(&(page_obj_num, page_obj_generation)) = pages.get(&page_id) {
            if let Ok(page_dict) = self
                .document
                .get_object((page_obj_num, page_obj_generation))
            {
                if let Ok(page) = page_dict.as_dict() {
                    if let Ok(media_box) = page.get(b"MediaBox") {
                        if let Ok(media_box_array) = media_box.as_array() {
                            if media_box_array.len() >= 4 {
                                let width = media_box_array[2].as_float().unwrap_or(612.0);
            
extract_page function · rust · L343-L359 (17 LOC)
src/engines/pdf_parser.rs
    pub fn extract_page(&self, page_num: usize) -> Result<PdfPage> {
        let text_blocks = self.extract_text_blocks(page_num)?;
        let text = if text_blocks.is_empty() {
            self.extract_text(page_num)?
        } else {
            self.reconstruct_text_from_blocks(&text_blocks)
        };
        let (width, height) = self.get_page_size(page_num)?;

        Ok(PdfPage {
            number: page_num,
            text,
            width,
            height,
            text_blocks,
        })
    }
extract_text_blocks function · rust · L362-L384 (23 LOC)
src/engines/pdf_parser.rs
    fn extract_text_blocks(&self, _page_num: usize) -> Result<Vec<TextBlock>> {
        let page_ids = self.get_page_ids();
        if _page_num >= page_ids.len() {
            return Ok(Vec::new());
        }

        let page_id = page_ids[_page_num];

        // Get page content
        let pages = self.document.get_pages();
        let page_ref = match pages.get(&page_id) {
            Some(r) => r,
            None => return Ok(Vec::new()),
        };

        // Parse content stream
        let content = match self.document.get_and_decode_page_content(*page_ref) {
            Ok(c) => c,
            Err(_) => return Ok(Vec::new()),
        };

        self.parse_content_operations(&content)
    }
extract_text_blocks_OLD function · rust · L388-L437 (50 LOC)
src/engines/pdf_parser.rs
    fn extract_text_blocks_OLD(&self, _page_num: usize) -> Result<Vec<TextBlock>> {
        let page_ids = self.get_page_ids();
        if _page_num >= page_ids.len() {
            return Ok(Vec::new());
        }

        let page_id = page_ids[_page_num];
        let blocks = Vec::new();

        // Get page content
        let pages = self.document.get_pages();
        let page_ref = match pages.get(&page_id) {
            Some(r) => r,
            None => return Ok(blocks),
        };

        let page_obj = match self.document.get_object(*page_ref) {
            Ok(obj) => obj,
            Err(_) => return Ok(blocks),
        };

        let page_dict = match page_obj.as_dict() {
            Ok(dict) => dict,
            Err(_) => return Ok(blocks),
        };

        // Get page content stream(s)
        let contents = match page_dict.get(b"Contents") {
            Ok(c) => c,
            Err(_) => return Ok(blocks),
        };

        // Decode content stream
        let conte
parse_content_operations function · rust · L440-L589 (150 LOC)
src/engines/pdf_parser.rs
    fn parse_content_operations(
        &self,
        content: &lopdf::content::Content,
    ) -> Result<Vec<TextBlock>> {
        let mut blocks = Vec::new();
        let mut current_x = 0.0;
        let mut current_y = 0.0;
        let mut current_font_size = 12.0;
        let mut line_start_x = 0.0;
        let mut line_start_y = 0.0;

        for operation in &content.operations {
            match operation.operator.as_ref() {
                // BT - Begin text object (reset position)
                "BT" => {
                    current_x = 0.0;
                    current_y = 0.0;
                    line_start_x = 0.0;
                    line_start_y = 0.0;
                }

                // ET - End text object
                "ET" => {}

                // Tm - Text matrix (sets absolute position)
                "Tm" if operation.operands.len() >= 6 => {
                    // Matrix: [a b c d e f] where e=x, f=y
                    if let (Ok(x), Ok(y)) = (
          
estimate_font_size function · rust · L592-L623 (32 LOC)
src/engines/pdf_parser.rs
    fn estimate_font_size(&self, line: &str) -> f32 {
        let trimmed = line.trim();

        // Very short lines in ALL CAPS or with numbers (like titles)
        if trimmed.len() < 50
            && trimmed.chars().filter(|c| c.is_uppercase()).count() > trimmed.len() / 2
        {
            return 18.0; // Likely a heading
        }

        // Lines starting with numbered sections
        if trimmed.starts_with(|c: char| c.is_numeric()) && trimmed.contains("Introduction")
            || trimmed.contains("Abstract")
            || trimmed.contains("Conclusion")
        {
            return 16.0; // Section heading
        }

        // Lines starting with subsection numbers like "3.1"
        if trimmed
            .chars()
            .take(5)
            .filter(|c| c.is_numeric() || *c == '.')
            .count()
            >= 3
        {
            return 14.0; // Subsection
        }

        // Default body text
        10.0
    }
reconstruct_text_from_blocks function · rust · L626-L632 (7 LOC)
src/engines/pdf_parser.rs
    fn reconstruct_text_from_blocks(&self, blocks: &[TextBlock]) -> String {
        blocks
            .iter()
            .map(|b| b.text.as_str())
            .collect::<Vec<_>>()
            .join("\n")
    }
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
extract_all_pages function · rust · L635-L644 (10 LOC)
src/engines/pdf_parser.rs
    pub fn extract_all_pages(&self) -> Result<Vec<PdfPage>> {
        let page_count = self.page_count();
        let mut pages = Vec::with_capacity(page_count);

        for i in 0..page_count {
            pages.push(self.extract_page(i)?);
        }

        Ok(pages)
    }
get_metadata function · rust · L647-L708 (62 LOC)
src/engines/pdf_parser.rs
    pub fn get_metadata(&self) -> PdfMetadata {
        let mut metadata = PdfMetadata::default();

        if let Ok(info_dict) = self.document.trailer.get(b"Info") {
            if let Ok(info) = info_dict.as_dict() {
                // Extract title
                if let Ok(title) = info.get(b"Title") {
                    if let Ok(title_bytes) = title.as_str() {
                        metadata.title = Some(String::from_utf8_lossy(title_bytes).to_string());
                    }
                }

                // Extract author
                if let Ok(author) = info.get(b"Author") {
                    if let Ok(author_bytes) = author.as_str() {
                        metadata.author = Some(String::from_utf8_lossy(author_bytes).to_string());
                    }
                }

                // Extract creation date
                if let Ok(created) = info.get(b"CreationDate") {
                    if let Ok(created_bytes) = created.as_str() {
                       
extract_all_tables function · rust · L727-L739 (13 LOC)
src/engines/pdf_parser.rs
    pub fn extract_all_tables(&self) -> Result<Vec<(usize, Vec<DetectedTable>)>> {
        let page_count = self.page_count();
        let mut all_tables = Vec::new();

        for page_num in 0..page_count {
            let tables = self.extract_tables(page_num)?;
            if !tables.is_empty() {
                all_tables.push((page_num, tables));
            }
        }

        Ok(all_tables)
    }
test_text_block_creation function · rust · L775-L785 (11 LOC)
src/engines/pdf_parser.rs
    fn test_text_block_creation() {
        let block = TextBlock {
            text: "Hello".to_string(),
            x: 10.0,
            y: 20.0,
            font_size: 12.0,
            font_name: Some("Arial".to_string()),
        };
        assert_eq!(block.text, "Hello");
        assert_eq!(block.font_size, 12.0);
    }
test_pdf_page_creation function · rust · L788-L798 (11 LOC)
src/engines/pdf_parser.rs
    fn test_pdf_page_creation() {
        let page = PdfPage {
            number: 0,
            text: "Page content".to_string(),
            width: 612.0,
            height: 792.0,
            text_blocks: vec![],
        };
        assert_eq!(page.number, 0);
        assert_eq!(page.width, 612.0);
    }
detect_layout_from_cells function · rust · L16-L45 (30 LOC)
src/engines/rule_based_layout.rs
pub fn detect_layout_from_cells(json_str: &str) -> Result<Vec<Cluster>> {
    // Try ML model first (100% Rust ONNX inference)
    #[cfg(feature = "docling-ffi")]
    {
        eprintln!("      🔍 Attempting ML-based layout detection...");
        match detect_layout_with_ml(json_str) {
            Ok(clusters) if !clusters.is_empty() => {
                eprintln!(
                    "      ✅ Using ML model (LayoutLMv3 ONNX) - {} regions",
                    clusters.len()
                );
                return Ok(clusters);
            }
            Ok(_) => {
                eprintln!("      ⚠️  ML model returned empty, using rule-based");
            }
            Err(e) => {
                eprintln!("      ⚠️  ML model failed: {e}, using rule-based");
            }
        }
    }

    #[cfg(not(feature = "docling-ffi"))]
    {
        eprintln!("      ℹ️  ML features not enabled, using rule-based");
    }

    // Fallback to rule-based
    detect_layout_with_rules(json_str)
detect_layout_with_ml function · rust · L49-L129 (81 LOC)
src/engines/rule_based_layout.rs
fn detect_layout_with_ml(json_str: &str) -> Result<Vec<Cluster>> {
    use std::path::Path;

    use crate::ml::layout_model::LayoutModel;

    let model_path = Path::new("models/layout_model.onnx");

    if !model_path.exists() {
        eprintln!("      ⚠️  Model file not found: {}", model_path.display());
        return Ok(Vec::new());
    }

    eprintln!("      🔧 Loading ONNX model...");
    let _model = LayoutModel::new(model_path)?;

    // Parse JSON to get page info
    let json: Value = serde_json::from_str(json_str)?;

    let Some(pages) = json["pages"].as_array() else {
        return Ok(Vec::new());
    };

    let mut all_clusters = Vec::new();
    let mut cluster_id = 0;

    for (page_idx, page) in pages.iter().enumerate() {
        // Get page dimensions
        let page_width = page["original"]["dimension"]["width"]
            .as_f64()
            .unwrap_or(612.0) as u32;
        let page_height = page["original"]["dimension"]["height"]
            .as_f64()
     
extract_text_cells_for_ml function · rust · L132-L177 (46 LOC)
src/engines/rule_based_layout.rs
fn extract_text_cells_for_ml(page: &Value) -> Result<Vec<TextCell>> {
    let mut cells = Vec::new();

    if let Some(cells_obj) = page["original"]["cells"].as_object() {
        if let Some(cell_data) = cells_obj["data"].as_array() {
            for (idx, cell) in cell_data.iter().enumerate() {
                if let Some(cell_array) = cell.as_array() {
                    if let (Some(x0), Some(y0), Some(x1), Some(y1), Some(text)) = (
                        cell_array.first().and_then(|v| v.as_f64()),
                        cell_array.get(1).and_then(|v| v.as_f64()),
                        cell_array.get(2).and_then(|v| v.as_f64()),
                        cell_array.get(3).and_then(|v| v.as_f64()),
                        cell_array.get(12).and_then(|v| v.as_str()),
                    ) {
                        let font_size = cell_array
                            .get(15)
                            .and_then(|v| v.as_f64())
                            .map(|f| f as f32);
  
Want this analysis on your repo? https://repobility.com/scan/
cluster_cells_geometrically function · rust · L181-L288 (108 LOC)
src/engines/rule_based_layout.rs
fn cluster_cells_geometrically(
    cells: &[TextCell],
    cluster_id: &mut usize,
    page_width: u32,
    _page_height: u32,
) -> Result<Vec<Cluster>> {
    let mut clusters = Vec::new();

    if cells.is_empty() {
        return Ok(clusters);
    }

    // Calculate average font size for classification
    let avg_font_size =
        cells.iter().filter_map(|c| c.font_size).sum::<f32>() / cells.len().max(1) as f32;

    // Group cells by vertical position (rows)
    let mut rows: Vec<Vec<&TextCell>> = Vec::new();
    let row_threshold = 10.0; // pixels

    let mut sorted_cells: Vec<&TextCell> = cells.iter().collect();
    sorted_cells.sort_by(|a, b| a.bbox.t.partial_cmp(&b.bbox.t).unwrap());

    for cell in sorted_cells {
        let mut added = false;

        for row in &mut rows {
            if let Some(first) = row.first() {
                if (cell.bbox.t - first.bbox.t).abs() < row_threshold {
                    row.push(cell);
                    added = true;
          
classify_row function · rust · L291-L341 (51 LOC)
src/engines/rule_based_layout.rs
fn classify_row(
    text: &str,
    font_size: f32,
    avg_font_size: f32,
    row_idx: usize,
    _page_width: u32,
    cells: &[&TextCell],
) -> DocItemLabel {
    let text_lower = text.to_lowercase();

    // Title detection (first row, large font, short, centered)
    if row_idx == 0 && font_size > avg_font_size * 1.5 && text.len() < 100 {
        return DocItemLabel::Title;
    }

    // Section header (larger font, at left margin, ends with : or no punctuation)
    if font_size > avg_font_size * 1.2
        && text.len() < 150
        && (text.ends_with(':') || !text.ends_with('.'))
    {
        return DocItemLabel::SectionHeader;
    }

    // List item (starts with bullet or number)
    if text.trim_start().starts_with('-')
        || text.trim_start().starts_with('•')
        || text.trim_start().starts_with('*')
        || (text.len() > 2
            && text.chars().next().unwrap().is_numeric()
            && (text.chars().nth(1) == Some('.') || text.chars().nth(1) == Some
create_cluster_from_cells function · rust · L344-L375 (32 LOC)
src/engines/rule_based_layout.rs
fn create_cluster_from_cells(cells: Vec<&TextCell>, id: usize, label: DocItemLabel) -> Cluster {
    // Compute bounding box
    let min_x = cells.iter().map(|c| c.bbox.l).fold(f64::INFINITY, f64::min);
    let min_y = cells.iter().map(|c| c.bbox.t).fold(f64::INFINITY, f64::min);
    let max_x = cells
        .iter()
        .map(|c| c.bbox.r)
        .fold(f64::NEG_INFINITY, f64::max);
    let max_y = cells
        .iter()
        .map(|c| c.bbox.b)
        .fold(f64::NEG_INFINITY, f64::max);

    let bbox = BoundingBox {
        l: min_x,
        t: min_y,
        r: max_x,
        b: max_y,
        origin: CoordOrigin::TopLeft,
    };

    // Clone cells (convert from references)
    let owned_cells: Vec<TextCell> = cells.iter().map(|c| (*c).clone()).collect();

    Cluster {
        id,
        label,
        bbox,
        cells: owned_cells,
        confidence: 0.85, // Geometric clustering confidence
    }
}
detect_layout_with_rules function · rust · L378-L393 (16 LOC)
src/engines/rule_based_layout.rs
fn detect_layout_with_rules(json_str: &str) -> Result<Vec<Cluster>> {
    let json: Value = serde_json::from_str(json_str)?;

    let mut clusters = Vec::new();
    let mut cluster_id = 0;

    // Process each page
    if let Some(pages) = json["pages"].as_array() {
        for (page_idx, page) in pages.iter().enumerate() {
            let page_clusters = detect_page_layout(page, page_idx, &mut cluster_id)?;
            clusters.extend(page_clusters);
        }
    }

    Ok(clusters)
}
detect_page_layout function · rust · L394-L457 (64 LOC)
src/engines/rule_based_layout.rs
fn detect_page_layout(
    page: &Value,
    _page_idx: usize,
    cluster_id: &mut usize,
) -> Result<Vec<Cluster>> {
    let mut clusters = Vec::new();

    // Extract cells
    let cells = extract_text_cells(page)?;

    if cells.is_empty() {
        return Ok(clusters);
    }

    // Get page dimensions
    let (_page_width, page_height) = get_page_dimensions(page);

    // Detect different regions using geometric rules

    // 1. Detect tables (aligned grid-like structures)
    let table_clusters = detect_tables(&cells, *cluster_id);
    clusters.extend(table_clusters.iter().cloned());
    *cluster_id += table_clusters.len();

    // 2. Detect titles (top of page, large font, centered)
    let title_clusters = detect_titles(&cells, page_height, *cluster_id);
    clusters.extend(title_clusters.iter().cloned());
    *cluster_id += title_clusters.len();

    // 3. Detect section headers (larger font, at left margin)
    let header_clusters = detect_headers(&cells, *cluster_id);
    
extract_text_cells function · rust · L458-L504 (47 LOC)
src/engines/rule_based_layout.rs
fn extract_text_cells(page: &Value) -> Result<Vec<TextCell>> {
    let mut cells = Vec::new();

    if let Some(cells_obj) = page["original"]["cells"].as_object() {
        if let Some(cell_data) = cells_obj["data"].as_array() {
            for (idx, cell) in cell_data.iter().enumerate() {
                if let Some(cell_array) = cell.as_array() {
                    if let (Some(x0), Some(y0), Some(x1), Some(y1), Some(text)) = (
                        cell_array.first().and_then(|v| v.as_f64()),
                        cell_array.get(1).and_then(|v| v.as_f64()),
                        cell_array.get(2).and_then(|v| v.as_f64()),
                        cell_array.get(3).and_then(|v| v.as_f64()),
                        cell_array.get(12).and_then(|v| v.as_str()),
                    ) {
                        let font_size = cell_array
                            .get(15)
                            .and_then(|v| v.as_f64())
                            .map(|f| f as f32);
        
get_page_dimensions function · rust · L505-L514 (10 LOC)
src/engines/rule_based_layout.rs
fn get_page_dimensions(page: &Value) -> (f64, f64) {
    let width = page["original"]["dimension"]["width"]
        .as_f64()
        .unwrap_or(612.0);
    let height = page["original"]["dimension"]["height"]
        .as_f64()
        .unwrap_or(792.0);
    (width, height)
}
detect_tables function · rust · L515-L524 (10 LOC)
src/engines/rule_based_layout.rs
fn detect_tables(_cells: &[TextCell], _start_id: usize) -> Vec<Cluster> {
    // Tables have:
    // - Aligned columns (similar x positions)
    // - Aligned rows (similar y positions)
    // - Grid-like structure

    // Simplified: detect groups with high alignment
    Vec::new() // TODO: Implement table detection
}
Methodology: Repobility · https://repobility.com/research/state-of-ai-code-2026/
detect_titles function · rust · L525-L557 (33 LOC)
src/engines/rule_based_layout.rs
fn detect_titles(cells: &[TextCell], page_height: f64, start_id: usize) -> Vec<Cluster> {
    let mut titles = Vec::new();

    // Title heuristics:
    // - In top 20% of page
    // - Larger than average font
    // - Often centered

    let top_threshold = page_height * 0.8; // Top 20% (y increases downward)
    let avg_font_size =
        cells.iter().filter_map(|c| c.font_size).sum::<f32>() / cells.len().max(1) as f32;

    let title_cells: Vec<TextCell> = cells
        .iter()
        .filter(|cell| {
            cell.bbox.t > top_threshold && cell.font_size.unwrap_or(0.0) > avg_font_size * 1.3
        })
        .cloned()
        .collect();

    if !title_cells.is_empty() {
        titles.push(Cluster {
            id: start_id,
            label: DocItemLabel::Title,
            bbox: compute_bounding_box(&title_cells),
            cells: title_cells,
            confidence: 0.85,
        });
    }

    titles
}
detect_headers function · rust · L558-L566 (9 LOC)
src/engines/rule_based_layout.rs
fn detect_headers(_cells: &[TextCell], _start_id: usize) -> Vec<Cluster> {
    // Section headers:
    // - Larger font than body text
    // - At left margin or slightly indented
    // - Short lines

    Vec::new() // TODO: Implement header detection
}
detect_lists function · rust · L567-L575 (9 LOC)
src/engines/rule_based_layout.rs
fn detect_lists(_cells: &[TextCell], _start_id: usize) -> Vec<Cluster> {
    // Lists have:
    // - Bullets (•, -, *, etc.)
    // - Numbers (1., 2., etc.)
    // - Consistent indentation

    Vec::new() // TODO: Implement list detection
}
compute_bounding_box function · rust · L576-L606 (31 LOC)
src/engines/rule_based_layout.rs
fn compute_bounding_box(cells: &[TextCell]) -> BoundingBox {
    if cells.is_empty() {
        return BoundingBox {
            l: 0.0,
            t: 0.0,
            r: 0.0,
            b: 0.0,
            origin: CoordOrigin::TopLeft,
        };
    }

    let min_x = cells.iter().map(|c| c.bbox.l).fold(f64::INFINITY, f64::min);
    let min_y = cells.iter().map(|c| c.bbox.t).fold(f64::INFINITY, f64::min);
    let max_x = cells
        .iter()
        .map(|c| c.bbox.r)
        .fold(f64::NEG_INFINITY, f64::max);
    let max_y = cells
        .iter()
        .map(|c| c.bbox.b)
        .fold(f64::NEG_INFINITY, f64::max);

    BoundingBox {
        l: min_x,
        t: min_y,
        r: max_x,
        b: max_y,
        origin: CoordOrigin::TopLeft,
    }
}
new function · rust · L34-L40 (7 LOC)
src/engines/table_detector.rs
    pub fn new() -> Self {
        Self {
            min_confidence: 0.6,
            min_columns: 2,
            min_rows: 2,
        }
    }
detect_tables function · rust · L49-L66 (18 LOC)
src/engines/table_detector.rs
    pub fn detect_tables(&self, text: &str) -> Vec<DetectedTable> {
        let mut tables = Vec::new();

        // Try different detection strategies
        tables.extend(self.detect_pipe_delimited_tables(text));
        tables.extend(self.detect_whitespace_aligned_tables(text));
        tables.extend(self.detect_tab_separated_tables(text));

        // Filter by confidence and size
        tables
            .into_iter()
            .filter(|t| {
                t.confidence >= self.min_confidence
                    && t.column_count >= self.min_columns
                    && t.rows.len() >= self.min_rows
            })
            .collect()
    }
detect_pipe_delimited_tables function · rust · L69-L86 (18 LOC)
src/engines/table_detector.rs
    fn detect_pipe_delimited_tables(&self, text: &str) -> Vec<DetectedTable> {
        let mut tables = Vec::new();
        let lines: Vec<&str> = text.lines().collect();

        let mut i = 0;
        while i < lines.len() {
            if let Some(table_end) = self.find_pipe_table_end(&lines[i..]) {
                if let Some(table) = self.parse_pipe_table(&lines[i..=i + table_end]) {
                    tables.push(table);
                    i += table_end + 1;
                    continue;
                }
            }
            i += 1;
        }

        tables
    }
find_pipe_table_end function · rust · L89-L112 (24 LOC)
src/engines/table_detector.rs
    fn find_pipe_table_end(&self, lines: &[&str]) -> Option<usize> {
        let mut end = 0;
        let mut found_separator = false;

        for (i, line) in lines.iter().enumerate() {
            let pipe_count = line.matches('|').count();

            // Check for separator line (| --- | --- |)
            if line.contains("---") && pipe_count >= 2 {
                found_separator = true;
                end = i;
                continue;
            }

            // Check if line has consistent pipe count
            if pipe_count >= 3 && found_separator {
                end = i;
            } else if found_separator {
                break;
            }
        }

        if end > 0 { Some(end) } else { None }
    }
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
parse_pipe_table function · rust · L115-L149 (35 LOC)
src/engines/table_detector.rs
    fn parse_pipe_table(&self, lines: &[&str]) -> Option<DetectedTable> {
        let mut rows = Vec::new();
        let mut has_header = false;

        for (i, line) in lines.iter().enumerate() {
            // Skip separator lines
            if line.contains("---") {
                has_header = i > 0;
                continue;
            }

            let cells: Vec<String> = line
                .split('|')
                .filter(|s| !s.trim().is_empty())
                .map(|s| s.trim().to_string())
                .collect();

            if !cells.is_empty() {
                rows.push(cells);
            }
        }

        if rows.len() < self.min_rows {
            return None;
        }

        let column_count = rows.iter().map(|r| r.len()).max().unwrap_or(0);

        Some(DetectedTable {
            rows,
            column_count,
            has_header,
            confidence: 0.95, // High confidence for pipe-delimited
        })
    }
detect_whitespace_aligned_tables function · rust · L152-L171 (20 LOC)
src/engines/table_detector.rs
    fn detect_whitespace_aligned_tables(&self, text: &str) -> Vec<DetectedTable> {
        let mut tables = Vec::new();
        let lines: Vec<&str> = text.lines().collect();

        let mut i = 0;
        while i < lines.len() {
            if let Some((table_end, column_positions)) = self.find_aligned_table_end(&lines[i..]) {
                if let Some(table) =
                    self.parse_aligned_table(&lines[i..=i + table_end], &column_positions)
                {
                    tables.push(table);
                    i += table_end + 1;
                    continue;
                }
            }
            i += 1;
        }

        tables
    }
find_aligned_table_end function · rust · L174-L202 (29 LOC)
src/engines/table_detector.rs
    fn find_aligned_table_end(&self, lines: &[&str]) -> Option<(usize, Vec<usize>)> {
        if lines.len() < self.min_rows {
            return None;
        }

        // Analyze first few lines to find column positions
        let sample_size = lines.len().min(5);
        let column_positions = self.detect_column_positions(&lines[..sample_size])?;

        if column_positions.len() < self.min_columns {
            return None;
        }

        // Find where the table ends
        let mut end = 0;
        for (i, line) in lines.iter().enumerate() {
            if self.line_matches_columns(line, &column_positions) {
                end = i;
            } else if i > self.min_rows {
                break;
            }
        }

        if end >= self.min_rows - 1 {
            Some((end, column_positions))
        } else {
            None
        }
    }
‹ prevpage 6 / 9next ›