Loading...
Loading...
02-reusable-code-python/pipelines/recipes.py
"""
사전 정의 파이프라인 레시피 5종
자주 사용되는 콘텐츠 변환 시나리오를 레시피로 미리 정의한다.
레시피를 기반으로 PipelineConfig를 즉시 생성할 수 있다.
@source claude-world/notebooklm-skill
@extracted 2026-03-18
@version 1.0.0
의존성:
- pydantic>=2.0 (필수)
사용법:
from pipelines.recipes import get_recipe, list_recipes, create_config_from_recipe
from pipelines.models import SourceInput
# 레시피 조회
recipe = get_recipe("research-to-article")
print(recipe.description)
# 레시피 기반 설정 생성
source = SourceInput(type="url", content="https://example.com/paper")
config = create_config_from_recipe("research-to-article", source)
"""
from __future__ import annotations
import logging
from .models import PipelineConfig, RecipeDefinition, SourceInput
from .types import OutputType, PipelineStage
logger = logging.getLogger(__name__)
# 사전 정의 레시피 레지스트리
RECIPES: dict[str, RecipeDefinition] = {
"research-to-article": RecipeDefinition(
name="research-to-article",
description=(
"연구 자료(논문/URL/텍스트)를 수집하여 구조화된 보고서와 "
"마인드맵을 자동 생성한다. 학술 정리 및 팀 공유에 적합하다."
),
stages=[
PipelineStage.INGEST,
PipelineStage.SYNTHESIZE,
PipelineStage.CREATE,
PipelineStage.PUBLISH,
],
default_outputs=[OutputType.REPORT, OutputType.MIND_MAP],
estimated_cost=0.05,
tags=["research", "academic", "report"],
),
"trend-to-content": RecipeDefinition(
name="trend-to-content",
description=(
"트렌드 뉴스·커뮤니티 포스트를 수집하여 슬라이드 덱과 "
"브리핑 문서를 생성한다. 마케팅·전략 팀의 트렌드 파악에 활용한다."
),
stages=[
PipelineStage.INGEST,
PipelineStage.SYNTHESIZE,
PipelineStage.CREATE,
PipelineStage.PUBLISH,
],
default_outputs=[OutputType.SLIDES, OutputType.BRIEFING],
estimated_cost=0.04,
tags=["trend", "marketing", "content"],
),
"lecture-to-study-kit": RecipeDefinition(
name="lecture-to-study-kit",
description=(
"강의 영상 URL 또는 강의 노트를 입력받아 플래시카드, 퀴즈, "
"학습 가이드를 생성한다. 온라인 강좌 학습자를 위한 레시피."
),
stages=[
PipelineStage.INGEST,
PipelineStage.SYNTHESIZE,
PipelineStage.CREATE,
PipelineStage.PUBLISH,
],
default_outputs=[
OutputType.FLASHCARDS,
OutputType.QUIZ,
OutputType.STUDY_GUIDE,
],
estimated_cost=0.08,
tags=["education", "study", "quiz"],
),
"docs-to-training": RecipeDefinition(
name="docs-to-training",
description=(
"기술 문서(README, API 문서, 위키)를 분석하여 사내 교육용 "
"슬라이드와 오디오 요약을 생성한다. 신규 팀원 온보딩에 활용한다."
),
stages=[
PipelineStage.INGEST,
PipelineStage.SYNTHESIZE,
PipelineStage.CREATE,
PipelineStage.PUBLISH,
],
default_outputs=[OutputType.SLIDES, OutputType.AUDIO, OutputType.STUDY_GUIDE],
estimated_cost=0.07,
tags=["documentation", "training", "onboarding"],
),
"news-to-briefing": RecipeDefinition(
name="news-to-briefing",
description=(
"다수의 뉴스 기사를 수집·분석하여 핵심 브리핑 문서와 "
"타임라인을 생성한다. 일간/주간 뉴스레터 자동화에 적합하다."
),
stages=[
PipelineStage.INGEST,
PipelineStage.SYNTHESIZE,
PipelineStage.CREATE,
PipelineStage.PUBLISH,
],
default_outputs=[OutputType.BRIEFING, OutputType.TIMELINE],
estimated_cost=0.03,
tags=["news", "briefing", "newsletter"],
),
}
def get_recipe(name: str) -> RecipeDefinition:
"""이름으로 레시피를 조회한다.
Args:
name: 레시피 식별자 (kebab-case)
Returns:
RecipeDefinition 인스턴스
Raises:
KeyError: 존재하지 않는 레시피 이름인 경우
사용 예::
recipe = get_recipe("research-to-article")
print(recipe.estimated_cost)
"""
if name not in RECIPES:
available = sorted(RECIPES.keys())
raise KeyError(
f"Recipe '{name}' not found. Available recipes: {available}"
)
logger.debug("레시피 조회: name=%s", name)
return RECIPES[name]
def list_recipes() -> list[RecipeDefinition]:
"""등록된 모든 레시피를 이름 순서로 반환한다.
Returns:
RecipeDefinition 목록 (이름 오름차순 정렬)
사용 예::
for recipe in list_recipes():
print(f"{recipe.name}: {recipe.description}")
"""
logger.debug("레시피 목록 조회: count=%d", len(RECIPES))
return sorted(RECIPES.values(), key=lambda r: r.name)
def create_config_from_recipe(
recipe_name: str,
source: SourceInput,
**options: object,
) -> PipelineConfig:
"""레시피를 기반으로 PipelineConfig를 생성한다.
레시피의 기본 단계와 산출물 타입을 그대로 사용하며,
options를 통해 실행 옵션을 오버라이드할 수 있다.
Args:
recipe_name: 레시피 식별자 (kebab-case)
source: 파이프라인 입력 소스
**options: 파이프라인 실행 옵션 (stop_on_error, timeout_seconds 등)
Returns:
생성된 PipelineConfig 인스턴스
Raises:
KeyError: 존재하지 않는 레시피 이름인 경우
사용 예::
source = SourceInput(type="url", content="https://example.com/paper")
config = create_config_from_recipe(
"research-to-article",
source,
stop_on_error=False,
timeout_seconds=600,
)
report = await orchestrator.run(config)
"""
recipe = get_recipe(recipe_name)
# 기본 옵션에 사용자 옵션 병합
merged_options: dict[str, object] = {
"stop_on_error": True,
"timeout_seconds": 300,
**options,
}
config = PipelineConfig(
name=recipe.name,
stages=list(recipe.stages),
outputs=list(recipe.default_outputs),
source=source,
options=merged_options,
)
logger.info(
"레시피 기반 설정 생성: recipe=%s, stages=%s, outputs=%s",
recipe_name,
[s.value for s in config.stages],
[o.value for o in config.outputs],
)
return config