Visual parsing v2
Visual parsing v2
이 문서는 이슈 #14의 PDF/image visual parsing v2 경로를 설명한다. 기존 공개 baseline(eval/fixtures/smoke_rfp/raw)과 CSV-text v1 ingestion은 기본 동작으로 유지한다.
목적
- 원본 PDF/이미지에서 text, page, bbox, region metadata를 함께 추출한다.
- parser artifact를 기존 RAG document schema로 정규화해 chunking, retrieval, citation 흐름에서 재사용한다.
- HWP는 이번 단계에서 native visual parsing을 하지 않고 CSV 텍스트 fallback으로 비교 가능성을 유지한다.
What this is NOT
이 파이프라인이 하지 않는 것을 명확히 라벨링한다 (reviewer 오해 방지용 — 이 섹션이 ground truth):
- Layout-aware vision foundation model을 사용하지 않는다. LayoutLMv3 / Donut / ColPali / Nougat / pix2struct 같은 vision-language 모델은
visual_ingestion.py에 import되지 않으며, 표/제목/본문 구분은 pdfplumber의 통계적 table detection과 PyMuPDF text block heuristic + pytesseract OCR fallback 조합에만 의존한다. vision foundation model과의 1-page 비교 spike는 후속 단계 항목. - HWP를 native parse하지 않는다.
pyhwp/hwp5html/olefile을 import하지 않으며, HWP 본문은 사용자가 사전에data_list.csv의텍스트컬럼에 추출해 둔 텍스트를 사용한다 (visual_fallback_hwp마커). native HWP parser spike는 후속 단계 항목. - End-to-end vision quality ablation을 제공하지 않는다. 현재 단계의 측정은 OCR text recall, layout block precision/recall, table cell F1, field key-value precision 같은 parser-stage 지표(
reports/parser_eval_summary.json)에 한정된다. layout-aware 모델과의 정량 비교는 별도 spike에서 다룬다.
입력
--visual_input_dir: PDF 또는 이미지(pdf,png,jpg,jpeg,tif,tiff,bmp,webp) 파일 디렉터리.--metadata_csv --files_dir --ingestion_mode visual: 기존data_list.csv메타데이터를 사용하되 PDF/image는 v2 parser로 처리하고 HWP는 v1 텍스트 fallback으로 처리한다.--visual_artifact_dir: v2 artifact 저장 위치. 생략하면<output_dir>/visual_artifacts를 사용한다.
출력
index.json: 기존 RAG index schema를 유지하면서 section/chunk/evidence/citation에regions와page_span을 선택적으로 포함한다.ingestion_report.json: 문서별parsed,partial,fallback,failed상태와 실패 사유를 기록한다.*.visual.json:schema_version: 2artifact.pages[*].blocks[*],tables,field_candidates,sections,diagnostics를 포함한다.parser_eval_summary.json: parser-stage gold와 artifact를 비교한 OCR/layout/section/table/field/bbox 평가 리포트다.
Parser stages
- PDF text layer: PyMuPDF로 page block, bbox, layout type을 추출한다.
- OCR: PDF page text가 부족하거나 이미지 입력일 때 OCR adapter를 호출한다.
- Table candidates: pdfplumber table 추출과 layout text heuristic을 함께 사용한다.
- Field candidates:
key: value,key=value형태의 line을 후보로 기록한다. - Section detection: heading-like block을 section boundary로 사용하고, 없으면 문서 전체 section으로 묶는다.
Failure policy
pdf_parser_unavailable: PyMuPDF를 사용할 수 없어 PDF를 열 수 없음.ocr_unavailable: pytesseract 또는 시스템 Tesseract 실행이 불가능함.empty_visual_text: text layer와 OCR 모두에서 인덱싱 가능한 text가 없음.visual_fallback_hwp: HWP native visual parsing은 후속 과제로 남기고 CSV텍스트컬럼을 사용함.
OCR 품질은 자동으로 개선되었다고 간주하지 않는다. v2의 1차 성공 기준은 page/bbox region artifact 생성, 기존 retrieval 호환성, v1/v2 비교 가능성이다.
Parser-stage evaluation
QA end-to-end 지표만으로는 parser 품질 저하가 retrieval 문제인지, OCR/layout/table/field 단계 문제인지 분리하기 어렵다. eval/run_parser_eval.py는 이미 생성된 *.visual.json artifact를 gold YAML과 비교해 parser 단계별 지표를 독립적으로 기록한다.
python3 eval/run_parser_eval.py \
--artifact_dir eval/fixtures/parser_visual_v2 \
--gold eval/parser_visual_v2_gold.yaml \
--output_dir reports \
--run_name visual_v2_fixture \
--parser_version 2
실제 visual ingestion 결과를 비교할 때는 --artifact_dir data/index/visual_artifacts를 사용하고, gold의 doc_id와 artifact 파일명을 해당 run에 맞춘다. report schema는 eval/parser_metrics.schema.json에 둔다.
주요 지표는 다음과 같다.
- OCR: gold text snippet recall과 normalized char-F1 proxy.
- Layout: block text/type/page 기준 precision, recall, F1.
- Section: heading과
page_span기준 boundary recall. - Table: cell, row, column-count reconstruction F1.
- Field: key-value candidate precision, recall, F1.
- Bbox/page-region: anchor block의 bbox 존재율과, gold bbox가 있을 때 IoU threshold 충족률.
QA 단계에서는 eval/run_eval.py의 선택 gold 필드(expected_citation_pages, expected_citation_regions)로 citation이 올바른 page/region을 가리키는지 추가 평가할 수 있다. 자세한 기준과 drift 예시는 citation-grounding-eval.md에 둔다.
실패 taxonomy는 ocr_missing_text, layout_type_mismatch, section_boundary_missing, table_cell_mismatch, field_missing, field_value_mismatch, bbox_missing, bbox_misaligned를 포함한다. 이 코드는 downstream 분석에서 retrieval miss, noisy chunking, wrong field grounding, weak bbox citation 같은 QA 실패 원인과 연결한다.
private hard-case gold에는 문서별 hardcase_categories를 둘 수 있다. eval/run_parser_eval.py는 summary.by_hardcase_category를 생성해 scanned PDF, rotated/skewed, table-heavy, mixed-layout, noisy OCR 조건별 parser metric과 failure count를 분리한다. 비공개 원문과 raw artifact는 커밋하지 않고 aggregate만 docs/real-data/private-hardcase-benchmark.md 방식으로 기록한다.
실행 예시
python3 scripts/build_index.py \
--visual_input_dir data/visual_samples \
--output_dir data/index \
--embedding_backend hashing
python3 scripts/build_index.py \
--metadata_csv data/data_list.csv \
--files_dir data/files \
--ingestion_mode visual \
--output_dir data/index \
--embedding_backend hashing
검증
기본 회귀는 기존과 동일하게 유지한다.
python3 -m unittest discover -s tests -q
python3 scripts/build_index.py --input_dir eval/fixtures/smoke_rfp/raw --output_dir /private/tmp/agentic-vlm-index --embedding_backend hashing
python3 app.py --input_dir /private/tmp/agentic-vlm-index --output_dir /private/tmp/agentic-vlm-outputs --query "기관 A와 기관 B의 AI 요구사항 차이 알려줘"
python3 eval/run_eval.py --index_dir /private/tmp/agentic-vlm-index --output_dir /private/tmp/agentic-vlm-reports --config eval/config.yaml
python3 eval/run_parser_eval.py --artifact_dir eval/fixtures/parser_visual_v2 --gold eval/parser_visual_v2_gold.yaml --output_dir /private/tmp/agentic-vlm-parser-reports --run_name visual_v2_fixture --parser_version 2
python3 scripts/update_readme_metrics.py --report reports/eval_summary.json --readme README.md --check