← 개발 로그 목록

LearningCollector: 블로그 포스팅 자동화를 위한 초안 처리 및 프론트매터 지원 추가

/ 13분 분량 / 개발 로그

개발 진척

LearningCollector: 블로그 포스팅 자동화를 위한 초안 처리 및 프론트매터 지원 추가

안녕하세요! LearningCollector 프로젝트를 진행하면서 개발 과정을 공유하는 기술 블로거입니다. 오늘은 블로그 포스팅 자동화를 한 단계 더 발전시킨 흥미로운 업데이트를 소개해 드릴까 합니다. 바로 마크다운 초안 파일의 자동 파싱 및 프론트매터 지원 기능 추가입니다.

🚀 요약

이번 커밋에서는 마크다운 초안 파일에서 제목, 요약, 태그와 같은 메타데이터를 자동으로 추출하고, YAML 형식의 프론트매터(frontmatter)를 지원하도록 API 기능을 확장했습니다. 또한, 로컬 환경에서의 개발 편의성을 높이기 위해 localhost 연결도 지원합니다.

  • 작업 날짜: 2026년 1월 25일
  • 전체적인 맥락: 기존에는 포스팅할 내용을 수동으로 입력하거나 복사/붙여넣기 해야 했지만, 이제는 마크다운 초안 파일만으로도 손쉽게 블로그 포스트를 생성할 수 있게 되어, 콘텐츠 제작 과정이 훨씬 간편해졌습니다.

💡 배경 및 목적

왜 이 작업이 필요했는가?

블로그에 꾸준히 글을 올리기 위해서는 콘텐츠 제작 과정의 효율성이 매우 중요합니다. 특히 기술 블로그의 경우, 코드 예시나 구조화된 정보를 포함하기 위해 마크다운을 자주 사용하게 됩니다. 하지만 매번 포스팅할 때마다 제목, 요약, 태그 등의 메타데이터를 수동으로 입력하는 것은 번거로운 작업이 될 수 있습니다.

해결하려는 문제

  • 마크다운 초안 파일에서 포스팅에 필요한 메타데이터(제목, 요약, 태그 등)를 수동으로 입력해야 하는 번거로움.
  • 프론트매터(YAML)를 사용하는 마크다운 파일과 일반 마크다운 파일을 일관되게 처리하는 방식의 부재.
  • 로컬 개발 환경에서 API 테스트 시 인증 과정 없이 간편하게 확인하고 싶은 니즈.

목표

  • 마크다운 초안 파일로부터 제목, 요약, 태그 등 핵심 메타데이터를 자동으로 추출하여 포스팅 생성을 간소화.
  • YAML 프론트매터를 사용하는 마크다운 파일과 그렇지 않은 일반 마크다운 파일 모두를 유연하게 처리.
  • 로컬 환경에서의 개발 및 테스트 편의성 증대.

🔧 구현 내용

이번 커밋의 핵심은 api/blog_api.py 파일의 기능 확장과 관련 프롬프트 파일들의 업데이트입니다.

주요 변경사항 상세 설명

  1. localhost 지원 추가: use_localhost=True 옵션을 통해 별도의 인증 없이 로컬 서버에 접속하여 API를 테스트할 수 있게 되었습니다. 이는 개발 과정에서 매우 유용합니다.
  2. 프론트매터 파싱 기능 추가: YAML 형식으로 ---로 구분된 프론트매터 영역을 파싱하여 메타데이터를 추출합니다.
  3. 메타데이터 자동 추출:
    • 제목: 마크다운 파일의 첫 번째 H1 태그에서 제목을 추출합니다.
    • 요약: 마크다운 파일의 첫 번째 문단을 요약으로 사용합니다.
  4. parse_draft_file() 함수 추가: 마크다운 파일을 입력받아 프론트매터 정보와 본문 내용을 분리하여 파싱하는 새로운 함수를 구현했습니다.
  5. create_post_from_draft() 함수 추가: 초안 파일을 생성하고 메타데이터를 관리하는 번거로움 없이, 단 한 번의 함수 호출로 초안 파일로부터 블로그 포스트를 생성할 수 있는 편리한 기능을 제공합니다.
  6. 프론트매터 및 일반 마크다운 동시 지원: 프론트매터가 포함된 파일과 일반 마크다운 파일 모두 정상적으로 처리할 수 있도록 유연성을 확보했습니다.

