fix(attachment): TextLoader 긴 한 줄 txt/json/md 청킹 잘림 수정 (#333) - #334
Hidden character warning
Conversation
<pre> 기본값(white-space: pre)이 자동 줄바꿈을 하지 않아 A4 폭을 넘는 긴 줄이 weasyprint 렌더 단계에서 잘려(discard) PDF·청킹에서 누락되던 문제 수정. - white-space: pre-wrap 으로 원문 유지 + 폭 초과 시 자동 줄바꿈 - overflow-wrap: anywhere 로 공백 없는 초장문도 강제 개행 - html.escape 로 <, & 태그 오해석에 의한 텍스트 유실 방지 - 로컬 변수 html → html_doc 개명(신규 html 모듈 충돌 회피) - 이슈 #333 회귀 유닛 테스트 추가(txt/json 끝 토큰 보존, 특수문자 escape) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Warning Review limit reached
Next review available in: 30 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesTextLoader long-line preservation
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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/tests/unit/test_attachment_textloader_long_line_333.py`:
- Around line 85-98: Update test_html_special_chars_preserved to assert that the
normalized extracted text retains the literal markers "<b>", "</b>", "a<b", and
"&", or compare against the fully normalized expected content; keep the existing
token-preservation checks as appropriate.
- Around line 65-69: Extend the long-line fixture around head, tail_token, and
content with a sufficiently long space-free token, and assert that this token’s
tail is present in the extracted PDF text. Keep the existing spaced-content
coverage while ensuring the new assertion exercises overflow-wrap: anywhere for
identifier-like strings.
- Around line 32-37: Update _has_weasyprint to catch only the expected
missing-dependency import exception for optional WeasyPrint availability,
allowing other import failures such as transitive or CFFI errors to propagate
instead of returning False.
🪄 Autofix (Beta)
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: 4d11d15d-174c-433f-9fe2-e85a8a4811a6
📒 Files selected for processing (2)
genon/preprocessor/facade/attachment_processor.pygenon/preprocessor/tests/unit/test_attachment_textloader_long_line_333.py
| def test_html_special_chars_preserved(tmp_path: Path): | ||
| """<, & 등 HTML 특수문자가 태그로 해석돼 뒤 텍스트가 유실되지 않아야 한다(html.escape).""" | ||
| _get_pdf_path, TextLoader = _import_processor() | ||
|
|
||
| # escape 없으면 '<b>' 이후 '중요' 는 태그로 먹히고, 'a<b 그리고 ... ' 도 유실됨. | ||
| content = "머리말 <b>중요구절</b> 그리고 조건 a<b 이고 기호 & 앰퍼샌드 끝토큰ESCAPE333" | ||
|
|
||
| txt = tmp_path / "special_chars.txt" | ||
| txt.write_text(content, encoding="utf-8") | ||
|
|
||
| norm = _norm(_extract_text(TextLoader(str(txt)))) | ||
|
|
||
| for token in ("중요구절", "앰퍼샌드", "끝토큰ESCAPE333"): | ||
| assert _norm(token) in norm, f"escape 누락으로 '{token}' 이 유실됨" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Assert the literal special characters.
The current assertions check surrounding words, not whether <b>, </b>, a<b, and & survive escaping. Include those exact markers, or compare normalized expected content, so punctuation loss cannot pass unnoticed.
🤖 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/unit/test_attachment_textloader_long_line_333.py`
around lines 85 - 98, Update test_html_special_chars_preserved to assert that
the normalized extracted text retains the literal markers "<b>", "</b>", "a<b",
and "&", or compare against the fully normalized expected content; keep the
existing token-preservation checks as appropriate.
CI 러너에 한글 폰트가 없어 weasyprint→PDF→PyMuPDF round-trip 에서 CJK 글리프가 .notdef 로 깨져(추출 텍스트 손상) 테스트가 실패했음. 잘림/escape 버그는 언어 무관이므로 콘텐츠를 ASCII 로 교체해 폰트 비의존으로 만들고 검증력은 유지. - pre-wrap(공백 있는 긴 줄) / overflow-wrap(공백 없는 초장문) 케이스 분리 - escape 검증도 ASCII 토큰으로 교체 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeRabbit 리뷰(Ruff BLE001) 반영. blind except 대신 실제로 발생하는 두 경우만 잡는다: ImportError(패키지 미설치), OSError(pango/gobject 등 네이티브 라이브러리 로드 실패). 프로덕션 weasyprint 가드도 두 경우 모두 폴백하므로 skip 판정과 일치하며, 그 외 예기치 않은 예외는 표면화된다. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(attachment): TextLoader 긴 한 줄 txt/json/md 청킹 잘림 수정 (#333)
개요
줄바꿈 없이 한 줄이 긴 txt/json/md 파일을 기본 첨부 전처리기(attachment 모드)로 적재하면, PDF 변환 시 A4 페이지 좌우 폭을 넘어가는 부분이 렌더링되지 않고(잘림), 청킹에서도 넘친 텍스트가 통째로 누락되던 문제를 수정함.
Closes #333
원인
txt/json/md 는
TextLoader.load()가 원문을<pre>{content}</pre>HTML 로 감싸 weasyprint 로 PDF 변환 → 그 PDF 를 PyMuPDF 로 파싱해 청킹함.그런데
<pre>의 기본값이white-space: pre라 자동 줄바꿈을 하지 않음. 그래서:md 만 "뷰어는 멀쩡, 청킹만 잘림" 인 이유는 경로가 갈리기 때문:
get_loader→TextLoader(<pre>)compose_vectors→convert_md_to_pdf(markdown →<p>, 자동 wrap)두 PDF 모두 weasyprint 로 생성되며(LibreOffice 아님), 차이는 HTML 구조(
<pre>no-wrap vs<p>auto-wrap)뿐. 즉 두 증상(txt/json/md)의 근본 원인은 하나 —TextLoader가<pre>로 감싸 긴 줄을 wrap 하지 않는 것. (버전 무관 — v2.2.2 / v2.2.3 / develop 동일)변경 사항
genon/preprocessor/facade/attachment_processor.pyimport html추가TextLoader.load()의<pre>HTML 생성부 수정:white-space: pre-wrap→ 원문 줄바꿈/공백 유지 + 폭 초과 시 자동 줄바꿈overflow-wrap: anywhere→ 공백 없는 초장문(URL 등)도 강제 개행html.escape(content)→<,&등이 태그로 해석돼 뒤 텍스트가 유실되는 것 방지html→html_doc개명 (신규html모듈과 충돌 회피)이 한 곳 수정으로 txt/json/md 청킹 누락이 함께 해결됨. md 표시용
convert_md_to_pdf경로는 이미 정상이라 수정 불필요.테스트
genon/preprocessor/tests/unit/test_attachment_textloader_long_line_333.py신규 추가 (기존test_attachment_processor_samples.py컨벤션 준수:@pytest.mark.unit,_import_processorsys.path 폴백, weasyprint 미설치 시 skip)test_long_single_line_txt_not_truncated— 줄바꿈 없는 긴 txt 의 끝 토큰이 청킹 결과에 보존되는지test_html_special_chars_preserved—<,&, 태그 유사 문자열 뒤 텍스트 보존(escape) 검증test_long_single_line_json_not_truncated— json 도 동일 경로라 끝 토큰 보존검증 결과
TextLoader.load()의 PDF 경로(escape + pre-wrap → weasyprint → PyMuPDF)를 동일 입력으로 재현해 확인:<pre>경로에선 실패(긴 줄 끝 토큰·escape 뒤 토큰 유실) → 진짜 회귀 가드로 작동함을 확인영향 범위
pre-wrap은 원문 줄바꿈/공백을 그대로 유지함🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests