오늘은 경제 블로그 자동화 프로젝트를 하루 종일 이어서 만들었다. 데이터 수집부터 글 생성, Blogger 포스팅, 인스타 카드뉴스까지 파이프라인을 연결하면서 크고 작은 버그를 열 번 넘게 잡았다.
1단계: 기존 진행상황 확인과 데이터 수집 스크립트
CLAUDE.md를 읽고 지금까지 진행상황부터 정리했다. Blogger API 연동은 이미 돼 있어서 02_post_article.py로 테스트 초안을 실행해봤는데, 이전 세션들에서 만든 중복 테스트 초안 3개가 그대로 쌓여 있었다. Blogger API로 확인 후 정리했다. 이어서 FRED(미국 경제지표), GDELT(뉴스) 수집 스크립트를 작성했다. FRED는 API 키 발급 후 바로 실데이터가 들어왔고, GDELT는 개발 환경 네트워크가 공유 IP라 속도제한(429)에 자주 걸려서 실패해도 계속 진행하는 폴백 처리를 넣었다.
2단계: 로컬 LLM으로 글 생성 로직 만들기
Claude API 키가 없어서, provider를 "claude" 또는 "ollama"로 바꿔 끼울 수 있는 생성 함수를 만들고 로컬 Ollama의 exaone3.5:7.8b 모델로 테스트했다. 이 모델은 한/영 이중언어에 특화돼 있고 내 맥북(M5 Air 24GB)에도 잘 맞아서 그대로 채택했다. FRED 데이터를 넣어 첫 실제 기사를 생성해보니 결과가 꽤 괜찮았다.
3단계: 전체 파이프라인 연결, 그리고 SEO 보강
수집→생성→Blogger 초안 저장을 한 번에 묶는 오케스트레이션 스크립트를 만들고 한글/영어 둘 다 검증했다. 이어서 SEO를 위해 본문에 <h2> 소제목 구조와 메타 설명 생성을 추가하려다, Blogger API v3에는 애초에 메타 설명(searchDescription) 필드 자체가 없다는 걸 확인했다(구글 공식 저장소 이슈에서도 동일하게 확인됨). 그래서 메타 설명은 콘솔에 출력만 하고 사람이 편집기에 직접 붙여넣는 방식으로 정리했다.
4단계: 계획서 작성 후 실제 첫 발행
작업이 길어지자 지금 몇 번째 단계인지 한눈에 보려고 Phase/Task로 나눈 PLAN.md를 만들었다. 이후 실제 발행 후보 글을 검수했는데, 지표 4개를 거의 같은 패턴("수치→일반 해석→역사적 비유")으로 반복 설명하는 게 아쉬워서, 프롬프트에 "지표끼리 서로 비교하는 해석을 넣으라"는 지시를 추가했더니 글의 밀도가 확 좋아졌다. 영어 블로그에 첫 정식 게시글을 발행했다.
5단계: 인스타그램 API 연동 삽질
Meta 개발자 사이트에서 앱을 만들고 Instagram 제품을 설정했다. 계정을 테스터로 등록하고 액세스 토큰까지는 받았는데, 이 토큰을 60일짜리 장기 토큰으로 "교환"하려는 시도가 계속 실패했다. 원인은 트러블슈팅 표에 정리했다.
6단계: 카드뉴스 파이프라인 (오후)
인스타그램은 텍스트만으로 게시가 안 돼서 카드뉴스 이미지 파이프라인을 새로 만들었다. 실제 운영 중인 블로그에 브라우저로 접속해 배경색·글자색·폰트를 그대로 추출했고(크림/세피아톤 배경, Playfair Display 헤드라인, Noto Serif KR 본문), Pillow로 커버 1장+지표 4장+마무리 1장, 총 6장짜리 카드뉴스를 렌더링하는 스크립트를 완성했다. 영어 버전은 첫 시도에 결과물이 꽤 마음에 들었다.
Trouble Shooting
| 증상 | 원인 | 해결 방법 |
|---|---|---|
| 인스타그램 토큰을 장기 토큰으로 "교환"하려 하면 매번 "session key invalid" 에러 | 이 화면에서 발급되는 토큰이 애초에 이미 60일짜리 장기 토큰이었음. 예전 방식(단기→장기 교환)용 엔드포인트를 잘못 쓰고 있었음 | 교환(exchange) 대신 갱신(refresh) 엔드포인트로 바꿔서 해결. 시크릿 두 종류를 다른 값으로 시도해 에러 메시지 차이로 원인을 좁혀갔다 |
| 한글 카드뉴스 헤드라인이 빈 사각형(tofu)으로 깨짐 | 헤드라인용 Playfair Display 폰트에 한글 글리프가 아예 없음 | 텍스트에 한글이 섞여 있으면 자동으로 Noto Serif KR 폰트로 바꿔 렌더링하도록 처리 |
| 마무리 카드에 실제 블로그 주소와 다른 가짜 URL이 함께 노출됨 | 모델이 프롬프트에 없던 URL을 스스로 지어냄 | 프롬프트에 URL 언급 금지 지시 추가 + 정규식으로 URL 패턴을 한 번 더 걸러내는 이중 안전장치 |
| 메타 설명을 Blogger에 붙여넣으니 150자 초과 에러 | 코드에 글자수 제한을 155자로 잘못 설정해둠 | Blogger 실제 한도인 150자로 수정 |
느낀 점 / 다음에 할 일
오늘 가장 크게 배운 건, 로컬 소형 모델은 지시한 출력 형식을 생각보다 자주 어긴다는 점이다. 마크다운 헤더를 섞거나, 라벨을 번역해버리거나, 글자수를 스스로 적어놓는 등 예상 밖의 변형이 계속 나와서 파서를 매번 관대하게, 그리고 여러 번 반복 실행해서 검증하는 습관이 필요했다. 다음에는 한글 카드뉴스 커버 파싱 버그를 마저 잡고, 완성된 카드뉴스를 실제로 인스타그램에 올리는 스크립트를 이어서 만들 계획이다.
댓글
댓글 쓰기