Spaces:
Sleeping
Sleeping
Download doc_intelligence/src/extraction/proximity_extractor.py from vettri06/Document_intelligence: direct link, hf CLI and curl.
- Browser
- Download file 2.75 kB
-
https://huggingface.co/spaces/vettri06/Document_intelligence/resolve/main/doc_intelligence/src/extraction/proximity_extractor.py
- Command line
-
hf download hf://spaces/vettri06/Document_intelligence/doc_intelligence/src/extraction/proximity_extractor.py
-
curl -L -o proximity_extractor.py https://huggingface.co/spaces/vettri06/Document_intelligence/resolve/main/doc_intelligence/src/extraction/proximity_extractor.py
2.75 kB
| from typing import Dict, Any, List | |
| import numpy as np | |
| from ..data.schema import DocumentRecord, OCRWord, CLASS_FIELD_SCHEMAS | |
| class ProximityHeuristicsExtractor: | |
| """ | |
| Baseline B: Spatial Bounding-Box Proximity Extractor. | |
| Associates values located directly to the right or below target key words. | |
| """ | |
| def __init__(self): | |
| self.triggers = { | |
| "invoice_number": ["invoice", "inv", "number", "no", "#"], | |
| "invoice_date": ["date", "dated"], | |
| "total_amount": ["total", "due", "balance", "amount"], | |
| "company_name": ["store", "mart", "inc", "ltd", "cafe"], | |
| "date": ["date", "time"], | |
| "applicant_name": ["name", "applicant", "employee", "signature"], | |
| "address": ["address", "street", "city", "place"] | |
| } | |
| def _find_words_near(self, key_word: OCRWord, all_words: List[OCRWord], max_dx=300, max_dy=80) -> List[OCRWord]: | |
| kx0, ky0, kx1, ky1 = key_word.bbox | |
| candidates = [] | |
| for w in all_words: | |
| if w == key_word: | |
| continue | |
| wx0, wy0, wx1, wy1 = w.bbox | |
| # 1. Directly to the right (same line) | |
| is_right = (wx0 >= kx0) and (wx0 - kx1 <= max_dx) and (abs(wy0 - ky0) <= 25) | |
| # 2. Directly below (within column) | |
| is_below = (wy0 >= ky1) and (wy0 - ky1 <= max_dy) and (abs(wx0 - kx0) <= 100) | |
| if is_right or is_below: | |
| dist = np.sqrt((wx0 - kx1)**2 + (wy0 - ky0)**2) | |
| candidates.append((dist, w)) | |
| candidates.sort(key=lambda x: x[0]) | |
| return [c[1] for c in candidates] | |
| def extract(self, record: DocumentRecord, doc_class: str = None) -> Dict[str, Any]: | |
| cls_name = doc_class or record.doc_class | |
| schema_fields = CLASS_FIELD_SCHEMAS.get(cls_name, []) | |
| extracted = {f: None for f in schema_fields} | |
| all_words = record.ocr_words | |
| for field in schema_fields: | |
| trig_list = self.triggers.get(field, []) | |
| matched_key_word = None | |
| for w in all_words: | |
| w_lower = w.text.lower() | |
| if any(t in w_lower for t in trig_list): | |
| matched_key_word = w | |
| break | |
| if matched_key_word: | |
| near_words = self._find_words_near(matched_key_word, all_words) | |
| if near_words: | |
| # Collect tokens on same line | |
| val_tokens = [near_words[0].text] | |
| for nw in near_words[1:4]: | |
| if abs(nw.bbox[1] - near_words[0].bbox[1]) <= 20: | |
| val_tokens.append(nw.text) | |
| extracted[field] = " ".join(val_tokens) | |
| return extracted | |