tsKim
feat: schoolbridge spaces deploy (extract-text endpoint added)
7f105c8

모델 A — 추출 파이프라인 (A단계: 이진 분류 + B단계: 카테고리 분류)

담당: 윤정 · model/extraction/ · KoELECTRA fine-tuned


한 줄 요약

가정통신문 원문 텍스트를 넣으면, 학부모가 실행해야 할 후보 문장 리스트가 나옵니다 (B단계 입력용).


2단계 구조

┌──────────────────────────────────────────────────────────────┐
│                  가정통신문 원문 텍스트 (OCR 출력)            │
└─────────────────────────┬────────────────────────────────────┘
                          │
        ┌─────────────────▼──────────────────┐
        │          A단계 — 윤정 담당           │
        │      file/predict.py               │
        │                                    │
        │  ① split_sentences()               │
        │    줄바꿈 복원 + 문장 분리           │
        │    (헤더·OCR 노이즈 조기 차단)       │
        │                                    │
        │  ② is_likely_todo()                │
        │    정규식 1차 필터                  │
        │    → KoELECTRA 이진 분류            │
        │      0: 노이즈  1: 할 일·중요 일정   │
        │                                    │
        │  ③ extract_due_date()              │
        │     extract_amount()               │
        │     extract_action_hint()          │
        │    정규식으로 날짜·금액·행동 추출    │
        └─────────────────┬──────────────────┘
                          │
             list[dict] — B단계 입력 스키마
             {"text", "source", "due_date",
              "amount", "confidence", "action_hint"}
                          │
        ┌─────────────────▼──────────────────┐
        │          B단계 — 경이 담당           │
        │   KoELECTRA 5-class 카테고리 분류   │
        │   (제출·준비물·건강·안전·비용·일정·기타) │
        └────────────────────────────────────┘

기술 스택

A단계 모델 KoELECTRA-small-v3 이진 분류 (checkpoints/koelectra-binary/)
B단계 모델 KoELECTRA-base-v3 5-class · yunjeong116/koelectra-extractor
날짜 / 금액 정규식 (regex)
실행 환경 CPU / GPU 자동 선택
의존성 torch · transformers · huggingface_hub · sklearn

이전 → 현재: Llama-3-Korean 8B (Colab T4, 4-bit 양자화) → KoELECTRA 하이브리드
추론 속도 ↑, 서버 배포 용이성 ↑


카테고리 & 중요도 (B단계)

카테고리 설명 기본 점수
제출 서류 · 동의서 · 과제 1.00
준비물 지참물 안내 0.85
건강·안전 건강 · 안전 사항 0.80
비용 금액 포함 항목 (정규식) 0.75
일정 행사 · 일정 안내 0.70
기타 위 외 항목 0.50

긴급 키워드(반드시, 마감, 즉시 등) 포함 시 +0.05 / due_date 있을 시 +0.05


모델 성능 (B단계 카테고리 분류기)

v2 재학습 결과 (2026-04-28 · 15 epoch · cosine LR · WeightedCrossEntropy)

              precision    recall  f1-score   support

          일정     1.0000    1.0000    1.0000         4
         준비물     1.0000    0.5000    0.6667         4
          제출     0.8000    1.0000    0.8889         4
       건강·안전     0.8571    0.8571    0.8571         7
          기타     0.5000    1.0000    0.6667         1

    accuracy                         0.8500        20
   macro avg     0.8314    0.8714    0.8159        20
weighted avg     0.8850    0.8500    0.8444        20

v1 → v2 비교

지표 v1 (10 epoch) v2 (15 epoch) 변화
accuracy 0.7500 0.8500 +0.10 ✅
macro F1 0.5988 0.8159 +0.22 ✅
기타 F1 0.0000 0.6667 완전 회복 ✅

MVP 목표 (accuracy ≥ 0.80, macro F1 ≥ 0.75) 달성
학습 파라미터: num_train_epochs=15, lr=2e-5, scheduler=cosine, warmup_ratio=0.1, WeightedCrossEntropy(balanced)


버그 수정 이력 (2026-04-27)

# 현상 원인 수정
Bug 1 인사말이 TODO로 잡힘 NON_TODO_PATTERNS안녕하세요 미포함 패턴 3개 추가
Bug 2 NLLB 첫 번역 문장 어색 제목 줄이 인사말과 합쳐져 번역 전달 _HEADER_ONLY 필터 추가
Bug 3 원→won 오탐 원하시는, 원인 등 substring 매칭 MONEY_PATTERN에 숫자 선행 조건 강제

파일 구성

