Skip to content

Bug/148 hwp parsing error - #341

Merged
HeechanKim-Genon merged 4 commits into
developfrom
bug/148-hwp-parsing-error
Aug 6, 2026
Merged

Bug/148 hwp parsing error#341
HeechanKim-Genon merged 4 commits into
developfrom
bug/148-hwp-parsing-error

Conversation

@inoray

@inoray inoray commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

fix(#148): HWP 표 구조 회귀 테스트 추가 + 첨부용 markdown 표 compact 출력

개요

  • 한국투자공사 배포본(v1.7.4.1)에서 보고된 HWP 문서의 표가 최종 청크에 제대로 실리지 않는 버그([OCR] 파일적재용 전처리기 한글파일(hwp) 성능 개선 필요 #148) 에 대한 회귀 테스트를 추가한다.
    • 현재 버전 (v2.2.4)에서는 모두 정상처리 되고 있어서 정상처리되는 상황을 테스트에 반영했다.
  • 첨부용 전처리기의 markdown 표 출력을 compact(컬럼 정렬 패딩 제거) 형태로 바꿔 대형 표의 청크 크기를 줄인다.

배경 — 보고된 두 가지 증상

  1. 표 구조 유실 — 표 내부 텍스트만 평문으로 추출되어 행/열 관계가 사라진다.
    [별표 제3호] 숙박급지 표에서 말레이시아·브루나이·태국,필리핀 이 실제로는 병지인데
    AI 가 을지라고 오답했다.
  2. 가로 페이지 잘림 — landscape 페이지가 PDF 변환 시 잘려 표 오른쪽 열이 사라진다.
    "법인카드 사용내역이 청크에 없다"가 이 증상이다.

주요 변경

1) HWP 표 구조 회귀 테스트 신설 (핵심)

tests/regression/test_hwp_table_structure_regression.py — 테스트 9개.

두 전처리기는 HWP 처리 방식과 표 출력 형식이 달라 각각 검증한다.

첨부용 attachment 적재용 intelligent
HWP 처리 자체 개발 parser 로 직접 파싱 (PDF 변환 없음) rhwp 로 PDF 변환 후 dots.ocr 레이아웃 파싱
표 출력 markdown 파이프 표 HTML
실행 환경 CI 에서 실제 실행 rhwp + dots.ocr 엔드포인트 있을 때만
  • TestAttachmentHwpTableStructure (4개) — 표 청크 분할 여부, 별표3/별표4 구조, 표 개수 가드
  • TestIntelligentHwpTableStructure (4개) — HTML 직렬화, 별표3/별표4 구조, 별표4 행 레이블
  • test_rhwp_pdf_페이지_지오메트리 (1개) — 변환 단계 분리 검증

markdown/HTML 을 모두 "행 × 셀" 2차원 리스트로 정규화해 assert 로직을 한 벌만 두고
두 경로가 공유한다. golden 스냅샷이 아니라 의미 기반 assert 라 baseline 파일이 없다.

2) 첨부용 markdown 표 compact 출력

output.compact_tables(기본 true) 신설. markdown 표의 컬럼 정렬 패딩을 제거해 대형 표의
청크 크기를 줄인다. 표 내용은 동일하고 공백만 사라진다.

Summary by CodeRabbit

  • New Features

    • Markdown tables are now formatted compactly by default, reducing unnecessary spacing and output size.
    • Compact table formatting can be enabled or disabled through configuration and runtime options.
    • Improved table handling preserves structure across document processing and chunking workflows.
  • Bug Fixes

    • Improved preservation of HWP table rows, columns, headers, merged cells, and page geometry.
    • Added fallback behavior when compact table serialization cannot be applied.
  • Documentation

    • Documented the new compact table output setting and supported processing modes.

@inoray inoray self-assigned this Aug 6, 2026
@inoray inoray linked an issue Aug 6, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@inoray, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f4daf071-5157-485c-90ee-30869f5f5e59

📥 Commits

Reviewing files that changed from the base of the PR and between 931a940 and 265a0bb.

📒 Files selected for processing (3)
  • genon/preprocessor/facade/attachment_processor.py
  • genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py
  • genon/preprocessor/tests/unit/test_attachment_compact_tables_unit.py
📝 Walkthrough

Walkthrough

The attachment processor now supports compact Markdown table serialization by default. The setting propagates through recursive and hybrid processing, supports runtime overrides, and falls back to the existing exporter on errors. Unit and HWP regression tests cover output and table preservation.

Changes

Compact Markdown table serialization

