Repository navigation
fix: OCR 파서 — 표 처방전 좌표 파싱 복구 + 약봉투 압축형 다중 약 분리 #98
Description
📌 Description
OCR 파싱 개선 1단계의 파서 수정. #96(회귀 테스트 기반) 위에서 진행한다.
OcrParser.java 한 파일만 건드리며, 스키마·응답 DTO·보안 설정 변화 없음.
두 서식이 다중 약 추출에 실패한다:
B. 병원 표 처방전 — 좌표 파싱 경로에 못 들어감
parse()는 isTablePrescription()이 true여야 parseByCoordinates()로 간다. 그런데
isTablePrescription()은 LABEL_DOSAGE_PATTERN(1회\s*투약량\s*\d 등)이 매치되면 즉시 false를
반환한다. 이 \s*가 줄바꿈을 삼켜서, 표 헤더 1회투약량\n1일투여횟수의 다음 줄 숫자에
매치된다 → 표 처방전을 "약봉투 라벨"로 오판 → 좌표 파싱이 한 번도 실행된 적 없음.
좌표 경로에 억지로 넣어도, detectColumnIndex()가 헤더 셀의 순서 인덱스로 컬럼을 잡아서
헤더 처방 의약품의 명칭이 처방의약품의+명칭 두 필드로 쪼개지면 인덱스가 밀려 전 행이 skip된다.
현재 baseline (#96 하네스): table_prescription_synth.json R=0.00 (5약 중 1약).
C. 약봉투 압축형 — 첫 약만 추출
약이름 + 1정씩1회5일분이 N번 반복되는 약봉투. 별표도 1회투약량 N 라벨 텍스트도 없어
isTextSequentialMulti(= LABEL_DOSAGE_PATTERN 2회+)에 안 걸리고 parseByRegex 단일 폴백 →
COMPACT_DOSAGE_PATTERN이 첫 매치만.
🎯 목표
- 표 처방전이 좌표 파싱 경로로 진입하고, 헤더 셀이 쪼개져도 컬럼을 올바르게 배정한다
- 압축형 약봉투의 약을 전부 분리 추출한다
- 두 서식의 합성 fixture를 guard로 승격 (R=1.00)
🛠️ 작업 범위
OcrParser.java 단일 파일.
B-1. 게이트 정규식
LABEL_DOSAGE_PATTERN의 \s* → [ \t]* (같은 줄의 숫자 = 진짜 라벨만 인정).
isTextSequentialMulti, isTablePrescription 둘 다 이 패턴을 공유 → 표 헤더 오인 함께 해소.
B-2. x좌표 앵커 기반 컬럼 배정 (parseByCoordinates)
detectColumnIndex / ColumnIndex(순서 인덱스) 제거하고:
- 헤더 행에서 키워드가 든 셀마다
(x중심, 컬럼종류)를 앵커로 기록 (0=name 1=dosage 2=times 3=days) - 헤더 판정: name 앵커 존재 + 앵커 2개 이상
- 데이터 행의 각 셀을 x가 가장 가까운 앵커에 배정, 컬럼당 첫 값 채택
- 헤더 못 찾거나 결과 비면
parseByRegex폴백 (기존 유지) - 미사용이 되는
getCol정리
B-3. 폴백 조건 완화 (parseByPharmacyReceipt)
allMatch(전부 null) → 절반 이상 null이면 parseGroupedTrailingNumbers 시도.
C-1. 압축형 게이트 확장 (isTextSequentialMulti)
LABEL_DOSAGE_PATTERN 카운트에 더해, COMPACT_DOSAGE_PATTERN 매치가 2회 이상이어도 true.
→ parseByTextSequential이 이미 이름 줄로 블록 나누고 tryCompactDosage 시도하므로 로직 재사용.
테스트 (#96 하네스)
table_prescription_synth.json— guard 승격drug_bag_compact_synth.json(신규 합성) — 압축형 약봉투, guard- 실제 사진 fixture는 팀이 이름 마스킹 후 추후 추가
✅ To-do
-
LABEL_DOSAGE_PATTERN\s*→[ \t]* -
parseByCoordinatesx좌표 앵커 방식으로 교체,detectColumnIndex/ColumnIndex/getCol정리 -
parseByPharmacyReceipt폴백 조건 완화 -
isTextSequentialMulti—COMPACT_DOSAGE_PATTERN2회+ 조건 추가 - 합성 압축형 약봉투 fixture 추가
-
table_prescription_synth.jsonguard 승격 - 기존 별표 영수증(guard) 무회귀 확인
📏 완료 조건 (DoD)
table_prescription_synth.json: 약 5건, 필드 채움, guard 통과drug_bag_compact_synth.json: 약 N건 전부, guard 통과pharmacy_receipt_starred.json(기존 guard) 결과 변화 없음./gradlew test --tests "*OcrParser*"통과
📒 기타
- 선행: feat: OCR 응답 원본 저장 + 파서 회귀 테스트 기반 #96 (회귀 하네스). feat: OCR 응답 원본 저장 + 파서 회귀 테스트 기반 #96 머지 후 rebase
- 커밋 분리:
fix: 표 처방전 좌표 파싱/fix: 약봉투 압축형 다중 약/test: 합성 fixture - OCR은 공간 좌표가 아니라 읽는 순서로 응답 → 표는 컬럼별로 묶여 행 구조가 사라진다
(.dev/learnings/ocr_table_prescription_parsing.md)
Activity
Merge pull request #99 from PIUDAProject/fix/98