튜토리얼 5: 추출기 플러그인 개발
eulerweave는 Python entry points 기반의 플러그인 시스템을 사용합니다. 이 튜토리얼에서는 내장 추출기의 구조를 이해하고, 직접 추출기 플러그인을 만드는 방법을 설명합니다.
사전 요구 사항: 튜토리얼 1: 빠른 시작의 기본 워크플로에 익숙해야 합니다.
내장 추출기 현황
eulerweave v0.1에는 6개의 내장 추출기가 포함되어 있습니다:
eulerweave plugins list
Extractors:
txt eulerweave.core.io.local_files:TxtExtractor [.txt]
jsonl eulerweave.core.io.jsonl:JsonlExtractor [.jsonl]
csv eulerweave.core.io.csv_extractor:CsvExtractor [.csv]
parquet eulerweave.core.io.parquet_extractor:ParquetExtractor [.parquet]
html eulerweave.core.io.html_extractor:HtmlExtractor [.html]
pdf eulerweave.core.io.pdf_extractor:PdfExtractor [.pdf]
각 추출기는 pyproject.toml의 eulerweave.extractors entry point에 등록됩니다:
[project.entry-points."eulerweave.extractors"]
txt = "eulerweave.core.io.local_files:TxtExtractor"
jsonl = "eulerweave.core.io.jsonl:JsonlExtractor"
csv = "eulerweave.core.io.csv_extractor:CsvExtractor"
parquet = "eulerweave.core.io.parquet_extractor:ParquetExtractor"
html = "eulerweave.core.io.html_extractor:HtmlExtractor"
pdf = "eulerweave.core.io.pdf_extractor:PdfExtractor"
내장 추출기 옵션 (options_schema)
일부 추출기는 options 필드를 통해 세부 설정을 받습니다.
컴파일러는 각 추출기의 options_schema()를 호출하여 옵션을 검증합니다.
CSV 추출기 옵션
inputs:
- type: csv
uri: data/train.csv
options:
text_column: content # 텍스트로 사용할 컬럼
delimiter: "\t" # 구분자 (기본: ",")
Parquet 추출기 옵션
inputs:
- type: parquet
uri: data/train.parquet
options:
text_column: text
PDF 추출기 옵션
inputs:
- type: pdf
uri: data/paper.pdf
options:
strategy: auto # auto, text, ocr
page_range: "1-10" # 페이지 범위
잘못된 옵션 예시
# 에러: additionalProperties 위반
inputs:
- type: pdf
uri: data/paper.pdf
options:
bad_key: true # ← 허용되지 않는 키
Compilation error: Input option validation failed for 'pdf'
Additional properties not allowed: 'bad_key'
# 에러: strategy 열거형 위반
inputs:
- type: pdf
uri: data/paper.pdf
options:
strategy: magic # ← auto, text, ocr 중 하나여야 함
Compilation error: Input option validation failed for 'pdf'
'magic' is not one of ['auto', 'text', 'ocr']
ExtractorInterface 이해하기
모든 추출기 플러그인은 ExtractorInterface를 구현해야 합니다:
from eulerweave.registry.loader import ExtractorInterface
from eulerweave.core.record import CanonicalRecord
class ExtractorInterface:
"""모든 추출기가 구현해야 하는 프로토콜."""
def extract(self, uri: str, options: dict | None = None) -> Iterator[CanonicalRecord]:
"""URI에서 데이터를 읽어 CanonicalRecord를 yield."""
...
def options_schema(self) -> dict | None:
"""JSON Schema dict를 반환. 옵션이 없으면 None."""
return None
def supported_schemes(self) -> list[str]:
"""지원하는 URI 스킴 목록. 기본: ["file"]."""
return ["file"]
def probe(self, uri: str) -> bool:
"""URI를 처리할 수 있는지 빠르게 확인. 기본: True."""
return True
핵심 포인트:
extract()— 매니페스트의inputs[].uri에서uri를,inputs[].options에서options를 받음options_schema()— JSON Schema를 반환하면 컴파일러가 자동 검증- CanonicalRecord는 고유한
id,text필드,metadata, 출처 정보를 포함
커스텀 추출기 만들기: 예제
패키지 구조
eulerweave-xlsx-extractor/
pyproject.toml
eulerweave_xlsx_extractor/
__init__.py
extractor.py
tests/
test_extractor.py
extractor.py
"""XLSX extractor plugin for eulerweave."""
from __future__ import annotations
import hashlib
from pathlib import Path
from typing import Iterator
from eulerweave.core.record import CanonicalRecord
class XlsxExtractor:
"""Excel 파일에서 텍스트를 추출하는 플러그인."""
def extract(
self,
uri: str,
options: dict | None = None,
) -> Iterator[CanonicalRecord]:
import openpyxl
opts = options or {}
text_column = opts.get("text_column", "A")
sheet_name = opts.get("sheet_name", None)
path = Path(uri)
wb = openpyxl.load_workbook(str(path), read_only=True)
ws = wb[sheet_name] if sheet_name else wb.active
for i, row in enumerate(ws.iter_rows(min_row=2, values_only=False)):
cell_value = str(row[ord(text_column) - ord("A")].value or "")
if not cell_value.strip():
continue
rec_id = hashlib.sha256(
f"{path.name}:{i}".encode()
).hexdigest()[:16]
yield CanonicalRecord(
id=rec_id,
text=cell_value.strip(),
metadata={"row": i + 2, "sheet": ws.title},
source_uri=str(path),
source_type="xlsx",
extracted_by="XlsxExtractor",
)
wb.close()
def options_schema(self) -> dict:
return {
"type": "object",
"properties": {
"text_column": {
"type": "string",
"default": "A",
"description": "텍스트가 있는 컬럼 문자 (A, B, C, ...)",
},
"sheet_name": {
"type": "string",
"description": "시트 이름 (기본: 활성 시트)",
},
},
"additionalProperties": False,
}
pyproject.toml
[build-system]
requires = ["setuptools>=64", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "eulerweave-xlsx-extractor"
version = "0.1.0"
dependencies = ["eulerweave>=0.1.0", "openpyxl>=3.1"]
[project.entry-points."eulerweave.extractors"]
xlsx = "eulerweave_xlsx_extractor.extractor:XlsxExtractor"
설치 및 확인
pip install -e .
eulerweave plugins list # xlsx가 표시되어야 함
eulerweave plugins doctor # ✓ xlsx 확인
매니페스트에서 사용
inputs:
- type: xlsx
uri: data/training_data.xlsx
options:
text_column: B
sheet_name: Sheet1
플러그인 진단 (plugins doctor)
eulerweave plugins doctor
[eulerweave] Plugin diagnostics
Extractors:
✓ txt — eulerweave.core.io.local_files:TxtExtractor
✓ jsonl — eulerweave.core.io.jsonl:JsonlExtractor
✓ csv — eulerweave.core.io.csv_extractor:CsvExtractor
✓ parquet — eulerweave.core.io.parquet_extractor:ParquetExtractor
✓ html — eulerweave.core.io.html_extractor:HtmlExtractor
✓ pdf — eulerweave.core.io.pdf_extractor:PdfExtractor
No issues found.
로드 실패 시:
✗ xlsx — my_package.extractor:XlsxExtractor
[ImportError: No module named 'openpyxl']
해결: pip install openpyxl
Entry Point 그룹 목록
eulerweave는 4개의 entry point 그룹을 지원합니다:
| 그룹 | 용도 | 예시 |
|---|---|---|
eulerweave.extractors |
데이터 추출기 | txt, jsonl, pdf |
eulerweave.blocks |
커스텀 파이프라인 블록 | 외부 전처리 블록 |
eulerweave.metrics |
커스텀 메트릭 블록 | 도메인 특화 메트릭 |
eulerweave.providers.llm |
LLM 프로바이더 | 커스텀 API 연동 |
플러그인 체크리스트
extract(self, uri, options=None)→Iterator[CanonicalRecord]구현options_schema()→ JSON Schema dict 반환 (additionalProperties: false권장)pyproject.toml의eulerweave.extractorsentry point에 등록pip install -e .실행eulerweave plugins list로 확인eulerweave plugins doctor로 진단- 테스트 작성 (기본 추출, 빈 파일, 옵션 검증)
다음 단계
- 튜토리얼 6: 검증 — 플러그인 관련 검증 오류 이해
- 튜토리얼 7: MDS 내보내기 — 스트리밍 형식 내보내기
- 튜토리얼 8: 메트릭 — 파이프라인 품질 통계