| .. | ||
| extract-excel.py | ||
| extract-images.py | ||
| merge-batch.py | ||
| merge-data.ts | ||
| ocr-claude-vision.ts | ||
| ocr-local.py | ||
| README.md | ||
| requirements.txt | ||
HNS 물질 Import 파이프라인
C:\Projects\MeterialDB\유해물질 화물적부도 검색툴.xlsm 외부 자료를 HNS_SUBSTANCE DB로 변환하는 1회성 파이프라인.
파이프라인 구조
[Excel xlsm]
├─ (1) extract-excel.py → out/base.json (1,345종 기본 정보)
└─ (2) extract-images.py → out/images/*.png (225종 상세 카드 이미지)
↓
(3) ocr-images.ts → out/ocr.json (Claude Vision → 물성/위험도/EmS JSON)
↓
(4) merge-data.ts → frontend/src/data/hnsSubstanceData.json
↓
(5) tsx src/db/seedHns.ts → HNS_SUBSTANCE 테이블
전제 조건
- Python 3.9+ with
openpyxl - Node.js 20
ANTHROPIC_API_KEY환경변수 (Claude Vision API)- Excel 원본 파일:
C:\Projects\MeterialDB\유해물질 화물적부도 검색툴.xlsm
실행 순서
1) Excel 메타 시트 파싱
cd backend
python scripts/hns-import/extract-excel.py
- 입력:
C:\Projects\MeterialDB\유해물질 화물적부도 검색툴.xlsm - 처리 시트:
화물적부도 화물코드(1,345개),동의어(215개),IBC CODE(분류) - 출력:
scripts/hns-import/out/base.json
2) 이미지 225개 추출
python scripts/hns-import/extract-images.py
- 출력:
scripts/hns-import/out/images/{nameKr}.pngscripts/hns-import/out/image-map.json(파일명↔시트명 매핑)
3) Claude Vision OCR
export ANTHROPIC_API_KEY="sk-ant-..."
cd backend
npx tsx scripts/hns-import/ocr-images.ts
- 이미지 한 장당 Claude API 1회 호출
- 동시 5개 병렬, 실패 시 3회 재시도
- 출력:
scripts/hns-import/out/ocr.json{ [nameKr]: OcrResult }
4) 최종 JSON 병합
npx tsx scripts/hns-import/merge-data.ts
- 입력:
out/base.json+out/ocr.json - 출력:
frontend/src/data/hnsSubstanceData.json(전량 덮어쓰기)
5) DB 재시드
cd backend
npx tsx src/db/seedHns.ts
- 기존
DELETE FROM HNS_SUBSTANCE→ 새 1,345종 INSERT
재실행 안내
out/디렉토리는.gitignore처리되어 커밋되지 않음- OCR 결과는 비결정적이므로 재실행 시 약간 달라질 수 있음
- 비용 절감을 위해 OCR 결과는 보존하고
ocr-images.ts --resume로 실패 항목만 재시도 가능
비용/시간 가이드
- 이미지 225장 × Claude Sonnet 4.6 기준 약 $3~10
- 전체 파이프라인: Excel 파싱 ~30초, 이미지 추출 ~10초, OCR ~10~20분, 병합/시드 ~1분
알려진 이슈 (후속 작업 필요)
1) OCR ↔ base.json 국문명 매칭 실패 (136건)
merge-data.ts 실행 시 base.json의 국문명과 ocr.json 키 표기가 달라 상세정보가 연결되지 않는 물질이 다수 존재. 실제 514종 중 상세 정보 보유는 73종 수준.
예시:
| base.json 국문명 | ocr.json 키 |
|---|---|
1메톡시2프로판올 |
1-메톡시-2프로판올 |
c810이소알코올 |
(C8-10)이소 알코올 |
메탄올 |
(OCR 없음, 이미지 누락) |
가솔린 |
휘발유 (동의어) |
원인:
- 하이픈/공백/괄호 제거 수준 차이 (Excel 시트명과 이미지 파일명 추출 로직 불일치)
- 동의어 처리 미흡 (동의어 시트 215개 활용 필요)
- OCR 대상 225종 외 나머지 1,120종은 기본정보만 존재
권장 해결 방향:
merge-data.ts에 정규화 함수 추가 (공백/하이픈/괄호 제거 후 매칭)base.json의 동의어(synonyms) 배열을 역인덱스로 활용해 OCR 키와 교차 매칭- 매칭 실패 목록을
out/merge-unmatched.json으로 출력하여 수동 검토
2) SEBC/CAS/UN 번호 varchar 길이 초과
base.json 생성 시 Excel에서 복수 CAS/UN 번호를 줄바꿈으로 결합해 저장하여, HNS_SUBSTANCE 테이블의 VARCHAR(20) 등 제약을 초과했음. 현재는 seedHns.ts 의 firstToken() 헬퍼로 첫 토큰만 검색 컬럼에 저장하고 원본 전체는 DATA JSONB에 보존.
영향:
CAS_NO,UN_NO검색 시 두 번째 이후 번호로는 매칭 불가- 프론트엔드 표시 시 JSONB의 원본 값을 참조해야 함
권장 해결 방향:
extract-excel.py에서 복수 CAS/UN 을 배열로 분리 저장- 스키마에
CAS_NO_LIST TEXT[],UN_NO_LIST TEXT[]추가 후 GIN 인덱스 구성
3) MSDS 요약시트 포맷 이미지 (약 5건)
원본 xlsm 일부 시트는 표준 HNS 카드가 아닌 KOSHA MSDS 요약시트 포맷으로, 저해상도 + 필드 구조 상이로 OCR 정확도가 떨어짐.
해당 물질: 프로필벤젠, 프르푸필 알콜, 프로필렌 클리콜 알긴산, 휘발유, 헥사메틸렌 디이소시안산
권장 해결 방향:
ANTHROPIC_API_KEY설정 후HNS_OCR_ONLY로 해당 5종만 재OCR- 이미지 누락 필드는 화학 문헌값(ICSC, PubChem)으로 보강