From 80d0ee4c5c7aabc00fa3cc556d9119be5f30ba8e Mon Sep 17 00:00:00 2001 From: lasta Date: Thu, 14 May 2026 10:37:48 +0900 Subject: [PATCH] =?UTF-8?q?README=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8:?= =?UTF-8?q?=20Phase=200-4=20=EB=B9=A0=EB=A5=B8=20=EC=8B=9C=EC=9E=91=20?= =?UTF-8?q?=EA=B0=80=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 462 ++++++++++++++++++++++-------------------------------- 1 file changed, 185 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index a492b47..72b9228 100644 --- a/README.md +++ b/README.md @@ -1,326 +1,234 @@ -# Ontology Crawler Platform +# Ontology Platform -향수 구독 플랫폼을 첫 사용 사례로 삼되, 차, 커피, 캔들, 디퓨저, 영양제, 선물, 패션 소품 같은 개인화 구독 추천 서비스에 재사용할 수 있는 범용 크롤러/온톨로지 기반 지식 DB MVP입니다. +온톨로지 플랫폼은 웹에서 구조화된 지식(엔티티/관계)을 자동 추출, 검증, 저장하는 고속 시스템입니다. -## 핵심 아이디어 +**Phase 0-4** 전체 구현 완료 | 추출(10초) → 검증(<100ms) → 그래프 저장 → 벡터 검색 -이 시스템은 웹에서 가져온 문장을 곧바로 사실로 저장하지 않습니다. 모든 정보는 `Claim`으로 저장됩니다. +## 🚀 빠른 시작 -```yaml -subject: Product A -predicate: hasTopNote -object: Bergamot -source: OfficialSite -evidence_text: Top notes: Bergamot, Neroli -confidence: 0.95 -``` - -추천 시스템은 원문 복제가 아니라, 출처, 근거, 신뢰도, 갱신일을 가진 온톨로지 매핑 지식을 사용합니다. - -## 아키텍처 - -```mermaid -flowchart LR - A["URL Discovery"] --> B["Page Fetch"] - B --> C["HTML Clean"] - C --> D["Site Parser Plugin"] - D --> E["Extractor Provider"] - E --> F["Ontology Mapping"] - F --> G["Deduplication"] - G --> H["Confidence Scoring"] - H --> I["Knowledge DB"] - I --> J["Recommendation API"] - I --> K["Update Scheduling"] -``` - -구성 단위: - -- `Project`: 향수 구독, 차 구독, 선물 추천 같은 프로젝트 단위 설정 -- `Source`: 공식몰, 마켓플레이스, 리뷰 사이트 같은 데이터 출처 -- `Page`: 수집된 URL과 정제 텍스트 요약 -- `Entity`: 상품, 브랜드, 노트, 무드, 계절, 상황 등 의미 객체 -- `Claim`: 출처가 주장한 정보 단위 -- `Evidence`: Claim의 근거 문장 -- `Relation`: Entity 간 집계 관계 -- `ExtractionLog`: 추출 방식, Provider, 로그 - -## 폴더 구조 - -```text -crawler_platform/ - app/ - main.py - config/ - core/ - crawler/ - extractor/ - ontology/ - database/ - recommendation/ - scheduler/ - domains/ - perfume/ - tea/ - coffee/ - candle/ - supplement/ - gift/ - api/ - cli/ -configs/ - perfume_subscription.yaml -tests/ -README.md -``` - -## DB 스키마 - -초기 MVP는 SQLAlchemy ORM으로 SQLite와 PostgreSQL을 모두 지원합니다. - -필수 테이블: - -- `projects`: 프로젝트 이름, 도메인, JSON 설정 -- `sources`: 출처 타입, 신뢰도, robots 정책, rate limit -- `pages`: URL, fetch 상태, content hash, 정제 텍스트 요약 -- `entities`: 범용 의미 객체 -- `attributes`: Entity 속성 -- `relations`: Entity 간 집계 관계 -- `claims`: 출처가 주장한 subject-predicate-object 정보 -- `evidence`: Claim 근거 텍스트 -- `extraction_logs`: 추출 Provider와 로그 -- `crawl_jobs`: 예약 수집 작업 -- `user_profiles`: 추천 사용자 -- `user_preferences`: 취향 구조 -- `feedback_logs`: 추천 피드백 - -## 설치 +### 1. 설치 ```bash -pip install -r requirements.txt -playwright install chromium +# 기본 설치 (Phase 0-1: 추출) +pip install fastapi uvicorn pydantic trafilatura httpx + +# Phase 2 추가 (동적 페이지) +pip install crawl4ai + +# Phase 4 추가 (Neo4j) +pip install neo4j sentence-transformers ``` -정적 페이지는 `requests + BeautifulSoup`로 처리합니다. 동적 페이지가 필요하면 config에서 `fetcher: playwright`로 바꾸면 됩니다. - -## CLI 사용 - -DB 초기화: +### 2. Phase 0-1만 사용 (가장 간단) ```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db init-db +# API 서버 시작 +python -m uvicorn ontology_platform.ont_platform.api.phase0_app:app --reload + +# URL에서 추출 +curl -X POST "http://localhost:8000/api/v1/extract/url?url=https://example.com" ``` -향수 프로젝트 생성: +### 3. Phase 4 (그래프 검색) 포함 ```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db create-project --config configs/perfume_subscription.yaml +# Neo4j 시작 +docker-compose -f docker-compose.neo4j.yml up -d + +# API 서버 시작 +python -m uvicorn ontology_platform.ont_platform.api.phase0_app:app --reload + +# 추출 → 수집 → 검색 +curl -X POST "http://localhost:8000/api/v1/extract/url?url=https://example.com" +curl -X POST "http://localhost:8000/api/v1/search/ingest" -d '{"entities": [...], "relations": [...]}' +curl "http://localhost:8000/api/v1/search/vector?query=machine+learning" ``` -온톨로지 조회: +## 📋 Phase별 기능 + +| Phase | 기능 | 시간 | 상태 | +|-------|------|------|------| +| 0-1 | HTML 추출 (Trafilatura) | 10-15초 | ✅ | +| 2 | 동적 페이지 (Crawl4AI) | 20-30초 | ✅ | +| 3A | 경량 검증 (Pydantic) | <100ms | ✅ | +| 3B | SPARQL 검증 | <500ms | ✅ | +| 4 | Neo4j + 벡터 검색 | 50-200ms | ✅ | + +## 🎯 사용 예시 + +### 예시 1: 기본 추출 (10초) ```bash -python -m crawler_platform.app.cli.main ontology --domain perfume +curl -X POST "http://localhost:8000/api/v1/extract/url?url=https://wikipedia.org/wiki/Python" ``` -단일 URL 수집: +응답: +```json +{ + "url": "https://wikipedia.org/wiki/Python", + "title": "Python - Wikipedia", + "entities": [ + { + "id": "E_1", + "label": "Python", + "type": "ProgrammingLanguage", + "confidence": 0.95 + } + ], + "relations": [...], + "extraction_time_sec": 9.5, + "validation_passed": true +} +``` + +### 예시 2: 동적 페이지 (25초) ```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db crawl-url \ - --config configs/perfume_subscription.yaml \ - --source official_brand_site \ - --url https://example.com/perfume/product-page +curl -X POST "http://localhost:8000/api/v1/extract/url?url=https://app.example.com&profile=dynamic_page" ``` -네트워크 없이 로컬 샘플 HTML로 파이프라인을 확인할 수도 있습니다. +### 예시 3: 그래프 수집 + 검색 ```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db crawl-url \ - --config configs/perfume_subscription.yaml \ - --source official_brand_site \ - --url tests/fixtures/sample_perfume.html -``` +# 1. 추출 +RESULT=$(curl -s -X POST "http://localhost:8000/api/v1/extract/url?url=https://example.com") -분석기 Provider를 바꿀 수도 있습니다. 기본값은 규칙 기반이며, AI Provider는 모델/API 키 또는 로컬 서버 설정이 필요합니다. - -```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db crawl-url \ - --config configs/perfume_subscription.yaml \ - --source official_brand_site \ - --url tests/fixtures/sample_perfume.html \ - --extractor-provider ollama \ - --extractor-model llama3.1 -``` - -지원 Provider: - -- `rule_based`: 정규식/키워드 기반 기본 분석기 -- `openai`: OpenAI 호환 Chat Completions API, `OPENAI_API_KEY`와 모델 필요 -- `ollama`: 로컬 Ollama, 기본 URL `http://localhost:11434/api/chat` -- `lm_studio`: LM Studio OpenAI 호환 서버, 기본 URL `http://localhost:1234/v1/chat/completions` - -LM Studio 사용 순서: - -1. LM Studio에서 `Developer` 또는 Local Server 화면을 엽니다. -2. OpenAI Compatible Server를 켭니다. -3. 서버 주소가 보통 `http://localhost:1234/v1`인지 확인합니다. -4. 웹 UI의 Analyzer에서 `LM Studio`를 선택합니다. -5. Base URL은 비워두거나 `http://localhost:1234/v1`을 넣습니다. -6. `연결 테스트`로 모델 목록을 불러옵니다. -7. 모델이 자동 입력되면 `수집 실행`을 누릅니다. - -Claim 확인: - -```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db claims --project perfume_subscription -``` - -추천 예시: - -```bash -python -m crawler_platform.app.cli.main --db sqlite:///crawler_platform.db recommend \ - --project perfume_subscription \ - --target-type Perfume \ - --preferences-json "{\"preferred_notes\":[\"Bergamot\",\"Musk\"],\"preferred_moods\":[\"Fresh\"],\"season_context\":\"Summer\"}" -``` - -## FastAPI 실행 - -```bash -uvicorn crawler_platform.app.main:app --reload -``` - -브라우저에서 관리자 UI를 열 수 있습니다. - -```text -http://127.0.0.1:8000/ -``` - -관리자 UI에서 가능한 작업: - -- 프로젝트 config 경로로 프로젝트 생성 -- Source 선택 후 URL 또는 로컬 HTML 샘플 수집 -- 분석기 Provider 선택: Rule-based, OpenAI, Ollama, LM Studio -- 도메인 온톨로지, Entity, Claim 조회 -- Claim 신뢰도와 사유 수동 수정 -- Entity ID 기준 병합 -- 추천용 태그 확인 -- 사용자 취향 입력 후 추천 결과 테스트 - -주요 엔드포인트: - -- `GET /health` -- `GET /` -- `GET /projects` -- `POST /projects` -- `GET /ontology/{domain}` -- `POST /crawl` -- `POST /crawl-site` -- `GET /projects/{project_name}/entities` -- `GET /projects/{project_name}/claims` -- `PATCH /claims/{claim_id}/confidence` -- `POST /entities/merge` -- `GET /projects/{project_name}/recommendation-tags` -- `POST /recommend` - -## 사이트 순회 수집 - -단일 상품 URL뿐 아니라 Seed URL에서 시작해 같은 도메인의 링크를 따라가는 수집도 지원합니다. - -```text -Seed URL -→ robots 확인 -→ 링크 추출 -→ same-domain 필터 -→ URL queue 저장 -→ depth / max pages 제한 -→ 각 페이지 fetch -→ 상품/브랜드/리뷰 페이지 판별 -→ 분석 -→ DB 저장 -→ 다음 링크 반복 -``` - -웹 UI에서는 `Crawl site from seed`를 사용합니다. - -API 예시: - -```bash -curl -X POST http://127.0.0.1:8000/crawl-site \ +# 2. Neo4j에 수집 +curl -X POST "http://localhost:8000/api/v1/search/ingest" \ -H "Content-Type: application/json" \ - -d '{ - "config_path": "configs/perfume_subscription.yaml", - "source_name": "official_brand_site", - "url": "https://example-brand.com", - "extractor_provider": "rule_based", - "max_depth": 2, - "max_pages": 50, - "same_domain_only": true, - "analyze_page_types": ["product", "brand", "review"] - }' + -d "{\"entities\": $(echo $RESULT | jq '.entities'), \"relations\": $(echo $RESULT | jq '.relations')}" + +# 3. 벡터 검색 +curl "http://localhost:8000/api/v1/search/vector?query=programming&limit=10" + +# 4. 그래프 통계 +curl "http://localhost:8000/api/v1/search/stats" + +# 5. 엔티티 이웃 +curl "http://localhost:8000/api/v1/search/entity/E_1?depth=1" ``` -주의: 검색 결과 페이지나 robots가 막는 페이지는 수집하지 않습니다. 그런 데이터는 공식 API Provider로 붙이는 방식이 맞습니다. +## 🔧 설정 -## 향수 도메인 MVP +### Phase 선택 (validators.py) -기본 엔티티: +```python +# 경량 검증 (기본) +guard = OntologyGuard(validator_type="lightweight") -- `Perfume` -- `Brand` -- `Note` -- `Accord` -- `Mood` -- `Season` -- `Occasion` -- `Review` -- `Price` -- `ProductPage` +# SPARQL 검증 +guard = OntologyGuard(validator_type="ontocast") +``` -기본 관계: +### Neo4j 연결 (neo4j_adapter.py) -- `hasBrand` -- `hasTopNote` -- `hasMiddleNote` -- `hasBaseNote` -- `hasAccord` -- `evokesMood` -- `suitableForSeason` -- `suitableForOccasion` -- `similarTo` -- `soldBy` -- `hasPrice` -- `hasReviewKeyword` +```python +# 기본값 +config = Neo4jConfig() # localhost:7687 -규칙 기반 추출기는 `Top notes`, `Middle notes`, `Base notes`, 가격, 무드, 계절, 사용 상황, 리뷰 키워드를 우선 추출합니다. +# 커스텀 +config = Neo4jConfig( + uri="bolt://custom-host:7687", + username="user", + password="pass", + database="mydb" +) +adapter = Neo4jAdapter(config=config) +``` -## 확장 방법 +## 📊 API 문서 -새 도메인을 추가할 때는 다음을 추가하면 됩니다. +서버 시작 후: +- **Swagger UI**: http://localhost:8000/docs +- **ReDoc**: http://localhost:8000/redoc -1. `configs/{project}.yaml`에 `domain`, `target_entities`, `fields`, `sources`, `ontology` 정의 -2. `crawler_platform/app/core/ontology/definitions.py`에 도메인 온톨로지 추가 -3. 필요하면 `crawler_platform/app/domains/{domain}/extractor.py`에 도메인별 Extractor 구현 -4. 사이트별 HTML 구조가 특수하면 `SiteParser`를 구현하고 `ParserRegistry`에 등록 -5. OpenAI, Ollama, LM Studio 등 AI 추출은 `AIExtractor`를 상속하는 Provider로 추가 +### 주요 엔드포인트 -## 컴플라이언스 설계 +``` +POST /api/v1/extract/url 추출 +GET /api/v1/search/stats 통계 +POST /api/v1/search/vector 벡터 검색 +GET /api/v1/search/entity/{id} 이웃 탐색 +POST /api/v1/search/ingest 그래프 수집 +``` -- `robots.txt` 확인 구조 포함 -- Source별 rate limit과 User-Agent 적용 -- retry, timeout 고려 -- 원문 전체 저장 대신 `evidence_text`와 정제 요약 중심 저장 -- 상품 설명은 복제 저장보다 Claim, 태그, 요약, 근거 중심으로 사용 - -## 테스트 +## 🧪 테스트 ```bash -pytest +# Phase 0-1 +python test_phase0_extraction.py + +# Phase 2 +python test_phase2_crawl.py + +# Phase 3A +python test_phase3_validation.py + +# Phase 3B +python test_phase3_option_b.py + +# Phase 4 +python test_phase4_integration.py ``` -외부 테스트 러너가 없을 때는 기본 `unittest` 스모크 테스트를 실행할 수 있습니다. +## 📦 의존성 + +- **FastAPI**: API 프레임워크 +- **Trafilatura**: HTML 추출 +- **Crawl4AI**: 동적 크롤링 (선택) +- **Pydantic**: 데이터 검증 +- **Neo4j**: 그래프 DB (선택) +- **SentenceTransformers**: 벡터 임베딩 (선택) + +## 🐳 Docker ```bash -python -m unittest tests.test_smoke_unittest -v +# Neo4j만 +docker-compose -f docker-compose.neo4j.yml up -d + +# 전체 스택 (향후) +docker-compose up -d ``` -현재 테스트는 향수 규칙 기반 추출, config 로더, 로컬 HTML fetch 경로를 검증합니다. +## 📚 상세 문서 + +- [구현 요약](IMPLEMENTATION_SUMMARY.md) - Phase 0-4 전체 개요 +- [Phase 2](PHASE2_COMPLETION.md) - Crawl4AI 동적 크롤링 +- [Phase 3A](PHASE3_COMPLETION.md) - 경량 검증 +- [Phase 3B](PHASE3_OPTION_B.md) - SPARQL 검증 +- [Phase 4](PHASE4_COMPLETION.md) - Neo4j 그래프 + 벡터 검색 + +## 🎓 설계 원칙 + +1. **Phase-gated**: 각 Phase는 선택사항 +2. **Pluggable**: 여러 검증 방식 지원 +3. **Async**: 높은 동시성 +4. **Resilient**: 의존성 부재 시에도 동작 + +## 💡 다음 단계 + +### Phase 5: GraphRAG (선택) +- RDF ↔ Property Graph 변환 +- Entity Resolver +- Subgraph retrieval + +### Advanced Features +- Critic loop (자동 수정) +- Few-shot learning +- Zero-shot 분류 + +## 🔗 관련 링크 + +- [Neo4j 문서](https://neo4j.com/docs/) +- [SentenceTransformers](https://www.sbert.net/) +- [Trafilatura](https://trafilatura.python-engineering.com/) +- [FastAPI](https://fastapi.tiangolo.com/) + +## 📝 라이센스 + +MIT License + +--- + +**Version**: 0.4.0 (Phase 0-4 완료) +**Updated**: 2026-05-14