This commit is contained in:
LASTA_DEV01\lasta
2026-05-13 19:57:34 +09:00
parent 2e9204243d
commit 9e88f4c7ad
4310 changed files with 48538 additions and 905279 deletions

View File

@@ -0,0 +1,162 @@
# Phase 1 — Trafilatura 통합 (다음 작업자 핸드오프)
본 문서는 Phase 0이 완료된 시점에서 Phase 1 작업을 이어받는 AI 에이전트 또는 개발자가 즉시 작업을 시작하기 위한 핸드오프 노트다.
## 시작 전 확인 사항
- [ ] **Phase 0 Acceptance Gate**가 모두 ✅인가? [PHASE0_ACCEPTANCE_GATE.md](PHASE0_ACCEPTANCE_GATE.md) 참조. 통과 전에는 Phase 1 진행 금지.
- [ ] `tests/unit``tests/integration` 전체가 PASS인가?
- [ ] git log에 Phase 0 commit들이 PR 단위로 분리되어 있는가? (0.1 vendored / 0.2 bug fix / 0.3 multi-file / 0.4 FastAPI / 0.5 config / 0.6 e2e tests / 0.7 gate)
## Phase 1 목표
URL이 입력일 때 원본 페이지에서 본문, 제목, 저자, 날짜, 언어, canonical URL을 정확히 뽑아 OntoCast의 `ContentUnit` metadata에 채워 넣는다.
**근거**: 통합설계서 §5 Phase 1, Trafilatura 분석 §11~§17.
**왜 Trafilatura를 가장 먼저 통합하는가**: 가장 작은 통합 — 단일 함수 호출(`bare_extraction`)만으로 끝남. 의존성도 명확하며 라이선스 동일 (Apache 2.0).
## 작업 단위 (PR 분해)
### 1.1: Trafilatura 의존성 활성화
`pyproject.toml`에 이미 `trafilatura[all]>=2.0.0`이 명시되어 있다. 활성화 절차:
```powershell
pip install -e ".[dev]" # 의존성 재설치 시 trafilatura 자동 설치
python -c "import trafilatura; print(trafilatura.__version__)"
```
**확인**: `2.0.0` 이상이 출력되어야 한다.
### 1.2: `web_extractor.py` 어댑터 작성
**위치**: `platform/core/extractors/web_extractor.py`
**근거**: Trafilatura 분석 §17의 `extract_for_ontology` 함수를 거의 그대로 사용.
**필수 동작**:
- 입력: `html: str`, `url: str`, `lang: str | None = None`
- 출력: `ExtractedWebDocument` (dataclass)
- `url`, `title`, `author`, `date`, `sitename`, `description`
- `text` (정제 본문)
- `body_xml` (Trafilatura `Document.body`)
- `metadata` (raw dict)
- `fingerprint` (SimHash)
- 실패 시 `None` 반환
**호출 옵션** (Trafilatura 분석 §12 권장값 그대로):
```python
Extractor(
output_format="python",
url=url,
with_metadata=True,
comments=False,
tables=True,
formatting=True,
links=True,
images=True,
dedup=True,
lang=lang,
)
```
### 1.3: `ContentUnit` 모델 확장
OntoCast의 `vendored/ontocast/ontocast/onto/content_unit.py`**직접 수정하지 말고**, 우리 쪽에 wrapper 모델을 만든다.
**위치**: `platform/models/content_unit.py`
**필드** (통합설계서 §7.1 참조):
- 기존 OntoCast 필드 (`text`, `index`, `doc_iri`, `graph`, `type`, `iri`) 유지/위임
- 추가: `source_url`, `title`, `author`, `publish_date`, `language`, `sitename`, `fingerprint`, `content_hash`, `metadata`, `retrieved_at`, `extracted_by`
**호환성**: 기존 OntoCast 코드가 받는 `ContentUnit`과 인터페이스 호환되도록 `as_ontocast()` 메서드 제공.
### 1.4: OntoCast `ConverterTool` 분기 추가 (URL/HTML 입력)
**문제**: OntoCast `ConverterTool`은 PDF/DOCX/MD만 처리. URL 또는 HTML 입력은 처리 못 함.
**조치 옵션**:
- **옵션 A (권장)**: OntoCast의 `convert_document.py` 모듈에 새 분기 추가 — `.html`, `.htm` 확장자 또는 `state.source_url`이 있으면 Trafilatura로 처리. **vendored 수정이지만 매우 작음**.
- **옵션 B**: API 레이어(`platform/api/`)에서 입력이 URL이면 미리 fetch + Trafilatura 처리한 뒤 그 결과를 JSON envelope로 ToolBox에 넘김.
**권장**: 옵션 B. vendored 수정을 늘리지 않고 platform 코드로 끝낼 수 있음.
새 endpoint:
- `POST /process/url` — body: `{"url": "...", "ontology_user_instruction": "...", ...}` — 내부적으로 `web_extractor`로 본문 추출 후 OntoCast workflow 실행.
### 1.5: Fingerprint 기반 dedup
- `tests/fixtures/`에 같은 본문의 두 URL fixture 만들기
- `web_extractor` 결과의 `fingerprint`가 일치하면 OntoCast 처리 skip
- 저장 위치: 일단 in-memory set (`platform/storage/dedup_cache.py`), Phase 2에서 Redis로 이전
### 1.6: 한국어 페이지 3종 추출 검증
**테스트 fixture 수집**:
- 한국어 뉴스 1개 (예: 연합뉴스/조선/한겨레)
- 한국어 블로그 1개 (예: 네이버 블로그)
- 한국어 쇼핑 페이지 1개 (예: 쿠팡 상품 페이지)
각각 raw HTML을 `tests/fixtures/korean/`에 저장 (실제 fetch는 운영 환경에서 한 번만, 그 결과를 fixture로 박제).
**테스트**: `tests/integration/test_web_extractor_korean.py`
- 본문 길이 > 200자
- title 추출 성공
- language 감지: `ko`
- author 또는 date 중 하나 이상 추출
### 1.7: Acceptance Gate 1 체크
통합설계서 §5 Phase 1 Acceptance Gate 4개 항목:
- [ ] URL 입력 → 본문/메타데이터가 정확히 추출되어 `ContentUnit`에 저장됨
- [ ] 한국어 뉴스/블로그/쇼핑 페이지 각각 1개씩 본문 추출 정확도 수동 검증
- [ ] 동일 URL 재입력 시 fingerprint 기반 dedup으로 skip
- [ ] Phase 0의 모든 기능이 여전히 정상 동작 (회귀 없음)
Phase 0의 `tests/unit/`, `tests/integration/` 전체가 여전히 PASS여야 함.
## Phase 1에서 만들 새 산출물
```
platform/
core/
extractors/
web_extractor.py ← 1.2
models/
content_unit.py ← 1.3
storage/
dedup_cache.py ← 1.5
api/
routes/
url_ingest.py ← 1.4 (POST /process/url)
tests/
fixtures/
korean/ ← 1.6
news_yonhap.html
blog_naver.html
shop_coupang.html
unit/
test_web_extractor.py ← 1.2
test_dedup_cache.py ← 1.5
integration/
test_url_ingest.py ← 1.4
test_web_extractor_korean.py ← 1.6
docs/
phases/
PHASE1_ACCEPTANCE_GATE.md ← 1.7 (PHASE0과 동일 형식)
PHASE2_NEXT_STEPS.md ← 다음 작업자에게 넘김
```
## 작업 시 준수사항 (PHASE0과 동일)
1. **PR 단위 분리**: 1.1~1.7 각각 별도 PR/커밋.
2. **PR 설명에 근거 인용**: 예) "통합설계서 §5 Phase 1 (1.2)에 따라 Trafilatura adapter 작성. Trafilatura 분석 §17 인용."
3. **vendored/ontocast/** 수정 최소화. 본 Phase에서는 옵션 B 사용 시 vendored 수정 0건이 목표.
4. **Phase 2로 넘어가지 말 것**: Acceptance Gate 1 통과 전까지 Crawl4AI 의존성을 코드에서 import하지 않는다.
## Phase 2 이후 핸드오프
Phase 1 완료 후 다음 작업자에게 동일한 형식의 `PHASE2_NEXT_STEPS.md`를 작성한다. 통합설계서 §12 Phase 2 작업 단위(2.1~2.8)를 참조.