Layer / File(s) Summary
Serialization and configuration flow
genon/preprocessor/facade/attachment_processor.py, genon/preprocessor/resource/*.yaml, genon/preprocessor/facade/gitbook_doc/attachment_processor.md
Adds compact_tables, propagates it through recursive DOCX and HWP processing, uses compact serialization with fallback, and documents the setting.
Compact output unit validation
genon/preprocessor/tests/unit/test_attachment_compact_tables_unit.py
Tests default and explicit formatting, cell preservation, fallback behavior, and configuration overrides.
HWP structure regression coverage
genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py, genon/.gitignore
Adds HWP table structure checks across processing paths and verifies converted PDF page geometry. Adds ignore rules for sample artifacts.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: heechankim-genon

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.62% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the HWP parsing issue addressed by the regression tests, but it does not mention the compact Markdown table change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/148-hwp-parsing-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@genon/preprocessor/facade/attachment_processor.py`:
- Line 1017: Parse and validate the compact_tables runtime override before the
selection at attachment_processor.py:1017-1017, rejecting invalid values and
interpreting "false" as False rather than applying bool() directly. Pass the
resulting Boolean through the DOCX and HWP recursive splitter calls at
attachment_processor.py:1455-1455 and attachment_processor.py:1661-1661. Add
unit coverage at
genon/preprocessor/tests/unit/test_attachment_compact_tables_unit.py:178-183 for
"false" and invalid runtime values.

In `@genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py`:
- Line 61: Update the whitespace normalization expressions in the affected test
helper to replace the raw non-breaking-space literals with the Unicode escape
"\u00a0", while preserving the existing replacement and stripping behavior and
resolving RUF001 warnings.
- Around line 463-468: Update the environment override logic around
GENOS_LAYOUT_ENDPOINT and GENOS_LAYOUT_API_KEY so an overridden endpoint is only
accepted when an API key is explicitly provided via GENOS_LAYOUT_API_KEY;
otherwise reject or fail the configuration instead of retaining the YAML
api_key. Preserve the existing behavior when no endpoint override is supplied.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e7092ddd-6fe4-484c-8e56-93357deb0330

📥 Commits

Reviewing files that changed from the base of the PR and between 3c96d7a and 931a940.

📒 Files selected for processing (8)
  • genon/.gitignore
  • genon/preprocessor/facade/attachment_processor.py
  • genon/preprocessor/facade/gitbook_doc/attachment_processor.md
  • genon/preprocessor/resource/attachment_processor_config.yaml
  • genon/preprocessor/resource_dev/attachment_processor_config.yaml
  • genon/preprocessor/sample_files/hwp_sample_table.hwp
  • genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py
  • genon/preprocessor/tests/unit/test_attachment_compact_tables_unit.py

Comment thread genon/preprocessor/facade/attachment_processor.py Outdated
Comment thread genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py Outdated
Comment on lines +463 to +468
endpoint = os.environ.get("GENOS_LAYOUT_ENDPOINT")
if endpoint:
genos_layout["endpoint"] = endpoint
api_key = os.environ.get("GENOS_LAYOUT_API_KEY")
if api_key is not None:
genos_layout["api_key"] = api_key

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not send the configured API key to an overridden endpoint.

If GENOS_LAYOUT_ENDPOINT is set and GENOS_LAYOUT_API_KEY is absent, this code retains the API key from resource_dev/intelligent_processor_config.yaml. It can send that key to the environment-supplied endpoint. Require an API key whenever the endpoint is overridden.

Proposed fix
     endpoint = os.environ.get("GENOS_LAYOUT_ENDPOINT")
-    if endpoint:
-        genos_layout["endpoint"] = endpoint
     api_key = os.environ.get("GENOS_LAYOUT_API_KEY")
-    if api_key is not None:
+    if endpoint:
+        if api_key is None:
+            raise RuntimeError(
+                "GENOS_LAYOUT_API_KEY is required when GENOS_LAYOUT_ENDPOINT is set"
+            )
+        genos_layout["endpoint"] = endpoint
         genos_layout["api_key"] = api_key
+    elif api_key is not None:
+        genos_layout["api_key"] = api_key
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
endpoint = os.environ.get("GENOS_LAYOUT_ENDPOINT")
if endpoint:
genos_layout["endpoint"] = endpoint
api_key = os.environ.get("GENOS_LAYOUT_API_KEY")
if api_key is not None:
genos_layout["api_key"] = api_key
endpoint = os.environ.get("GENOS_LAYOUT_ENDPOINT")
api_key = os.environ.get("GENOS_LAYOUT_API_KEY")
if endpoint:
if api_key is None:
raise RuntimeError(
"GENOS_LAYOUT_API_KEY is required when GENOS_LAYOUT_ENDPOINT is set"
)
genos_layout["endpoint"] = endpoint
genos_layout["api_key"] = api_key
elif api_key is not None:
genos_layout["api_key"] = api_key
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@genon/preprocessor/tests/regression/test_hwp_table_structure_regression.py`
around lines 463 - 468, Update the environment override logic around
GENOS_LAYOUT_ENDPOINT and GENOS_LAYOUT_API_KEY so an overridden endpoint is only
accepted when an API key is explicitly provided via GENOS_LAYOUT_API_KEY;
otherwise reject or fail the configuration instead of retaining the YAML
api_key. Preserve the existing behavior when no endpoint override is supplied.

@inoray
inoray requested a review from HeechanKim-Genon August 6, 2026 09:59
@HeechanKim-Genon
HeechanKim-Genon merged commit a5e8b62 into develop Aug 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[OCR] 파일적재용 전처리기 한글파일(hwp) 성능 개선 필요

2 participants