model/extraction/
├── fill_original2.py              ← notices_original2.jsonl 자동 채우기 스크립트
├── file/
│   ├── predict.py                 ← A단계 메인 파이프라인 (백엔드 진입점)
│   ├── evaluate_model.py          ← Base vs Fine-tuned 성능 비교 (강사 제출용)
│   ├── preprocess_txt_to_jsonl.py ← PDF txt → JSONL 변환 (문장 단위, 라벨링용)
│   └── txt_to_jsonl.py            ← PDF txt → JSONL 변환 (문서 단위)
├── data/
│   ├── notices_labeled_v2.jsonl   ← 학습 라벨 데이터 (100문장, is_todo + original_id)
│   ├── notices_original2.jsonl    ← 원문 27장 + category/keywords/importance 자동 채우기
│   ├── notices_original2.csv      ← CSV 버전
│   └── galsan_txt/                ← 갈산초 가정통신문 txt 원본 (~100건)
├── checkpoints/
│   └── koelectra-extractor/       ← B단계 5-class 카테고리 분류 체크포인트 (Hub 백업)
├── docs/
│   ├── devlog-2026-04-27.md       ← Bug 수정 3종 + 학습 파라미터 개선
│   ├── devlog-2026-04-28.md       ← notices_original2.jsonl 자동 채우기 작업
│   └── devlog-2026-04-28-v2.md    ← v2 재학습 결과 (accuracy 0.85 달성)
└── x/                             ← 구버전 보관 (Llama Few-shot + 구 predict.py)
    ├── MODEL.py
    ├── predict.py
    ├── notices_labeled_v2.csv
    └── extracted_results.json

A단계 출력 예시 (file/predict.py)

B단계(경이 모델) 입력 스키마:

[
  {
    "text":        "개인용 이어폰(3.5mm) 4월 20일까지 준비해 주세요.",
    "source":      "sample.txt",
    "due_date":    "2026-04-20",
    "amount":      null,
    "confidence":  0.9312,
    "action_hint": "준비"
  },
  {
    "text":        "구입비는 5,000원 이내의 잔돈으로 준비합니다.",
    "source":      "sample.txt",
    "due_date":    null,
    "amount":      5000,
    "confidence":  0.8741,
    "action_hint": "준비"
  }
]

실행

A단계 추출 (직접 테스트)

pip install torch transformers
python model/extraction/file/predict.py

모델 성능 평가 (Base vs Fine-tuned 비교)

pip install scikit-learn pandas
python model/extraction/file/evaluate_model.py
# 테스트 데이터 직접 지정 시:
python model/extraction/file/evaluate_model.py --test_data data/test_data.jsonl

txt → JSONL 변환 (데이터 전처리)

# 문서 단위 (notices_original2.jsonl 스키마)
python model/extraction/file/txt_to_jsonl.py \
    --input data/galsan_txt/*.txt \
    --output data/notices_original2.jsonl \
    --source_type 초등학교

# 문장 단위 (학습 라벨링용)
python model/extraction/file/preprocess_txt_to_jsonl.py \
    --input_dir data/galsan_txt \
    --output data/notices_labeled.jsonl

notices_original2.jsonl 자동 채우기

python model/extraction/fill_original2.py

멱등성 보장 — 재실행 시 항상 재계산하여 덮어씀.


백엔드 연동

from model.extraction.file.predict import predict

# A단계: 후보 문장 추출 → B단계 입력
candidates = predict(notice_text, source="파일명.pdf")
# [{"text", "source", "due_date", "amount", "confidence", "action_hint"}, ...]

모델은 첫 호출 시 로컬 체크포인트(checkpoints/koelectra-binary/)를 우선 로드하고,
없으면 HuggingFace Hub(yunjeong116/koelectra-extractor)에서 자동 다운로드합니다.


데이터 구성

파일 내용 건수
notices_labeled_v2.jsonl 문장 단위 라벨 (is_todo + category + original_id) 100문장 (N01~N19)
notices_original2.jsonl 원문 문서 단위 + category/keywords/importance 27건
galsan_txt/ 갈산초 가정통신문 원본 txt ~100건

notices_labeled_v2.jsonloriginal_id 필드로 원문(notices_original2.jsonl)과 연결 가능.
N16~N19(알림장 4건)는 27장 원문 미포함 → original_id: null.


잔존 한계 및 향후 작업

항목 내용
준비물 recall 0.50 4개 중 2개 오분류. 데이터 추가 시 개선 여지 있음
기타 support=1 검증셋 샘플 1개 → F1 신뢰도 낮음. 가상 데이터 증강 필요
전체 샘플 100개 데이터 절대량 부족. 가상 데이터 추가 후 3차 학습 예정 (목표: 준비물·기타 F1 ≥ 0.70)
Binary 체크포인트 checkpoints/koelectra-binary/ 미배포 상태 — Colab 재학습 후 교체 필요