Add your description here
This project has been archived.
The maintainers of this project have marked this project as archived. No new releases are expected.
Project description
๐ Structured Output Kit
๐ PDF/์ด๋ฏธ์ง ํ์ฑ + LLM ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ์ถ์ถ + ์ ๋์ ํ๊ฐ + ์๊ฐํ๋ฅผ ์ํ ํตํฉ ๋ฒค์น๋งํฌ ํดํท
๋ค์ํ ํ์ฑ ํ๋ ์์ํฌ(Docling, PyPDF, PDFPlumber ๋ฑ)๋ก ๋ฌธ์๋ฅผ ํ ์คํธํํ๊ณ , ์ฌ๋ฌ LLM ํธ์คํธ(OpenAI, Anthropic, Google, Ollama ๋ฑ)์ ์ถ์ถ ํ๋ ์์ํฌ(Instructor, LangChain, LlamaIndex, Marvin ๋ฑ)๋ฅผ ํต์ผ๋ ์ธํฐํ์ด์ค๋ก ์คํํ์ฌ ๊ตฌ์กฐํ๋ ์ ๋ณด๋ฅผ ์ถ์ถํ๊ณ , ์ ๋ต JSON๊ณผ์ ์ ์ฌ๋๋ฅผ ์ ๋ํํ์ฌ ์๊ฐํํ ์ ์๋ ์ข ํฉ ๋ฒค์น๋งํฌ ๋๊ตฌ์ ๋๋ค.
โจ ์ฃผ์ ํน์ง
๏ฟฝ ๋ค์ค ํ์ฑ ํ๋ ์์ํฌ
- PDF: Docling, PyPDF, PDFPlumber, PyMuPDF ์ง์
- ์ด๋ฏธ์ง: Vision Language Model(VLM) ๊ธฐ๋ฐ OCR
- Microsoft: MarkItDown์ผ๋ก ๋ค์ํ ๋ฌธ์ ํ์ ์ง์
๐ ๋ค์ค LLM ํธ์คํธ & ํ๋ ์์ํฌ
- ํธ์คํธ: OpenAI, Anthropic, Google, Ollama, OpenAI-Compatible ์๋ฒ
- ํ๋ ์์ํฌ: Instructor, LangChain(Tool/Parser), LlamaIndex, Marvin, Mirascope, Ollama ๋ฑ
๐ฏ ์ ๋์ ํ๊ฐ ์์คํ
- ์๋ฒ ๋ฉ ์ ์ฌ๋(์ฝ์ฌ์ธ ์ ์ฌ์ฑ)์ ์์ ์ผ์น ๊ธฐ๋ฐ ํ์ด๋ธ๋ฆฌ๋ ์ค์ฝ์ด๋ง
- ํ๋๋ณ ์ธ๋ถ ํ๊ฐ ๋ฐ ํ๊ฐ๋ฆฌ์ ์๊ณ ๋ฆฌ์ฆ์ ํตํ ์ต์ ๋งค์นญ
๐ ์ค์๊ฐ ์๊ฐํ
- Streamlit ๊ธฐ๋ฐ ์ธํฐ๋ํฐ๋ธ ๋์๋ณด๋
- ์ ์ HTML ๋ฆฌํฌํธ ์์ฑ
- ์ฑ๋ฅ ๋ถํฌ ๋ฐ ํ๋๋ณ ์์ธ ๋ถ์
๐ API & CLI ํตํฉ ์ธํฐํ์ด์ค
- RESTful API ์๋ฒ (FastAPI)
- Typer ๊ธฐ๋ฐ ๋ช ๋ น์ค ์ธํฐํ์ด์ค
- ํ์ฑ โ ์ถ์ถ โ ํ๊ฐ โ ์๊ฐํ ์ ์ฒด ํ์ดํ๋ผ์ธ ์ง์
โก YAML ๊ธฐ๋ฐ ์ํฌํ๋ก์ฐ
- ์ฌ๋ฌ ํ์ฑ ๋ฐฉ๋ฒ ร ์ฌ๋ฌ ์ถ์ถ ์ค์ ์ ์๋ ์กฐํฉ ์คํ
- ์ค์ ํ์ผ ๊ธฐ๋ฐ ๋ฐฐ์น ์ฒ๋ฆฌ
- ํ์ฑ ์์ด ์ง์ ํ ์คํธ ์ ๋ ฅ๋ ์ง์
- ์คํ ๊ฒฐ๊ณผ ์๋ ์ ๋ฆฌ ๋ฐ ์์ฝ ๋ฆฌํฌํธ
๐ง ํ์ฅ์ฑ & ์ปค์คํฐ๋ง์ด์ง
- ์ปค์คํ ์คํค๋ง ์ถ๊ฐ (Pydantic ๊ธฐ๋ฐ)
- ํ๊ฐ ๊ธฐ์ค ์ปค์คํฐ๋ง์ด์ง (YAML ์ค์ )
- ์๋ก์ด ํ๋ ์์ํฌ ์ฝ๊ฒ ์ถ๊ฐ ๊ฐ๋ฅ
๐ Quick Start
1๏ธโฃ ์ค์น
# uv ์ค์น (๊ถ์ฅ)
curl -fsSL https://astral.sh/uv/install.sh | sh
# ํ๋ก์ ํธ ํด๋ก ๋ฐ ์์กด์ฑ ์ค์น
git clone https://github.com/Bae-ChangHyun/StructuredOutputKit.git
cd StructuredOutputKit
uv venv
source .venv/bin/activate
uv sync
2๏ธโฃ ํ๊ฒฝ ์ค์
# ํ๊ฒฝ ๋ณ์ ํ์ผ ์์ฑ
cp .env.example .env
# .env ํ์ผ์ API ํค ์ค์
echo "OPENAI_API_KEY=your_api_key_here" >> .env
3๏ธโฃ 30์ด ํ ์คํธ
# API ์๋ฒ ์์
python main.py
# ์ ํฐ๋ฏธ๋์์ ํ
์คํธ ์ถ์ถ ํ
์คํธ
curl -X POST http://localhost:8000/v1/extraction \
-H 'Content-Type: application/json' \
-d '{
"input_text": "์๋
ํ์ธ์. ์ ๋ ํ๊ธธ๋์
๋๋ค. ์ปดํจํฐ๊ณตํ๊ณผ๋ฅผ ์กธ์
ํ๊ณ Python ๊ฐ๋ฐ์๋ก 3๋
๊ฐ ๊ทผ๋ฌดํ์ต๋๋ค.",
"schema_name": "schema_han",
"framework": "OpenAIFramework",
"host_info": {
"provider": "openai",
"base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini"
}
}'
4๏ธโฃ CLI๋ก ์์ํ๊ธฐ
# ํ
์คํธ์์ ๊ตฌ์กฐํ๋ ์ ๋ณด ์ถ์ถ
python main.py --cli extract --input "์๋
ํ์ธ์. ๊น์ฒ ์์
๋๋ค. ์์ธ๋ํ๊ต ์กธ์
ํ ์ผ์ฑ์์ 5๋
๊ฐ ๊ทผ๋ฌดํ์ต๋๋ค."
# PDF ํ์ผ ํ์ฑ (์์)
python main.py --cli parse --file document.pdf --framework DoclingFramework
# ํ๊ฐ ์คํ (์ํ ๋ฐ์ดํฐ ์ฌ์ฉ)
python main.py --cli eval \
--pred result/extraction/$(ls result/extraction | tail -1)/result.json \
--gt data/๋ฆฌ๋ฉค๋ฒ-s1.json
# ์๊ฐํ ์คํ
python main.py --cli viz --eval-result result/evaluation/$(ls result/evaluation | tail -1)/eval_result.json
5๏ธโฃ ์ํฌํ๋ก์ฐ๋ก ์์ํ๊ธฐ
# ์ํฌํ๋ก์ฐ ํ
ํ๋ฆฟ ์์ฑ
python workflow_cli.py workflow template --output my_workflow.yaml
# ์ค์ ํ์ผ ํธ์ง ํ (API ํค ์ค์ ํ์)
python workflow_cli.py workflow run my_workflow.yaml
# ๊ฐ๋จํ ์ถ์ถ๋ง ํ
์คํธ (ํ์ฑ ์์)
python workflow_cli.py workflow run test_extraction_only.yaml
๐ ๋ชฉ์ฐจ
๐ ๋ชฉ์ฐจ
๐ฆ ์ค์น ๊ฐ์ด๋
์์คํ ์๊ตฌ์ฌํญ
- Python 3.12 ์ด์
- Linux/macOS/Windows
- ์ต์ 4GB RAM (VLM ์ฌ์ฉ ์ 8GB+ ๊ถ์ฅ)
์ค์น ๋ฐฉ๋ฒ
๋ฐฉ๋ฒ 1: uv ์ฌ์ฉ (๊ถ์ฅ)
# uv ์ค์น
curl -fsSL https://astral.sh/uv/install.sh | sh
# ํ๋ก์ ํธ ์ค์
git clone https://github.com/Bae-ChangHyun/StructuredOutputKit.git
cd StructuredOutputKit
uv venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv sync
๋ฐฉ๋ฒ 2: pip ์ฌ์ฉ
git clone https://github.com/Bae-ChangHyun/StructuredOutputKit.git
cd StructuredOutputKit
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
๋ฐฉ๋ฒ 3: Docker (์คํ์ )
FROM python:3.12-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync --no-dev
COPY . .
ENV API_HOST=0.0.0.0 API_PORT=8000
EXPOSE 8000
CMD ["python", "main.py"]
docker build -t structured-output-kit .
docker run -p 8000:8000 --env-file .env structured-output-kit
โ๏ธ ํ๊ฒฝ ์ค์
ํ๊ฒฝ ๋ณ์ ์ค์
.env.example์ ๋ณต์ฌํ์ฌ .env ํ์ผ์ ์์ฑํ๊ณ ํ์ํ API ํค๋ฅผ ์ค์ ํ์ธ์.
ํ๊ฒฝ ๋ณ์ ์์ธ ์ค์
# ์๋ฒ ์ค์
API_HOST=0.0.0.0
API_PORT=8000
DEBUG=true
# OpenAI
OPENAI_API_KEY=sk-your-api-key
OPENAI_MODELS=gpt-4o-mini
OPENAI_EMBED_MODELS=text-embedding-3-small
# Anthropic
ANTHROPIC_API_KEY=your-api-key
ANTHROPIC_MODELS=claude-3-5-sonnet-latest
# Google
GOOGLE_API_KEY=your-api-key
GOOGLE_MODELS=gemini-1.5-flash
# OpenAI-Compatible (vLLM, Together AI ๋ฑ)
OPENAI_COMPATIBLE_BASEURL=http://localhost:8000/v1
OPENAI_COMPATIBLE_MODELS=your-model-name
OPENAI_COMPATIBLE_API_KEY=dummy
# Ollama
OLLAMA_BASEURL=http://localhost:11434/v1
OLLAMA_MODELS=llama3.1:8b
# HuggingFace (๋ก์ปฌ ์๋ฒ ๋ฉ)
HUGGINGFACE_EMBED_MODELS=jhgan/ko-sroberta-multitask
# Langfuse (์ ํ์ฌํญ)
LANGFUSE_HOST=your-langfuse-host
LANGFUSE_PUBLIC_KEY=your-public-key
LANGFUSE_SECRET_KEY=your-secret-key
# ์ ํ ์ค์
MAX_FILE_SIZE=10485760
TASK_TIMEOUT=3600
๐ป ์ฌ์ฉ๋ฒ
API ์ฌ์ฉ๋ฒ
์๋ฒ ์์
# ๊ธฐ๋ณธ ์คํ
python main.py
# ์ปค์คํ
ํฌํธ๋ก ์คํ
python main.py --port 8080
# ๊ฐ๋ฐ ๋ชจ๋ (์๋ ๋ฆฌ๋ก๋)
python main.py --reload
API ๋ฌธ์: http://localhost:8000/docs
์ฃผ์ ์๋ํฌ์ธํธ
๏ฟฝ ํ์ฑ API - POST /v1/parsing
PDF/์ด๋ฏธ์ง ํ์ผ ํ์ฑ:
curl -X POST http://localhost:8000/v1/parsing \
-F 'file=@document.pdf' \
-F 'framework=DoclingFramework'
Python ์ฌ์ฉ๋ฒ:
import requests
with open("document.pdf", "rb") as f:
response = requests.post(
"http://localhost:8000/v1/parsing",
files={"file": f},
data={
"framework": "DoclingFramework",
"extra_kwargs": '{"parse_figures": true}'
}
)
result = response.json()
print(f"ํ์ฑ๋ ํ
์คํธ: {result['data']['content']}")
print(f"ํ์ฑ ์๊ฐ: {result['latency']}์ด")
๏ฟฝ๐ ์ถ์ถ API - POST /v1/extraction
๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ:
curl -X POST http://localhost:8000/v1/extraction \
-H 'Content-Type: application/json' \
-d '{
"input_text": "์๋
ํ์ธ์. ์ ์ด๋ฆ์ ํ๊ธธ๋์
๋๋ค.",
"schema_name": "schema_han",
"framework": "OpenAIFramework",
"host_info": {
"provider": "openai",
"base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini"
}
}'
Python ์ฌ์ฉ๋ฒ:
import requests
response = requests.post("http://localhost:8000/v1/extraction", json={
"input_text": "๊น์ฒ ์์
๋๋ค. ์์ธ๋ํ๊ต ์ปดํจํฐ๊ณตํ๊ณผ ์กธ์
ํ ๋ค์ด๋ฒ์์ 5๋
๊ฐ ๊ทผ๋ฌดํ์ต๋๋ค.",
"schema_name": "schema_han",
"framework": "OpenAIFramework",
"extra_kwargs": {"temperature": 0.1, "timeout": 900},
"host_info": {
"provider": "openai",
"base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini"
}
})
result = response.json()
print(f"์ถ์ถ ๊ฒฐ๊ณผ: {result['data']['result']}")
print(f"์ฑ๊ณต๋ฅ : {result['success_rate']}")
print(f"์๋ต ์๊ฐ: {result['latency']}์ด")
๐ ํ๊ฐ API - POST /v1/evaluation
curl -X POST http://localhost:8000/v1/evaluation \
-H 'Content-Type: application/json' \
-d '{
"pred_json_path": "result/extraction/20250812_0850/result.json",
"gt_json_path": "data/๋ฆฌ๋ฉค๋ฒ-s1.json",
"schema_name": "schema_han",
"host_info": {
"provider": "huggingface",
"base_url": "",
"model": "jhgan/ko-sroberta-multitask"
}
}'
๐จ ์๊ฐํ API - POST /v1/visualization/generate
curl -X POST http://localhost:8000/v1/visualization/generate \
-H 'Content-Type: application/json' \
-d '{
"eval_result_path": "result/evaluation/20250812_0854/eval_result.json"
}'
๐ง ์ ํธ๋ฆฌํฐ API
# ์ง์ ํธ์คํธ ๋ชฉ๋ก
curl http://localhost:8000/v1/utils/providers
# ํธ์คํธ๋ณ ํ๋ ์์ํฌ ๋ชฉ๋ก
curl http://localhost:8000/v1/utils/frameworks?provider=openai
# ์ฌ์ฉ ๊ฐ๋ฅํ ์คํค๋ง ๋ชฉ๋ก
curl http://localhost:8000/v1/utils/schemas
# ํ์ฑ ํ๋ ์์ํฌ ๋ชฉ๋ก
curl http://localhost:8000/v1/utils/parsing-frameworks
CLI ์ฌ์ฉ๋ฒ
ํ์ฑ (Parsing)
# PDF ํ์ผ ํ์ฑ
python main.py --cli parse --file document.pdf --framework DoclingFramework
# ์ด๋ฏธ์ง OCR (VLM ์ฌ์ฉ)
python main.py --cli parse --file image.png --framework VLMFramework
# ๊ณ ๊ธ ์ต์
python main.py --cli parse \
--file document.pdf \
--framework PDFPlumberFramework \
--kwargs '{"parse_tables":true}' \
--save
์ถ์ถ (Extract)
# ๊ธฐ๋ณธ ์ถ์ถ
python main.py --cli extract --input "ํ๊ธธ๋์
๋๋ค. ์์ธ๋ ์กธ์
ํ ์นด์นด์ค์์ 3๋
๊ทผ๋ฌดํ์ต๋๋ค."
# ํ์ผ์์ ์ถ์ถ
python main.py --cli extract --input ./sample.txt --schema schema_han
# ๊ณ ๊ธ ์ต์
python main.py --cli extract \
--input "ํ
์คํธ ๋ด์ฉ" \
--schema schema_han \
--retries 3 \
--kwargs '{"temperature":0.1,"timeout":900}' \
--save
ํ๊ฐ (Evaluation)
# ๊ธฐ๋ณธ ํ๊ฐ
python main.py --cli eval \
--pred result/extraction/latest/result.json \
--gt data/๋ฆฌ๋ฉค๋ฒ-s1.json
# ์ปค์คํ
ํ๊ฐ ๊ธฐ์ค ์ฌ์ฉ
python main.py --cli eval \
--pred result/extraction/latest/result.json \
--gt data/๋ฆฌ๋ฉค๋ฒ-s1.json \
--criteria evaluation/criteria/custom_criteria.json \
--save
์๊ฐํ (Visualization)
# Streamlit ๋์๋ณด๋ ์คํ
python main.py --cli viz --eval-result result/evaluation/latest/eval_result.json
# ์ ์ HTML ์์ฑ
python main.py --cli viz \
--eval-result result/evaluation/latest/eval_result.json \
--html \
--out result/visualization/custom_dir
๐ ์ํฌํ๋ก์ฐ ์ฌ์ฉ๋ฒ
์ํฌํ๋ก์ฐ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด parsing, extraction, evaluation ๋จ๊ณ๋ฅผ YAML ์ค์ ํ์ผ์ ํตํด ํ ๋ฒ์ ์คํํ ์ ์์ต๋๋ค. ์ฌ๋ฌ ํ์ฑ ๋ฐฉ๋ฒ๊ณผ ์ถ์ถ ์ค์ ์ ์กฐํฉ์ ์๋์ผ๋ก ์คํํ์ฌ ์ต์ ์ ๊ฒฐ๊ณผ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
์ฃผ์ ํน์ง
- ๋ค๋จ๊ณ ํตํฉ ์คํ: parsing โ extraction โ evaluation ํ์ดํ๋ผ์ธ
- ์กฐํฉ ์คํ: ์ฌ๋ฌ ํ์ฑ ์ค์ ร ์ฌ๋ฌ ์ถ์ถ ์ค์ ์ ๋ชจ๋ ์กฐํฉ ์๋ ์คํ
- ์ค์ ๊ธฐ๋ฐ: YAML ํ์ผ๋ก ๋ชจ๋ ํ๋ผ๋ฏธํฐ ๊ด๋ฆฌ
- ๊ธฐ์กด ์ฝ๋ ์ฌ์ฌ์ฉ: ๊ธฐ์กด CLI ๊ธฐ๋ฅ๋ค์ ๊ทธ๋๋ก ํ์ฉ
- ํ์ฅ์ฑ: ์๋ก์ด ๋จ๊ณ๋ ํ๋ ์์ํฌ ์ฝ๊ฒ ์ถ๊ฐ ๊ฐ๋ฅ
๋น ๋ฅธ ์์
# 1. ํ
ํ๋ฆฟ ์์ฑ
python workflow_cli.py workflow template --output my_workflow.yaml
# 2. ์ค์ ํ์ผ ํธ์ง ํ ์คํ
python workflow_cli.py workflow run my_workflow.yaml
์์ 1: ์ถ์ถ๋ง ์คํ (ํ์ฑ ์์)
# test_extraction_only.yaml
name: "extraction_test"
description: "์ถ์ถ ๊ธฐ๋ฅ๋ง ํ
์คํธ"
# ํ์ฑ ์ค์ ์์
parsing: null
# ์ถ์ถ ์ค์ (์ฌ๋ฌ ๊ฐ ๊ฐ๋ฅ)
extraction:
- prompt: "Extract person information"
input_text: "์๋
ํ์ธ์. ๊น์ฒ ์์
๋๋ค. ์์ธ๋ ์กธ์
ํ ์ผ์ฑ์์ 3๋
๊ทผ๋ฌดํ์ต๋๋ค."
schema_name: "schema_han"
framework: "openai"
host_info:
provider: "openai"
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
retries: 2
extra_kwargs:
temperature: 0.1
save: true
evaluation:
enabled: false
์์ 2: ํ์ฑ + ์ถ์ถ ์กฐํฉ ์คํ
# test_parsing_extraction.yaml
name: "full_pipeline_test"
description: "ํ์ฑ๊ณผ ์ถ์ถ ์กฐํฉ ํ
์คํธ"
# ํ์ฑ ์ค์ (2๊ฐ)
parsing:
- file_path: "./document1.pdf"
framework: "docling"
extra_kwargs:
use_ocr: true
save: true
- file_path: "./document1.pdf"
framework: "pypdf"
extra_kwargs: {}
save: true
# ์ถ์ถ ์ค์ (2๊ฐ)
extraction:
- prompt: "Extract person information"
schema_name: "schema_han"
framework: "openai"
host_info:
provider: "openai"
model: "gpt-4o-mini"
api_key: "${OPENAI_API_KEY}"
save: true
- prompt: "Extract detailed career info"
schema_name: "schema_han"
framework: "anthropic"
host_info:
provider: "anthropic"
model: "claude-3-sonnet"
api_key: "${ANTHROPIC_API_KEY}"
save: true
evaluation:
enabled: false
# ์ด 2(parsing) ร 2(extraction) = 4๊ฐ ์กฐํฉ ์คํ:
# 1. docling + openai
# 2. docling + anthropic
# 3. pypdf + openai
# 4. pypdf + anthropic
์ํฌํ๋ก์ฐ ๋ช ๋ น์ด
# ์ํฌํ๋ก์ฐ ์คํ
python workflow_cli.py workflow run config.yaml
# ์ค์ ๊ฒ์ฆ
python workflow_cli.py workflow validate config.yaml
# ํ
ํ๋ฆฟ ์์ฑ
python workflow_cli.py workflow template
python workflow_cli.py workflow template --no-eval # ํ๊ฐ ์ค์ ์ ์ธ
# ๊ณ ๊ธ ์ต์
python workflow_cli.py workflow run config.yaml \
--parallel # ๋ณ๋ ฌ ์คํ
--no-fail-fast # ์คํจํด๋ ๊ณ์ ์งํ
--output ./results # ์ถ๋ ฅ ๋๋ ํ ๋ฆฌ ์ง์
--dry-run # ์ค์ ์คํ ์์ด ๊ฒ์ฆ๋ง
๊ฒฐ๊ณผ ๊ตฌ์กฐ
result/workflow/
โโโ workflow_name_20240824_143022/
โโโ workflow_config.json # ์คํ๋ ์ค์
โโโ workflow_summary.json # ์คํ ์์ฝ
โโโ combination_0_0/ # ์ฒซ ๋ฒ์งธ ์กฐํฉ ๊ฒฐ๊ณผ
โ โโโ parsing_result.txt
โ โโโ extraction_result.json
โ โโโ evaluation_result.json
โโโ combination_0_1/ # ๋ ๋ฒ์งธ ์กฐํฉ ๊ฒฐ๊ณผ
โโโ ...
๋ ์์ธํ ์ํฌํ๋ก์ฐ ์ฌ์ฉ๋ฒ์ WORKFLOW.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๐๏ธ ํ๋ก์ ํธ ๊ตฌ์กฐ
๐ ์ ์ฒด ํ๋ก์ ํธ ๊ตฌ์กฐ
structured_output_kit/
โโโ ๐ main.py # ๐ ๋ฉ์ธ ์ง์
์ (API ์๋ฒ/CLI ์คํ)
โโโ ๐ cli.py # ๐ป Typer ๊ธฐ๋ฐ CLI ์ธํฐํ์ด์ค
โโโ ๐ server/ # ๐ FastAPI ์๋ฒ
โ โโโ main.py # FastAPI ์ฑ ์ค์ ๋ฐ ๋ผ์ฐํฐ ๋ฑ๋ก
โ โโโ config.py # ์๋ฒ ์ค์ ๊ด๋ฆฌ
โ โโโ routers/ # API ์๋ํฌ์ธํธ
โ โ โโโ extraction.py # ๊ตฌ์กฐํ ์ ๋ณด ์ถ์ถ API
โ โ โโโ evaluation.py # ํ๊ฐ API
โ โ โโโ parsing.py # ํ์ฑ API
โ โ โโโ visualization.py # ์๊ฐํ API
โ โ โโโ utils.py # ์ ํธ๋ฆฌํฐ API
โ โโโ models/ # ๋ฐ์ดํฐ ๋ชจ๋ธ
โ โโโ services/ # ๋น์ฆ๋์ค ๋ก์ง ์๋น์ค
โโโ ๐ parsing/ # ๐ ํ์ฑ ๋ชจ๋
โ โโโ core.py # ํ์ฑ ํต์ฌ ๋ก์ง
โ โโโ factory.py # ํ์ฑ ํ๋ ์์ํฌ ํฉํ ๋ฆฌ
โ โโโ utils.py # ํ์ฑ ์ ํธ๋ฆฌํฐ
โ โโโ frameworks/ # ํ์ฑ ํ๋ ์์ํฌ ๊ตฌํ์ฒด
โ โโโ docling_framework.py # IBM Docling (๊ถ์ฅ)
โ โโโ pypdf_framework.py # PyPDF
โ โโโ pdfplumber_framework.py # PDFPlumber
โ โโโ fitz_framework.py # PyMuPDF
โ โโโ markitdown_framework.py # Microsoft MarkItDown
โ โโโ vlm_framework.py # Vision Language Model
โโโ ๐ extraction/ # ๐ง ์ถ์ถ ๋ชจ๋
โ โโโ core.py # ์ถ์ถ ํต์ฌ ๋ก์ง
โ โโโ utils.py # ์ถ์ถ ์ ํธ๋ฆฌํฐ
โ โโโ factory.py # LLM ํ๋ ์์ํฌ ํฉํ ๋ฆฌ
โ โโโ compatibility.yaml # ํ๋ ์์ํฌ-ํธ์คํธ ํธํ์ฑ ๋งคํ
โ โโโ frameworks/ # LLM ํ๋ ์์ํฌ ๊ตฌํ์ฒด
โ โ โโโ openai_framework.py # OpenAI ๋ค์ดํฐ๋ธ
โ โ โโโ anthropic_framework.py # Anthropic ๋ค์ดํฐ๋ธ
โ โ โโโ google_framework.py # Google Gemini ๋ค์ดํฐ๋ธ
โ โ โโโ ollama_framework.py # Ollama ๋ค์ดํฐ๋ธ
โ โ โโโ instructor_framework.py # Instructor
โ โ โโโ langchain_tool_framework.py # LangChain Tool
โ โ โโโ langchain_parser_framework.py # LangChain Parser
โ โ โโโ llamaindex_framework.py # LlamaIndex
โ โ โโโ marvin_framework.py # Marvin
โ โ โโโ mirascope_framework.py # Mirascope
โ โโโ schema/ # ๋ฐ์ดํฐ ์คํค๋ง
โ โโโ schema_han.py # ํ๊ตญ์ด ์ด๋ ฅ์ ์คํค๋ง
โโโ ๐ evaluation/ # ๐ ํ๊ฐ ๋ชจ๋
โ โโโ core.py # ํ๊ฐ ํต์ฌ ๋ก์ง
โ โโโ metrics.py # ํ๊ฐ ๋ฉํธ๋ฆญ (์๋ฒ ๋ฉ ์ ์ฌ๋, ์์ ์ผ์น)
โ โโโ utils.py # ํ๊ฐ ์ ํธ๋ฆฌํฐ
โ โโโ visualizer.py # Streamlit ์๊ฐํ
โ โโโ criteria/ # ํ๊ฐ ๊ธฐ์ค ์ค์ ํ์ผ
โโโ ๐ utils/ # ๐ ๏ธ ๊ณตํต ์ ํธ๋ฆฌํฐ
โ โโโ types.py # ํ์
์ ์ (Request/Response ๋ชจ๋ธ)
โ โโโ logging.py # ๋ก๊น
์ค์
โ โโโ tracing.py # Langfuse ์ถ์ ์ค์
โ โโโ cli_helpers.py # CLI ํฌํผ ํจ์
โ โโโ common.py # ๊ณตํต ๊ธฐ๋ฅ
โ โโโ visualization.py # ์๊ฐํ ํฌํผ
โโโ ๐ data/ # ๐ ์ํ ๋ฐ์ดํฐ
โ โโโ ๋ฆฌ๋ฉค๋ฒ-s1.json # ํ๊ตญ์ด ์ด๋ ฅ์ ์ํ
โ โโโ ๊ตญ๋ฌธ์ด๋ ฅ์(๊ทธ๋ฆผํฌํจ)-s1.json
โ โโโ ...
โโโ ๐ result/ # ๐ ๊ฒฐ๊ณผ ์ ์ฅ์
โโโ parsing/ # ํ์ฑ ๊ฒฐ๊ณผ
โโโ extraction/ # ์ถ์ถ ๊ฒฐ๊ณผ
โโโ evaluation/ # ํ๊ฐ ๊ฒฐ๊ณผ
โโโ visualization/ # ์๊ฐํ ๊ฒฐ๊ณผ
์คํ ๋ชจ๋
- ๐ API ์๋ฒ ๋ชจ๋:
python main.py(๊ธฐ๋ณธ๊ฐ) - ๐ป CLI ๋ชจ๋:
python main.py --cli [command]
ํ์ดํ๋ผ์ธ ํ๋ก์ฐ
graph LR
A[๐ PDF/์ด๋ฏธ์ง] --> B[๐ ํ์ฑ]
B --> C[๐ ํ
์คํธ]
C --> D[๐ง LLM ์ถ์ถ]
D --> E[๐ ๊ตฌ์กฐํ๋ JSON]
E --> F[๐ ํ๊ฐ]
F --> G[๐จ ์๊ฐํ]
H[โ๏ธ ์ค์ ] --> B
H --> D
H --> F
๐ง ์ง์ ํ๋ ์์ํฌ
ํ์ฑ ํ๋ ์์ํฌ
๐ PDF ํ์ฑ ํ๋ ์์ํฌ
| ํ๋ ์์ํฌ | ํน์ง | ์ฉ๋ |
|---|---|---|
| DoclingFramework | IBM ๊ฐ๋ฐ, ์ต์ AI ๊ธฐ๋ฐ | ๋ณต์กํ ๋ ์ด์์, ํ ์ด๋ธ ์ถ์ถ (๊ถ์ฅ) |
| PDFPlumberFramework | ํ ์ด๋ธ ์ถ์ถ ํนํ | ์ ํํ ํ ์ด๋ธ ๋ฐ์ดํฐ ํ์ ์ |
| PyPDFFramework | ๋น ๋ฅด๊ณ ๊ฐ๋ฒผ์ | ๋จ์ํ ํ ์คํธ ์ถ์ถ |
| FitzFramework | PyMuPDF ๊ธฐ๋ฐ | ๊ณ ์ฑ๋ฅ, ๋ค์ํ ํฌ๋งท ์ง์ |
| MarkItDownFramework | Microsoft ๊ฐ๋ฐ | Office ๋ฌธ์, ๋ค์ํ ํ์ ์ง์ |
๐ผ๏ธ ์ด๋ฏธ์ง/OCR ํ๋ ์์ํฌ
| ํ๋ ์์ํฌ | ๋ชจ๋ธ ์ง์ | ํน์ง |
|---|---|---|
| VLMFramework | OpenAI GPT-4V, Google Gemini | ๋ฉํฐ๋ชจ๋ฌ OCR, ์ดํด๋ ฅ ๋์ |
LLM ํธ์คํธ๋ณ ์ง์ ํ๋ ์์ํฌ
๐ค OpenAI
- โ OpenAIFramework - ๋ค์ดํฐ๋ธ Structured Outputs
- โ InstructorFramework - ํ์ ์์ ์ฑ ๊ฐํ
- โ LangchainToolFramework - Tool ๊ธฐ๋ฐ ์ถ์ถ
- โ LangchainParserFramework - ํ์ ๊ธฐ๋ฐ ์ถ์ถ
- โ LlamaIndexFramework - ๋ฐ์ดํฐ ์ค์ฌ ์ถ์ถ
- โ MarvinFramework - AI ์์ง๋์ด๋ง ๋๊ตฌ
- โ MirascopeFramework - ํ๋์ LLM ๋ผ์ด๋ธ๋ฌ๋ฆฌ
๐ญ Anthropic
- โ AnthropicFramework - ๋ค์ดํฐ๋ธ Tool Use
- โ InstructorFramework - Anthropic ์ง์
- โ LangchainToolFramework - Claude ํตํฉ
- โ LangchainParserFramework - Claude ํ์
- โ MarvinFramework - Claude ์ง์
๐ Google
- โ GoogleFramework - Gemini ๋ค์ดํฐ๋ธ JSON ๋ชจ๋
- โ InstructorFramework - Gemini ์ง์
- โ LangchainToolFramework - Gemini ํตํฉ
- โ LangchainParserFramework - Gemini ํ์
- โ LlamaIndexFramework - Gemini ์ง์
- โ MarvinFramework - Gemini ์ง์
- โ MirascopeFramework - Gemini ์ง์
๐ฆ Ollama (๋ก์ปฌ)
- โ OllamaFramework - ๋ค์ดํฐ๋ธ JSON ๊ตฌ์กฐํ
- โ OpenAIFramework - OpenAI ํธํ ๋ชจ๋
- โ InstructorFramework - ๋ก์ปฌ ๋ชจ๋ธ ์ง์
- โ LangchainToolFramework - Ollama ํตํฉ
- โ LangchainParserFramework - Ollama ํ์
- โ LlamaIndexFramework - Ollama ์ง์
- โ MarvinFramework - Ollama ์ง์
- โ MirascopeFramework - Ollama ์ง์
๐ OpenAI-Compatible
vLLM, Together AI, Groq ๋ฑ OpenAI ํธํ ์๋ฒ ์ง์
- โ OpenAIFramework - ํธํ ๋ชจ๋
- โ InstructorFramework - ํธํ ์ง์
- โ LangchainToolFramework - ํธํ ํตํฉ
- โ LangchainParserFramework - ํธํ ํ์
- โ LlamaIndexFramework - ํธํ ์ง์
- โ MarvinFramework - ํธํ ์ง์
- โ MirascopeFramework - ํธํ ์ง์
๐ ํ์ฑ ์์คํ
์ง์ ํ์ผ ํ์
๐ ์ง์ ํ์ผ ํ์ ๋ชฉ๋ก
| ํ์ | ํ์ฅ์ | ์ถ์ฒ ํ๋ ์์ํฌ | ํน์ง |
|---|---|---|---|
.pdf |
DoclingFramework | ๋ ์ด์์, ํ ์ด๋ธ ๋ณด์กด | |
| ์ด๋ฏธ์ง | .png, .jpg, .jpeg |
VLMFramework | OCR + ์ดํด |
| Word | .docx |
MarkItDownFramework | Office ๋ฌธ์ |
| PowerPoint | .pptx |
MarkItDownFramework | ์ฌ๋ผ์ด๋ ํ ์คํธ |
| Excel | .xlsx |
MarkItDownFramework | ์คํ๋ ๋์ํธ |
ํ์ฑ ์์
# ๋ณต์กํ PDF ๋ฌธ์ (ํ
์ด๋ธ ํฌํจ)
python main.py --cli parse --file report.pdf --framework DoclingFramework
# ์ด๋ฏธ์ง ๊ธฐ๋ฐ ๋ฌธ์ (OCR)
python main.py --cli parse --file scan.png --framework VLMFramework
# Office ๋ฌธ์
python main.py --cli parse --file document.docx --framework MarkItDownFramework
๐ ์คํค๋ง์ ํ๊ฐ
๊ธฐ๋ณธ ์คํค๋ง (schema_han)
ํ๊ตญ์ด ์ด๋ ฅ์ ์ ๋ณด ์ถ์ถ์ ์ํ ํฌ๊ด์ ์ธ ๊ตฌ์กฐํ๋ ์คํค๋ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
๐ ์คํค๋ง ๊ตฌ์กฐ ์์ธ
class ExtractInfo(BaseModel):
# ๊ธฐ๋ณธ ์ ๋ณด
personal_info: Optional[PersonalInfo] # ๊ฐ์ธ์ ๋ณด (์ด๋ฆ, ์ฐ๋ฝ์ฒ, ์ฃผ์ ๋ฑ)
summary_info: Optional[SummaryInfo] # ์์ฝ์ ๋ณด (๊ฐ๋ต์๊ฐ, ํต์ฌ์ญ๋)
# ํ๋ ฅ ๋ฐ ๊ต์ก
educations: List[Education] # ํ๋ ฅ์ฌํญ (ํ๊ต, ์ ๊ณต, ํ์ ๋ฑ)
education_programs: List[EducationProgram] # ๊ต์ก๊ณผ์ (์ธ๋ถ ๊ต์ก, ์ฐ์ ๋ฑ)
overseas_experiences: List[OverseasExperience] # ํด์ธ์ฐ์ (๊ตญ๊ฐ, ๊ธฐ๊ฐ, ๋ด์ฉ)
# ๊ฒฝ๋ ฅ ๋ฐ ์ฑ๊ณผ
careers: List[Career] # ๊ฒฝ๋ ฅ์ฌํญ (ํ์ฌ, ์ง๋ฌด, ๋ด๋น์
๋ฌด ๋ฑ)
certificates: List[Certificate] # ์๊ฒฉ์ฆ (์๊ฒฉ๋ช
, ๋ฐํ์ฒ, ์ ์ ๋ฑ)
awards: List[Award] # ์์/๊ณต๋ชจ์ (์์๋ช
, ๊ธฐ๊ด, ์ผ์)
# ๊ธฐํ ์ ๋ณด
employment_preference: Optional[EmploymentPreference] # ์ทจ์
์ฐ๋ (๋ณดํ, ์ฅ์ ๋ฑ)
military_service: Optional[MilitaryService] # ๋ณ์ญ (๊ตฐ๋ณ, ๊ณ๊ธ, ๊ธฐ๊ฐ)
cover_letter: Optional[CoverLetter] # ์๊ธฐ์๊ฐ์
etc_info: Optional[EtcInfo] # ๊ธฐํ ์ ๋ณด
์ฃผ์ ํ๋ ์์:
- PersonalInfo: ์ด๋ฆ, ์ฑ๋ณ, ์๋ ์์ผ, ์ฐ๋ฝ์ฒ, ์ด๋ฉ์ผ, ์ฃผ์, SNS ๋งํฌ
- Career: ํ์ฌ๋ช , ์ ์ฌ/ํด์ฌ์ผ, ๋ด๋น์ ๋ฌด, ์ฐ๋ด, ์ง์ฑ , ์ง๊ธ, ๊ณ ์ฉํํ
- Education: ํ๊ต์ข ๋ฅ, ํ๊ต๋ช , ์ ๊ณต, ํ์, ํ์ , ์กธ์ ์ํ
ํ๊ฐ ์์คํ
ํ์ด๋ธ๋ฆฌ๋ ํ๊ฐ ๋ฐฉ์์ ์ฌ์ฉํ์ฌ ์ ํ๋์ ์๋ฏธ์ ์ ์ฌ์ฑ์ ๋ชจ๋ ์ธก์ ํฉ๋๋ค.
๐ ํ๊ฐ ๋ฉํธ๋ฆญ ์์ธ
1. ์์ ์ผ์น (Exact Match)
- ๋ฌธ์์ด์ด ์ ํํ ์ผ์นํ๋์ง ํ์ธ
- ์ด๋ฆ, ์ด๋ฉ์ผ, ๋ ์ง ๋ฑ ์ ํ์ฑ์ด ์ค์ํ ํ๋์ ์ฌ์ฉ
2. ์๋ฒ ๋ฉ ์ ์ฌ๋ (Embedding Similarity)
- ์ฝ์ฌ์ธ ์ ์ฌ๋๋ฅผ ํตํ ์๋ฏธ์ ์ ์ฌ์ฑ ์ธก์
- ์๊ธฐ์๊ฐ์, ๋ด๋น์ ๋ฌด ๋ฑ ํ ์คํธ ํ๋์ ์ฌ์ฉ
- ์ง์ ๋ชจ๋ธ: OpenAI, HuggingFace (ko-sroberta-multitask)
3. ํ์ด๋ธ๋ฆฌ๋ ์ค์ฝ์ด
- ์์ ์ผ์น์ ์๋ฒ ๋ฉ ์ ์ฌ๋์ ๊ฐ์ค ํ๊ท
- ํ๋๋ณ ๋ง์ถค ๊ฐ์ค์น ์ค์ ๊ฐ๋ฅ
4. ํ๊ฐ๋ฆฌ์ ์๊ณ ๋ฆฌ์ฆ
- ๋ฆฌ์คํธ ์์ ๊ฐ ์ต์ ๋งค์นญ
- ๊ฒฝ๋ ฅ, ํ๋ ฅ ๋ฑ ์์๊ฐ ๋ค๋ฅผ ์ ์๋ ๋ฐฐ์ด ๋ฐ์ดํฐ ํ๊ฐ
# ํ๋๋ณ ํ๊ฐ ๋ฐฉ์ ์์
evaluation_criteria = {
"personal_info.name": {"method": "exact"}, # ์ด๋ฆ์ ์ ํํด์ผ ํจ
"personal_info.email": {"method": "exact"}, # ์ด๋ฉ์ผ๋ ์ ํํด์ผ ํจ
"summary_info.brief_introduction": {"method": "embedding"}, # ์๊ฐ๊ธ์ ์๋ฏธ์ ์ ์ฌ์ฑ
"careers": {"method": "hybrid", "exact_weight": 0.3, "embedding_weight": 0.7}
}
๐จ ์๊ฐํ
Streamlit ๋์๋ณด๋
์ธํฐ๋ํฐ๋ธ ๋์๋ณด๋๋ก ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ค์๊ฐ์ผ๋ก ํ์ํ ์ ์์ต๋๋ค.
๐ ๋์๋ณด๋ ๊ธฐ๋ฅ
์ฃผ์ ๊ธฐ๋ฅ:
- ๐ ์ ์ฒด ์ฑ๋ฅ ๊ฐ์: ์ด์ , ์์ ์ผ์น์จ, ์๋ฒ ๋ฉ ์ ์ฌ๋
- ๐ ํ๋๋ณ ์์ธ ๋ถ์: ๊ฐ ํ๋์ ์ ์ ๋ถํฌ ๋ฐ ์์ธ ๋น๊ต
- ๐ ์์ธก vs ์ ๋ต ๋น๊ต: ์ค์ ๊ฐ๊ณผ ์์ธก ๊ฐ์ ์๊ฐ์ ๋น๊ต
- ๐ ์ฑ๋ฅ ๋ถํฌ ์ฐจํธ: ์ ์ ํ์คํ ๊ทธ๋จ ๋ฐ ๋ถํฌ ์๊ฐํ
- ๐ฏ ์ค๋ฅ ๋ถ์: ๋ฎ์ ์ ์๋ฅผ ๋ฐ์ ํ๋์ ์์ธ ๋ถ์
์คํ ๋ฐฉ๋ฒ:
python main.py --cli viz --eval-result path/to/eval_result.json
์ ์ HTML ๋ฆฌํฌํธ
๊ฐ๋จํ HTML ๋ฆฌํฌํธ๋ก ๊ฒฐ๊ณผ๋ฅผ ๊ณต์ ํ ์ ์์ต๋๋ค.
์์ฑ ๋ฐฉ๋ฒ:
# CLI๋ก ์์ฑ
python main.py --cli viz --eval-result path/to/eval_result.json --html
# API๋ก ์์ฑ
curl -X POST http://localhost:8000/v1/visualization/generate \
-H 'Content-Type: application/json' \
-d '{"eval_result_path": "path/to/eval_result.json"}'
๐ ๏ธ ๊ฐ๋ฐ ๊ฐ์ด๋
๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ
# ๊ฐ๋ฐ ๋ชจ๋๋ก ์๋ฒ ์คํ
python main.py --reload
# ํ
์คํธ ์คํ (๊ตฌํ ์์ )
pytest tests/
# ์ฝ๋ ํฌ๋งทํ
(๊ถ์ฅ)
black .
ruff check .
์ปค์คํ ์คํค๋ง ์ถ๊ฐ
๐ ์๋ก์ด ์คํค๋ง ์์ฑ ๊ฐ์ด๋
extraction/schema/๋๋ ํ ๋ฆฌ์ ์ ์คํค๋ง ํ์ผ ์์ฑ- Pydantic v2 BaseModel์ ์์๋ฐ๋
ExtractInfoํด๋์ค ์ ์ - ์คํค๋ง ์ด๋ฆ์ผ๋ก ํ์ผ์ ์ ๊ทผ ๊ฐ๋ฅ
# extraction/schema/custom_schema.py
from pydantic import BaseModel, Field
from typing import Optional, List
class PersonInfo(BaseModel):
name: Optional[str] = Field(description="์ด๋ฆ", default=None)
age: Optional[int] = Field(description="๋์ด", default=None)
class SkillInfo(BaseModel):
skill_name: Optional[str] = Field(description="๊ธฐ์ ๋ช
", default=None)
proficiency: Optional[str] = Field(description="์๋ จ๋", default=None)
class ExtractInfo(BaseModel):
person: Optional[PersonInfo] = Field(description="์ธ๋ฌผ์ ๋ณด", default=None)
skills: List[SkillInfo] = Field(description="๊ธฐ์ ์คํ", default_factory=list)
์ปค์คํ ํ์ฑ ํ๋ ์์ํฌ ์ถ๊ฐ
๐ง ์๋ก์ด ํ์ฑ ํ๋ ์์ํฌ ๊ตฌํ
parsing/frameworks/๋๋ ํ ๋ฆฌ์ ์ ํ๋ ์์ํฌ ํ์ผ ์์ฑBaseFramework๋ฅผ ์์๋ฐ๋ ํด๋์ค ๊ตฌํ
# parsing/frameworks/custom_framework.py
from structured_output_kit.parsing.base import BaseFramework
class CustomFramework(BaseFramework):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# ์ด๊ธฐํ ๋ก์ง
def run(self, retries: int = 1) -> tuple[str, bool, float]:
# ํ์ฑ ๋ก์ง ๊ตฌํ
try:
content = self.parse_file(self.file_path)
return content, True, 0.5 # content, success, latency
except Exception as e:
return f"ERROR: {str(e)}", False, 0
def parse_file(self, file_path: str) -> str:
# ์ค์ ํ์ฑ ๋ก์ง
pass
์ปค์คํ LLM ํ๋ ์์ํฌ ์ถ๊ฐ
๐ค ์๋ก์ด LLM ํ๋ ์์ํฌ ๊ตฌํ
extraction/frameworks/๋๋ ํ ๋ฆฌ์ ์ ํ๋ ์์ํฌ ํ์ผ ์์ฑBaseFramework๋ฅผ ์์๋ฐ๋ ํด๋์ค ๊ตฌํcompatibility.yaml์ ํธ์คํธ ํธํ์ฑ ์ ๋ณด ์ถ๊ฐ
# extraction/frameworks/custom_framework.py
from structured_output_kit.extraction.base import BaseFramework, experiment
class CustomFramework(BaseFramework):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# LLM ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
def run(self, retries: int, inputs: dict = {}) -> tuple[list[Any], float, list[float]]:
@experiment(retries=retries)
def run_experiment(inputs):
# LLM ํธ์ถ ๋ก์ง
response = self.client.complete(
prompt=self.prompt.format(**inputs),
response_model=self.response_model
)
return response
predictions, percent_successful, latencies = run_experiment(inputs)
return predictions, percent_successful, latencies
๊ธฐ์ฌ ๋ฐฉ๋ฒ
- ๐ด Fork the repository
- ๐ Create a feature branch:
git checkout -b feature/amazing-feature - ๐พ Commit your changes:
git commit -m 'Add amazing feature' - ๐ค Push to the branch:
git push origin feature/amazing-feature - ๐ฏ Open a Pull Request
๏ฟฝ ์ฑ๋ฅ ๋ฒค์น๋งํฌ
๐จ ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค
๐ ํฌํธ ์ถฉ๋
# ๋ค๋ฅธ ํฌํธ ์ฌ์ฉ
python main.py --port 8080
๐ API ํค ์ค๋ฅ
# .env ํ์ผ ํ์ธ
cat .env | grep API_KEY
# ํ๊ฒฝ ๋ณ์ ์ง์ ์ค์
export OPENAI_API_KEY=your-key-here
๐ฆ ์์กด์ฑ ๋ฌธ์
# ๊ฐ์ํ๊ฒฝ ์ฌ์์ฑ
rm -rf .venv
uv venv
source .venv/bin/activate
uv sync
๐ ๋๋ฆฐ ์ฒซ ์คํ
- HuggingFace ๋ชจ๋ธ ๋ค์ด๋ก๋๋ก ์ธํ ์ง์ฐ
- ๋คํธ์ํฌ ์ฐ๊ฒฐ ์ํ ํ์ธ
๐พ ๋์ฉ๋ ํ์ผ ์ฒ๋ฆฌ
# MAX_FILE_SIZE ์กฐ์ (.env)
MAX_FILE_SIZE=52428800 # 50MB
๐ ๊ฒฐ๊ณผ๋ฌผ ๊ตฌ์กฐ
result/
โโโ ๐ extraction/ # ์ถ์ถ ๊ฒฐ๊ณผ
โ โโโ 20250823_1430/ # ํ์์คํฌํ ํด๋
โ โโโ result.json # ์ถ์ถ๋ JSON ๊ฒฐ๊ณผ
โ โโโ extraction.log # ์ถ์ถ ๋ก๊ทธ
โ โโโ metadata.json # ์คํ ๋ฉํ๋ฐ์ดํฐ
โโโ ๐ evaluation/ # ํ๊ฐ ๊ฒฐ๊ณผ
โ โโโ 20250823_1435/
โ โโโ eval_result.json # ํ๊ฐ ๊ฒฐ๊ณผ
โ โโโ pred.json # ์์ธก JSON (์ ๊ทํ๋จ)
โ โโโ gt.json # ์ ๋ต JSON
โ โโโ criteria.json # ์ฌ์ฉ๋ ํ๊ฐ ๊ธฐ์ค
โ โโโ evaluation.log # ํ๊ฐ ๋ก๊ทธ
โโโ ๐ visualization/ # ์๊ฐํ ๊ฒฐ๊ณผ
โโโ 20250823_1440/
โโโ visualization.html # HTML ๋ฆฌํฌํธ
๐ ์ฑ๋ฅ ๋ฒค์น๋งํฌ
๐ ์ํ ๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ
LLM ํ๋ ์์ํฌ ์ฑ๋ฅ ๋น๊ต (ํ๊ตญ์ด ์ด๋ ฅ์ ๋ฐ์ดํฐ์ )
| ํ๋ ์์ํฌ | ํธ์คํธ | ๋ชจ๋ธ | ์ ํ๋ | ์๋ต์๊ฐ | ์์ ์ฑ | ํน์ง |
|---|---|---|---|---|---|---|
| OpenAIFramework | OpenAI | gpt-4o-mini | 94.2% | 1.2s | โญโญโญโญโญ | ๋ค์ดํฐ๋ธ Structured Outputs |
| AnthropicFramework | Anthropic | claude-3-5-sonnet | 95.1% | 2.1s | โญโญโญโญโญ | Tool Use ๊ธฐ๋ฐ |
| GoogleFramework | gemini-1.5-flash | 92.8% | 1.8s | โญโญโญโญ | JSON ๋ชจ๋ | |
| InstructorFramework | OpenAI | gpt-4o-mini | 93.8% | 1.4s | โญโญโญโญโญ | ํ์ ๊ฒ์ฆ ๊ฐํ |
| LangchainToolFramework | OpenAI | gpt-4o-mini | 92.5% | 1.8s | โญโญโญโญ | Tool ๊ธฐ๋ฐ |
| OllamaFramework | Ollama | llama3.1:8b | 88.3% | 3.2s | โญโญโญ | ๋ก์ปฌ ์คํ |
ํ์ฑ ํ๋ ์์ํฌ ์ฑ๋ฅ ๋น๊ต
| ํ๋ ์์ํฌ | ํ์ผ ํ์ | ์ ํ๋ | ์๋ | ํน์ง |
|---|---|---|---|---|
| DoclingFramework | 95.2% | ์ค๊ฐ | ํ ์ด๋ธ, ๋ ์ด์์ ๋ณด์กด | |
| PDFPlumberFramework | 91.8% | ๋น ๋ฆ | ํ ์ด๋ธ ์ถ์ถ ํนํ | |
| VLMFramework | ์ด๋ฏธ์ง | 89.7% | ๋๋ฆผ | OCR + ์ดํด๋ ฅ |
| PyPDFFramework | 87.3% | ๋งค์ฐ ๋น ๋ฆ | ๋จ์ ํ ์คํธ |
*๊ฒฐ๊ณผ๋ ์ํ ๋ฐ์ดํฐ์ ๊ธฐ์ค์ด๋ฉฐ, ์ค์ ์ฑ๋ฅ์ ๋ฌธ์ ๋ณต์ก๋์ ๋ชจ๋ธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค.
๐ ํธ๋ฌ๋ธ์ํ
๐จ ์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค
๐ ํฌํธ ์ถฉ๋
# ๋ค๋ฅธ ํฌํธ ์ฌ์ฉ
python main.py --port 8080
๐ API ํค ์ค๋ฅ
# .env ํ์ผ ํ์ธ
cat .env | grep API_KEY
# ํ๊ฒฝ ๋ณ์ ์ง์ ์ค์
export OPENAI_API_KEY=your-key-here
๐ฆ ์์กด์ฑ ๋ฌธ์
# ๊ฐ์ํ๊ฒฝ ์ฌ์์ฑ
rm -rf .venv
uv venv
source .venv/bin/activate
uv sync
๐ ๋๋ฆฐ ์ฒซ ์คํ
- HuggingFace ๋ชจ๋ธ ๋ค์ด๋ก๋๋ก ์ธํ ์ง์ฐ
- VLM ๋ชจ๋ธ ๋ก๋ฉ ์๊ฐ
- ๋คํธ์ํฌ ์ฐ๊ฒฐ ์ํ ํ์ธ
๐พ ๋์ฉ๋ ํ์ผ ์ฒ๋ฆฌ
# MAX_FILE_SIZE ์กฐ์ (.env)
MAX_FILE_SIZE=52428800 # 50MB
๐ PDF ํ์ฑ ์คํจ
- ์ค์บ๋ PDF์ ๊ฒฝ์ฐ VLMFramework ์ฌ์ฉ ๊ถ์ฅ
- ์ํธํ๋ PDF๋ ์ง์ํ์ง ์์
- ๋ณต์กํ ๋ ์ด์์์ DoclingFramework ๊ถ์ฅ
๐ง ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ค๋ฅ
# HuggingFace ๋ชจ๋ธ ์บ์ ํด๋ฆฌ์ด
rm -rf ~/.cache/huggingface/
# ๋ค๋ฅธ ์๋ฒ ๋ฉ ๋ชจ๋ธ ์ฌ์ฉ
HUGGINGFACE_EMBED_MODELS=sentence-transformers/all-MiniLM-L6-v2
๐ ํ๋ ์์ํฌ ํธํ์ฑ ๋ฌธ์
compatibility.yamlํ์ผ์์ ์ง์ ์กฐํฉ ํ์ธ- ์ง์ํ์ง ์๋ ์กฐํฉ์ ์ค๋ฅ ๋ฉ์์ง๋ก ์๋ด
๐ ๊ฒฐ๊ณผ๋ฌผ ๊ตฌ์กฐ
๐ ๊ฒฐ๊ณผ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
result/
โโโ ๐ parsing/ # ํ์ฑ ๊ฒฐ๊ณผ
โ โโโ 20250824_1430/ # ํ์์คํฌํ ํด๋
โ โโโ content.txt # ํ์ฑ๋ ํ
์คํธ
โ โโโ parsing.log # ํ์ฑ ๋ก๊ทธ
โ โโโ metadata.json # ํ์ฑ ๋ฉํ๋ฐ์ดํฐ
โโโ ๐ extraction/ # ์ถ์ถ ๊ฒฐ๊ณผ
โ โโโ 20250824_1435/
โ โโโ result.json # ์ถ์ถ๋ JSON ๊ฒฐ๊ณผ
โ โโโ extraction.log # ์ถ์ถ ๋ก๊ทธ
โ โโโ metadata.json # ์คํ ๋ฉํ๋ฐ์ดํฐ (ํ๋ ์์ํฌ, ๋ชจ๋ธ ๋ฑ)
โโโ ๐ evaluation/ # ํ๊ฐ ๊ฒฐ๊ณผ
โ โโโ 20250824_1440/
โ โโโ eval_result.json # ํ๊ฐ ๊ฒฐ๊ณผ (์ ์, ๋ฉํธ๋ฆญ)
โ โโโ pred.json # ์์ธก JSON (์ ๊ทํ๋จ)
โ โโโ gt.json # ์ ๋ต JSON
โ โโโ criteria.json # ์ฌ์ฉ๋ ํ๊ฐ ๊ธฐ์ค
โ โโโ evaluation.log # ํ๊ฐ ๋ก๊ทธ
โโโ ๐ visualization/ # ์๊ฐํ ๊ฒฐ๊ณผ
โโโ 20250824_1445/
โโโ visualization.html # HTML ๋ฆฌํฌํธ
๐ ์ฌ์ฉ ์ฌ๋ก
๐ผ ๋น์ฆ๋์ค ํ์ฉ ์ฌ๋ก
1. ์ธ์ฌ ๋ด๋น์
- ์ด๋ ฅ์ ์๋ ๋ถ์ ๋ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ถ
- ์ง์์ ์ ๋ณด ์๋ ์ถ์ถ ๋ฐ ๋ถ๋ฅ
- ์ฑ์ฉ ํ๋ก์ธ์ค ์๋ํ
2. ์ฐ๊ตฌ์
- LLM ๊ตฌ์กฐํ ์ถ๋ ฅ ์ฑ๋ฅ ๋ฒค์น๋งํน
- ๋ค์ํ ํ๋ ์์ํฌ ๋น๊ต ์ฐ๊ตฌ
- ํ๊ฐ ๋ฉํธ๋ฆญ ๊ฐ๋ฐ ๋ฐ ๊ฒ์ฆ
3. ๊ฐ๋ฐ์
- ๋ฌธ์ ์ฒ๋ฆฌ ์์คํ ํ๋กํ ํ์ดํ
- LLM ํตํฉ ํ ์คํธ ํ๊ฒฝ
- ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ ๊ฒ์ฆ
4. ๋ฐ์ดํฐ ์ฌ์ด์ธํฐ์คํธ
- ๋น๊ตฌ์กฐํ ๋ฐ์ดํฐ ๊ตฌ์กฐํ
- ๋ชจ๋ธ ์ฑ๋ฅ ๋ถ์ ๋ฐ ์ต์ ํ
- ๋ฐ์ดํฐ ํ์ง ํ๊ฐ
๏ฟฝ ๊ณ ๊ธ ์ฌ์ฉ๋ฒ
๐๏ธ ๊ณ ๊ธ ์ค์ ๋ฐ ์ปค์คํฐ๋ง์ด์ง
๋ฐฐ์น ์ฒ๋ฆฌ
# ์ฌ๋ฌ ํ์ผ ์ผ๊ด ์ฒ๋ฆฌ
for file in documents/*.pdf; do
python main.py --cli parse --file "$file" --framework DoclingFramework
done
์ฑ๋ฅ ์ต์ ํ
# ๋ฐฐ์น ํฌ๊ธฐ ์กฐ์ (API)
extra_kwargs = {
"temperature": 0.1,
"timeout": 60,
"max_tokens": 4096
}
์ปค์คํ ํ๊ฐ ๊ธฐ์ค
{
"personal_info.name": {
"method": "exact",
"weight": 1.0
},
"careers.*.responsibilities": {
"method": "embedding",
"weight": 0.8,
"embedding_model": "jhgan/ko-sroberta-multitask"
}
}
Langfuse ํตํฉ ๋ชจ๋ํฐ๋ง
# ์ถ์ ID๋ก ์คํ
python main.py --cli extract \
--input "ํ
์คํธ" \
--trace-id "custom-trace-123"
๏ฟฝ๐ ๋ผ์ด์ ์ค
์ด ํ๋ก์ ํธ๋ MIT ๋ผ์ด์ ์ค ํ์ ๋ฐฐํฌ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ LICENSE ํ์ผ์ ์ฐธ์กฐํ์ธ์.
๐ ๊ฐ์ฌ์ ๋ง
์ด ํ๋ก์ ํธ๋ ๋ค์ ์คํ์์ค ํ๋ก์ ํธ๋ค์ ์ํฅ์ ๋ฐ์์ต๋๋ค:
๐ ์์กด์ฑ ํ๋ก์ ํธ๋ค
LLM ํ๋ ์์ํฌ
- Instructor - OpenAI ๊ตฌ์กฐํ ์ถ๋ ฅ
- LangChain - LLM ์ ํ๋ฆฌ์ผ์ด์ ํ๋ ์์ํฌ
- LlamaIndex - ๋ฐ์ดํฐ ํ๋ ์์ํฌ
- Marvin - AI ์์ง๋์ด๋ง ํดํท
- Mirascope - LLM ๋ผ์ด๋ธ๋ฌ๋ฆฌ
ํ์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
- Docling - IBM ๋ฌธ์ ํ์ฑ
- PDFPlumber - PDF ํ ์ด๋ธ ์ถ์ถ
- PyPDF - PDF ์ฒ๋ฆฌ
- MarkItDown - Microsoft ๋ฌธ์ ๋ณํ
์น ํ๋ ์์ํฌ
๋ชจ๋ํฐ๋ง & ์ถ์
- Langfuse - LLM ์ถ์ ๋ฐ ๋ชจ๋ํฐ๋ง
๐ ์ฐ๋ฝ์ฒ
- ์์ฑ์: Bae ChangHyun
- GitHub: @Bae-ChangHyun
- ์ด์ ๋ฆฌํฌํธ: GitHub Issues
- ํ ๋ก : GitHub Discussions
๐ฏ ๋ก๋๋งต
๐ง ๊ฐ๋ฐ ๊ณํ
v0.2.0 (์์ )
- ํ ์คํธ ์ค์ํธ ๊ตฌํ
- Docker ์ปดํฌ์ฆ ์ค์
- ์น UI ์ธํฐํ์ด์ค ์ถ๊ฐ
- ๋ ๋ง์ ํ์ฑ ํ๋ ์์ํฌ ์ง์
v0.3.0 (์์ )
- ์ค์๊ฐ ์คํธ๋ฆฌ๋ฐ ์ฒ๋ฆฌ
- ๋ถ์ฐ ์ฒ๋ฆฌ ์ง์
- ํด๋ผ์ฐ๋ ๋ฐฐํฌ ๊ฐ์ด๋
- ์ฑ๋ฅ ์ต์ ํ
์ฅ๊ธฐ ๊ณํ
- ๋ค๊ตญ์ด ์คํค๋ง ์ง์
- ์๋ ์คํค๋ง ์์ฑ
- ๋ฅ๋ฌ๋ ๊ธฐ๋ฐ ํ๊ฐ ๋ฉํธ๋ฆญ
- ํ๋ฌ๊ทธ์ธ ์์คํ
โญ ์ด ํ๋ก์ ํธ๊ฐ ๋์์ด ๋์ จ๋ค๋ฉด Star๋ฅผ ๋๋ฌ์ฃผ์ธ์! โญ
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file structured_output_kit-0.1.0.tar.gz.
File metadata
- Download URL: structured_output_kit-0.1.0.tar.gz
- Upload date:
- Size: 77.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0eb5a275ef1d270af3415097ad52669669db4b94dde9b6fe4be096a1e4bc4e3
|
|
| MD5 |
d1c1db64c89fb1b604dd95daa09c77e2
|
|
| BLAKE2b-256 |
fc91c920f3007c91f7267648ffc518b6e3a9fac81a56e82b25537d53d31dc7df
|
File details
Details for the file structured_output_kit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: structured_output_kit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 73.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00e68cd70f7dbdcc97306c940dd31227380515d7638fafd45730ba7926295716
|
|
| MD5 |
de803e38a8a713a37adf68b5678a3f04
|
|
| BLAKE2b-256 |
208091c704d130a8ce0335e2eb3555af1418187a6008056fd20a7b2251ec9d2a
|