변경된 파일 목록

  • api/blog_api.py
  • prompts/당일_공부_요약_프롬프트.md
  • prompts/알고리즘_풀이_포스팅_프롬프트.md
  • prompts/프로젝트_진척_및_의사결정_요약_프롬프트.md

추가/삭제된 코드 라인 수

(이 부분은 실제 커밋 데이터에서는 제공되지 않아 생략합니다. 실제 블로그 포스팅 시에는 git diff --stat 명령 등을 통해 확인할 수 있습니다.)

핵심 코드 설명

api/blog_api.py에 추가된 parse_draft_file 함수의 일부를 발췌하여 설명드리겠습니다.

import yaml

def parse_draft_file(file_path: str) -> dict:
    """
    마크다운 초안 파일을 파싱하여 메타데이터와 본문을 추출합니다.
    YAML 프론트매터를 지원하며, 프론트매터가 없을 경우에도 처리 가능합니다.
    """
    with open(file_path, 'r', encoding='utf-8') as f:
        content = f.read()

    metadata = {}
    body = content

    # 프론트매터 파싱 (YAML 형식)
    if content.startswith('---'):
        parts = content.split('---', 2)
        if len(parts) >= 3:
            try:
                metadata = yaml.safe_load(parts[1])
                body = parts[2].strip()
            except yaml.YAMLError as e:
                print(f"Error parsing YAML frontmatter: {e}")
                # YAML 파싱 오류 시에도 일반 마크다운으로 처리 시도

    # 제목 자동 추출 (H1 태그)
    if 'title' not in metadata:
        h1_match = re.search(r'^#\s+(.*)', body)
        if h1_match:
            metadata['title'] = h1_match.group(1).strip()

    # 요약 자동 추출 (첫 번째 문단)
    if 'excerpt' not in metadata:
        first_paragraph_match = re.search(r'^(.*?)(?:\n\n|$)', body, re.DOTALL)
        if first_paragraph_match:
            metadata['excerpt'] = first_paragraph_match.group(1).strip()
            # 너무 긴 요약은 잘라낼 수 있습니다. (예: 200자)
            # if len(metadata['excerpt']) > 200:
            #     metadata['excerpt'] = metadata['excerpt'][:200] + '...'

    # 기본 태그 설정 (예시)
    if 'tags' not in metadata:
        # 파일 이름이나 내용에 따라 기본 태그를 설정하는 로직 추가 가능
        metadata['tags'] = []

    return {"metadata": metadata, "body": body}

# ... (create_post_from_draft 함수 등 추가 구현)

이 함수는 파일 내용을 읽어와 ---로 둘러싸인 YAML 부분을 찾아 파싱합니다. 만약 프론트매터가 없다면, H1 태그에서 제목을, 첫 번째 문단에서 요약을 자동으로 추출하려고 시도합니다. create_post_from_draft 함수는 이 parse_draft_file 함수를 활용하여 초안 파일을 직접 블로그 포스트로 변환하는 핵심 로직을 수행합니다.

🧐 기술적 의사결정

어떤 기술/라이브러리를 선택했는가?

  • YAML 파싱: PyYAML 라이브러리를 사용하여 YAML 형식의 프론트매터를 쉽게 파싱하도록 결정했습니다. Python 표준 라이브러리가 아닌 외부 라이브러리이지만, YAML 처리에 있어서는 가장 표준적이고 안정적인 선택입니다.
  • 정규 표현식 (Regex): 마크다운 파일에서 H1 태그와 첫 번째 문단을 추출하기 위해 Python의 re 모듈을 활용했습니다. 이는 문자열 패턴 매칭에 강력하고 유연한 도구입니다.

