개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← YouTube Shorts 자동화

품질 픽스 — hook 혼입 차단과 VTT fallback

2026년 6월 21일
script-workersubtitle-worker품질Gemini

서로 다른 워커에서 발생한 품질 문제 두 가지를 같은 날 고쳤다.

script-worker — hook 의문형 혼입 차단

Shorts 스크립트 구조에서 hook은 오버레이 텍스트로 따로 표시된다. 근데 Gemini가 hook의 의문형 어투를 script 본문에 그대로 이어받는 경우가 있었다.

hook: "이게 진짜 가능한 일일까요?" script 첫 문장: "과연 이게 가능한지 알아봤습니다..."

script는 hook과 무관하게 바로 팩트 서술로 시작해야 한다.

프롬프트에 규칙 두 개를 추가했다.

의문형 종결은 script 전체에서 마지막 comment_bait 딱 1회만 허용.
hook 내용을 이어받지 말고 즉각 팩트 서술로 시작.

프롬프트만으로는 부족하다는 걸 전에도 경험했다. parseOutput에 검증 로직을 추가했다.

// 마지막 문장(comment_bait) 제외하고 의문형 감지
const sentences = script.split(/[.?!]/);
const body = sentences.slice(0, -1);
if (body.some(s => /니까|십니까/.test(s))) {
  throw new ScriptError("SCRIPT_QUESTION_OPENING");
}

SCRIPT_QUESTION_OPENING도 재시도 대상에 추가해서 위반 시 최대 3회 자동 재시도한다.

subtitle-worker — SSML 오염 VTT fallback

edge-tts의 --file 옵션으로 TTS를 생성할 때 VTT 파일에 SSML 원문이 그대로 박히는 케이스가 있었다.

// 정상: 단어별 타임스탬프
00:00:00.000 --> 00:00:00.300
결국

// 비정상: SSML 원문 오염
00:00:00.000 --> 00:00:05.000
speak>결국 이 사태는...

이 상태에서 VTT를 파싱하면 타임스탬프 기반 자막이 비어있게 된다.

두 단계로 막았다.

// 1. SSML 태그 포함 엔트리 스킵
if (/speak>|<prosody|<break/.test(raw)) continue;

// 2. 파싱 결과 비어있으면 문자 비례 방식으로 fallback
const result = buildSrtFromVtt(vtt);
if (!result.length) {
  console.warn("VTT 파싱 결과 비어있음 — 문자 비례 타이밍으로 fallback");
  return buildSrt(script);
}

buildSrt는 전체 스크립트 길이 대비 각 문장의 문자 수로 타이밍을 계산하는 방식이다. 정확도는 떨어지지만 자막이 아예 안 나오는 것보다 낫다.

← 이전 글카테고리 개편 — politics 제거와 기술·의료·과학 추가
다음 글 →DB 이관 — Supabase 연결과 Lambda 초기 구성