""" 뉴스레터 변환봇 (converters/newsletter_converter.py) 역할: 원본 마크다운 → 주간 뉴스레터 HTML 발췌 (LAYER 2) - TITLE + META + KEY_POINTS 발췌 - 주간 단위로 모아서 뉴스레터 HTML 생성 출력: data/outputs/weekly_{date}_newsletter.html Phase 3에서 Substack 등 연동 예정 """ import json import logging from datetime import datetime from pathlib import Path BASE_DIR = Path(__file__).parent.parent.parent LOG_DIR = BASE_DIR / 'logs' OUTPUT_DIR = BASE_DIR / 'data' / 'outputs' OUTPUT_DIR.mkdir(exist_ok=True) logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[ logging.FileHandler(LOG_DIR / 'converter.log', encoding='utf-8'), logging.StreamHandler(), ] ) logger = logging.getLogger(__name__) BLOG_BASE_URL = 'https://the4thpath.com' def extract_newsletter_item(article: dict, blog_url: str = '') -> dict: """단일 글에서 뉴스레터용 발췌 추출""" return { 'title': article.get('title', ''), 'meta': article.get('meta', ''), 'corner': article.get('corner', ''), 'key_points': article.get('key_points', []), 'url': blog_url or f"{BLOG_BASE_URL}/{article.get('slug', '')}", 'extracted_at': datetime.now().isoformat(), } def build_newsletter_html(items: list[dict], week_str: str = '') -> str: """주간 뉴스레터 HTML 생성""" if not week_str: week_str = datetime.now().strftime('%Y년 %m월 %d일 주간') article_blocks = [] for item in items: points_html = ''.join( f'
  • {p}
  • ' for p in item.get('key_points', []) ) block = f"""

    {item.get('corner','')}

    {item.get('title','')}

    {item.get('meta','')}

    전체 읽기 →

    """ article_blocks.append(block) articles_html = '\n'.join(article_blocks) return f""" The 4th Path 주간 뉴스레터 — {week_str}

    The 4th Path

    {week_str} 뉴스레터

    {articles_html}

    the4thpath.com | by 22B Labs

    """ def generate_weekly(articles: list[dict], urls: list[str] = None, save_file: bool = True) -> str: """ 여러 글을 모아 주간 뉴스레터 HTML 생성. articles: article dict 리스트 urls: 각 글의 발행 URL (없으면 slug로 생성) """ logger.info(f"주간 뉴스레터 생성 시작: {len(articles)}개 글") items = [] for i, article in enumerate(articles): url = (urls[i] if urls and i < len(urls) else '') items.append(extract_newsletter_item(article, url)) week_str = datetime.now().strftime('%Y년 %m월 %d일') html = build_newsletter_html(items, week_str) if save_file: date_str = datetime.now().strftime('%Y%m%d') filename = f"weekly_{date_str}_newsletter.html" output_path = OUTPUT_DIR / filename output_path.write_text(html, encoding='utf-8') logger.info(f"뉴스레터 저장: {output_path}") logger.info("주간 뉴스레터 생성 완료") return html if __name__ == '__main__': samples = [ { 'title': 'ChatGPT 처음 쓰는 사람을 위한 완전 가이드', 'meta': 'ChatGPT를 처음 사용하는 분을 위한 단계별 가이드', 'slug': 'chatgpt-guide', 'corner': '쉬운세상', 'key_points': ['무료로 바로 시작', 'GPT-3.5로도 충분', '프롬프트가 핵심'], }, { 'title': '개발자 생산성 10배 높이는 AI 도구 5선', 'meta': '실제 사용해본 AI 개발 도구 정직한 리뷰', 'slug': 'ai-dev-tools', 'corner': '숨은보물', 'key_points': ['Cursor로 코딩 속도 3배', 'Copilot과 차이점', '무료 플랜으로 충분'], }, ] html = generate_weekly(samples) print(html[:500])