왜 그 선택을 했는가?

  • PyYAML: YAML은 설정 파일이나 메타데이터를 표현하는 데 널리 사용되는 포맷이며, PyYAML은 Python 생태계에서 YAML을 다루는 사실상의 표준 라이브러리입니다. 복잡한 YAML 구조도 쉽게 처리할 수 있다는 장점이 있습니다.
  • re 모듈: 마크다운은 단순한 텍스트 형식이지만, 구조화된 정보를 추출하기 위해서는 특정 패턴을 찾아야 합니다. 정규 표현식은 이러한 패턴 매칭에 가장 효율적이고 유연한 방법입니다. 특히 H1 태그 (# 제목)와 문단 구분을 위한 빈 줄(\n\n)을 기준으로 삼는 것은 마크다운의 일반적인 형식을 따릅니다.

다른 대안과 비교

  • YAML 파싱:
    • 직접 문자열 처리: split 등의 문자열 함수를 사용하여 YAML 부분을 직접 파싱하는 방법도 고려할 수 있었습니다. 하지만 YAML은 들여쓰기나 특수 문자에 민감하기 때문에, 직접 처리하는 것은 복잡하고 오류 발생 가능성이 높습니다. PyYAML은 이러한 복잡성을 해결해 줍니다.
  • 정규 표현식:
    • HTML 파서 라이브러리 사용: 만약 마크다운을 HTML로 변환한 후 DOM 파싱 라이브러리(예: BeautifulSoup)를 사용했다면, H1 태그나 특정 요소 추출이 더 명확해질 수 있습니다. 하지만 여기서는 마크다운 파일 자체에서 메타데이터를 추출하는 것이 목적이고, 중간 변환 과정은 불필요하다고 판단했습니다. 정규 표현식이 더 간결하고 가벼운 해결책입니다.

장단점 분석

  • PyYAML:
    • 장점: YAML 포맷 처리에 표준적이고 강력하며, 복잡한 구조도 쉽게 다룰 수 있습니다.
    • 단점: 외부 라이브러리 의존성이 추가됩니다.
  • re 모듈:
    • 장점: Python에 내장되어 있어 추가 설치가 필요 없고, 다양한 패턴 매칭에 유연하게 사용할 수 있습니다.
    • 단점: 복잡한 정규 표현식은 가독성이 떨어지고 디버깅이 어려울 수 있습니다. 또한, 마크다운의 모든 파생 형식을 완벽하게 커버하기 어려울 수 있습니다. (예: # 뒤에 공백이 없는 경우 등)

🌱 배운 점 및 개선점

이번 작업을 통해 배운 것

  • 마크다운 파일에서 구조화된 정보를 추출하는 다양한 방법 (프론트매터, H1 태그, 첫 문단)과 그 구현 방법을 익혔습니다.
  • PyYAML 라이브러리의 기본적인 사용법을 익혔고, YAML 데이터 처리에 대한 이해를 높였습니다.
  • 로컬 개발 환경에서의 편의성을 높이는 것이 개발 생산성에 얼마나 중요한지 다시 한번 느꼈습니다.

앞으로 개선할 점

  • 오류 처리 강화: localhost 연결 실패, 프론트매터 파싱 오류 등 예외 상황에 대한 보다 견고한 오류 처리 로직을 추가해야 합니다.
  • 태그 추출 로직 고도화: 현재는 기본 태그만 설정되거나 수동으로 입력해야 하지만, 파일 내용이나 구조를 분석하여 관련 태그를 자동으로 제안하거나 추출하는 기능을 추가하면 더욱 편리해질 것입니다.
  • 프론트매터 스키마 검증: 특정 필드가 누락되거나 잘못된 형식으로 입력되었을 때 이를 감지하고 사용자에게 알림을 주는 스키마 검증 기능을 도입하면 데이터 일관성을 높일 수 있습니다.
  • 마크다운 파싱 라이브러리 고려: 만약 향후 더 복잡한 마크다운 구문(예: 테이블, 각주 등)을 정교하게 다루거나, 마크다운을 AST(Abstract Syntax Tree) 형태로 분석해야 할 필요가 생긴다면, mistune이나 markdown-it-py와 같은 전문 마크다운 파싱 라이브러리 사용을 고려해 볼 수 있습니다.

다음 단계 계획

  • 이번에 추가된 create_post_from_draft() 함수를 실제로 활용하여, 새로운 블로그 글을 마크다운 초안 파일로 작성하고 포스팅하는 과정을 자동화해 볼 예정입니다.
  • 앞서 언급한 개선점들, 특히 오류 처리 강화 및 태그 자동 추출 기능을 점진적으로 구현하여 API의 안정성과 유용성을 높여나갈 계획입니다.

📚 참고 자료

이번 업데이트를 통해 LearningCollector의 콘텐츠 제작 흐름이 한층 더 원활해지기를 기대합니다. 다음 포스팅에서 또 흥미로운 소식으로 찾아뵙겠습니다!