
AI 뉴스 프로그램의 TTS가 PC를 2번 다운시켜서 하루 만에 클라우드로 이사한 이야기
요약
로컬 PC의 CPU 발열 문제로 인해 AI 뉴스 제작 파이프라인의 TTS 엔진을 Gemini TTS로 클라우드 이주한 과정을 다룹니다. 하드웨어 보호 장치의 설계 결함과 클라우드 API 사용 시 발생한 정책 위반 이슈를 해결하는 과정을 기록했습니다.
핵심 포인트
- 로컬 CPU 과부하로 인한 하드웨어 강제 종료 문제 해결
- 안전장치는 보호 대상보다 먼저 작동해야 함을 강조
- Gemini TTS 도입으로 합성 속도 단축 및 CPU 부하 제거
- 클라우드 API 사용 시 콘텐츠 필터링 정책 대응 필요
서론
지난 기사에서 매일 아침 6시에 AI가 뉴스 프로그램을 1편 제작하여 YouTube에 업로드하는 전자동 파이프라인(yabou02)을 소개했습니다.
그 기사를 공개한 다음 날 아침, PC 전원이 통째로 꺼졌습니다. 이틀 연속으로 말이죠.
범인은 음성 합성 (TTS)입니다. 로컬 CPU에서의 Flow Matching 추론이 i9-12900K를 계속 가열한 결과, 메인보드의 보호 기구가 작동하여 강제 종료되었습니다. 온도 가드 (Temperature Guard)를 구현해 두었으나, 보기 좋게 뚫리고 말았습니다.
이 기사는 그 열 폭주(Heat Crash)로부터 시작된 격동의 하루 — TTS의 클라우드 이주, 콘텐츠 필터의 오작동 조사, API 쿼터(Quota) 고갈, 그리고 3단계 폴백(Fallback) 설계 — 의 기록입니다. 지난번과 마찬가지로 개발은 거의 전부 Claude Code와의 대화로 진행했습니다.
먼저 결과부터 보시죠. 이주 후의 새로운 체제(Gemini TTS)가 오늘 아침, 전자동으로 생성 및 공개한 영상이 바로 이것입니다.
온도 가드는 왜 패배했는가
지난번에 도입한 열 대책은 3단계 구성이었습니다. 스레드 제한, 온도 모니터링 (Windows 측의 LibreHardwareMonitor를 WSL2에서 HTTP로 참조), 합성 완료된 청크(Chunk)의 재개(Resume).
두 번째 크래시 이후 검시를 해보니 허무한 사실이 판명되었습니다. PC 재부팅 후에 LibreHardwareMonitor가 실행되지 않았던 것입니다. 그리고 온도 가드는 "모니터링 서버가 응답하지 않으면 묵묵히 스킵한다"라는 페일 오픈 (Fail-open) 설계였습니다. 즉, 가드가 패배한 것이 아니라, 그날 아침에는 부재중이었던 것입니다.
무인 시스템의 안전장치는 "보호 대상보다 먼저 죽어있지는 않은가"까지 포함하여 설계해야 한다는 교훈을 얻었습니다. 소프트웨어로 할 수 있는 일에는 한계가 있으므로, 발열원 자체를 쫓아내기로 했습니다.
Gemini TTS로의 이주
이주 대상은 Gemini 3.1 Flash TTS(gemini-3.1-flash-tts-preview)로 결정했습니다. 결정적인 이유는 3가지입니다.
- 제로샷 (Zero-shot)으로 목소리 선택지가 30종. 4개의 보이스로 뉴스 원고 샘플을 만들어 비교 청취한 후, 저음의 중후한 "Algenib"를 채택.
- 스타일을 자연어로 지시할 수 있음. "차분하고 낮은 목소리로, 뉴스 캐스터처럼"이라고 서두에 붙이기만 하면 됨.
- 영어 단어를 그대로 읽을 수 있음. 지난 기사에서 소개한 "영어 단어 가타카나 학습 사전"이 통째로 불필요해짐 (로컬 TTS의 폴백용으로 보존은 해두었습니다).
구현은 기존 TTS 레이어에 세 번째 엔진으로 추가했습니다. 문장 단위의 청크 분할 · 실측 타이밍 기록 (자막 및 슬라이드 동기화의 기반) · 재개 · 재시도는 모두 기존 메커니즘을 그대로 유용할 수 있었기에, 핵심 부분은 100줄 정도입니다.
r = client.interactions.create(
model="gemini-3.1-flash-tts-preview",
input=style_prompt + text,
...
결과적으로, 10분 분량 프로그램의 음성 합성이 약 50분 → 몇 분으로 단축되었고, CPU 부하는 거의 없습니다. 열 폭주는 구조적으로 소멸했습니다.
...라고 여기서 끝났다면 미담이었겠지만, 클라우드는 클라우드 나름대로 또 다른 지뢰밭이었습니다.
지뢰 1: "임팩트도: 별 4개"가 정책 위반
합성을 돌리기 시작하자 일부 청크만 400 에러로 거부되었습니다.
Input blocked: The prompt contains sensitive words that violate Google's Generative AI Prohibited Use policy
차단된 문장을 보니 —— "임팩트도: 별 4개". 뉴스의 평가를 나타내는 단순한 정형 문구입니다. 어디가 센시티브(Sensitive)하다는 것인지.
분리 실험 (동일한 문장에 대해 프롬프트 구성 요소를 하나씩 바꿔서 전송)을 한 결과, 흥미로운 사실을 발견했습니다.
| 스타일 지시 | 결과 |
|---|---|
| "프로 남성 뉴스 캐스터로서 읽어줘" | 🚫 차단 |
| "프로 뉴스 캐스터로서" (남성 삭제) | 🚫 차단 |
| "뉴스 캐스터처럼 읽어줘" | ✅ 통과 |
범인은 "~로서"의 역할극 (Role-play) 구문이었습니다. 인격을 연기하도록 하는 지시와 짧은 단편 텍스트의 조합이 필터의 무언가를 자극하는 듯합니다 ("남성"은 무죄였습니다).
스타일 프롬프트(Style Prompt)를 "~처럼" 구문으로 바꾸면서 오작동(False Positive)은 거의 사라졌지만, 보험으로서 **단계적 회피(Gradual Avoidance)**도 구현했습니다. 블록(Block)이 감지되면 ① 스타일 지시를 제외한 일반 문장으로 재전송 → ② 그래도 안 되면 Claude에게 "의미를 바꾸지 말고 바꿔 써줘"라고 요청하여 재전송 → ③ 마지막까지 통과하지 못하면 결락(Omission)으로 처리하여 완성 알림에 경고를 포함합니다. 동일한 문장을 단순히 재시도하는 것은 무의미하기 때문에(결정론적으로 블록됨), 리트라이(Retry)가 아니라 입력을 바꾸는 것이 포인트입니다.
지뢰 2: 일일 쿼터(Daily Quota) 100 요청
순조롭게 합성이 진행되던 그때, 이번에는 429 에러가 내려왔습니다.
Quota exceeded: generate_requests_per_model_per_day, limit: 100
무료 티어의 Gemini 3.1 Flash TTS는 하루 100 요청 · 분당 10 요청입니다. 프로그램 1편 = 약 80 청크(Chunk) = 80 요청이므로, 매일 아침 본방 송출만으로도 거의 가득 찹니다. 구분 실험이나 재생성을 수행한 날은 즉사합니다.
더 까다로운 점은 리셋 시각이 태평양 표준시(PT) 오전 0시 = 일본 시간 오후 4시라는 것입니다. "저녁에 실험해서 쿼터를 사용하면, 다음 날 아침 6시 본방이 고갈된 상태로 돌아간다"라는 시차 트랩이 있습니다 (실제로 다음 날 아침에 겪었습니다).
대책: 3단계 폴백(Fallback)과 "목소리의 통일"
쿼터 대책으로서, TTS 엔진을 3단계 폴백 체인으로 구성했습니다.
Gemini 3.1 Flash TTS (본래 엔진)
↓ 일일 쿼터 소진 시
Gemini 2.5 Flash TTS (별도 쿼터 · 동일한 목소리 Algenib · 반값)
...
설계에서 가장 공을 들인 부분은 **에러의 입도(Granularity)**입니다. 일일 쿼터 소진은 "그날은 더 이상 회복되지 않는" 실패이므로, 청크 단위로 결락을 쌓아가는 것이 아니라, 엔진 전체의 실패로서 즉시 상위 단계로 전파시킵니다. 이렇게 하면 다음 엔진이 모든 청크를 다시 합성하므로, 영상 한 편 안에서 목소리가 섞이지 않습니다. 일시적인 속도 제한(Rate Limit, 분당 10건)은 반대로 청크 단위로 리트라이 + 청크 간 6.5초의 페이싱(Pacing)을 통해 흡수합니다.
"어떤 실패는 국소적으로 억제하고, 어떤 실패는 전역(Global)으로 던질 것인가" —— 무인 파이프라인의 신뢰성은 이 분류 작업에서 결정된다는 것을 실감했습니다.
요청 수 자체를 1/3로
또 다른 대책은 소비 절감입니다. 1 청크 = 1 요청이므로, 청크를 길게 만들면 쿼터 소비가 줄어듭니다. 다만 상한 글자 수를 두 배로 늘리는 것만으로는 효과가 없었습니다. 대본이 "1문장 1행" 형식이었고, 분할 로직이 행 단위였기 때문입니다. 줄바꿈을 넘어서 문장을 채우도록 변경한 결과, 1편당 79 → 28 요청으로 줄었습니다. 무료 범위에서도 3편 분량의 여유가 생겼습니다.
부수적인 효과로, "임팩트 정도: 별 4개"와 같은 짧은 단편이 앞뒤 문장과 결합되어 단독으로 전송되지 않게 되었고, 필터 오작동의 온상도 사라졌습니다.
덤으로 자막도 자연스러워졌다
청크가 길어지면, 고정 글자 수로 자르던 자막의 분할 위치가 점점 부자연스러워집니다. 그래서 budoux(Google에서 만든 일본어 줄바꿈 라이브러리)를 도입하여, 문절 경계에서 자막을 끊도록 했습니다.
이전: OpenAI가 미국 정부에 | 대항하여, 무려 약 4.2조 엔 분량...
이후: OpenAI가 미국 정부에 | 대항하여, 무려 약 4.2조 엔 분량...
Pure Python으로 가볍고, 머신러닝 기반임에도 의존성(Dependency)이 제로입니다. 도입에는 30줄 정도면 충분했습니다. 일본어 자막·자막(Telop)을 만드는 분들에게 강력히 추천합니다.
신체제의 첫 출전에서 일어난 일
이전 직후 다음 날 아침(오늘 아침)의 자동 운행은 다음과 같았습니다.
CPU 온도: 매우 평온함. TTS 중에도 팬은 조용한 상태 유지
- 3.1의 쿼터가 전날 실험의 잔여분으로 고갈됨 (그 예의 16시 리셋 트랩) → 2.5로 자동 전환, 결락 0건. 폴백 설계가 첫날부터 제 역할을 함 - 음성 합성은 약 5분 만에 완료
한편 다른 문제도 발견되었습니다. 토요일은 "주간 요약" 회차라 대본의 헤드라인 형식이 평일과 달랐고, 슬라이드 토픽 검출이 0건이 되어 오프닝 슬라이드가 계속 떠 있는 상태가 되었습니다. 헤드라인 패턴 대응과, 이미 합성된 음성을 재사용한 타이밍 데이터 수정(재합성 없음 · 쿼터 소비 제로)을 통해 당일 중에 복구했습니다. 완전 자동 시스템에는 "본방 송출 중에만 밟을 수 있는 지뢰"가 끝이 없는 것 같습니다.
이 새로운 체제에서 생성 및 공개된 것이 서두에 삽입한 영상입니다. 목소리는 Gemini TTS의 Algenib이며, 중간부터 2.5로의 폴백 (Fallback)이 섞여 있지만, 구분하는 것은 거의 불가능할 것이라고 생각합니다.
비용의 변화
| 항목 | 이전 | 이후 |
|---|---|---|
| TTS 처리 시간 | 약 50분 (로컬 CPU) | 약 5분 (클라우드) |
| TTS 비용 | 0엔 + 전기세 + 발열 리스크 | 무료 범위 내 (범위 초과 시에도 월 1,000엔 초반) |
| 발열 크래시 (Thermal Crash) | 2회 / 2일 | 구조적으로 제로 |
| 영어 단어 가타카나 사전 | 필요 (학습 운용) | 불필요 |
'로컬 최강'이라고 생각했지만, 매일 50분 동안 CPU를 계속 태우는 비용(전기세·발열·고장 리스크·PC 점유)을 고려하면, 하루 수십 엔 수준의 클라우드 API가 압도적으로 저렴하다는 것이 이번의 결론입니다.
요약
- 로컬 TTS의 발열 문제는 소프트웨어 대책(스레드 제한·온도 모니터링)만으로는 완전히 방어할 수 없는 경우가 있다. 안전장치 자체가 죽는 케이스까지 포함하여 페일세이프 (Fail-safe)를 설계해야 한다.
- 클라우드 TTS는 클라우드 측의 '콘텐츠 필터 오작동', '일일 쿼터 (Daily Quota)', '리셋 시각의 시차'라는 또 다른 지뢰가 있다.
- 대책의 핵심은 **폴백 연쇄 (Fallback Chain)**와 에러 입도 분류 (Error Granularity Sorting) (국소적 재시도 vs 전역적 전환)이다. 덕분에 첫날부터 쿼터 부족을 무사히 넘길 수 있었다. - 1 청크 = 1 요청 방식의 API에서는, 청크 결합이 곧 비용 및 쿼터 최적화가 된다.
- 일본어 자막의 줄바꿈은 budoux를 사용하여 문절 단위로 끊으면 행복해질 수 있다.
이 이행 과정은 아침에 발열 크래시를 발견한 시점부터 밤에 영상이 완성될 때까지 꼬박 하루가 걸렸습니다. 설계 상담·구현·원인 파악 실험·테스트 71건에 이르기까지, 옆에 앉아 있는 Claude Code와 이인삼각(한 명과 일체삼각?)으로 진행한 돌격 공사였습니다. 트러블의 수만큼 시스템은 강해진다. 다음에는 어떤 지뢰가 기다리고 있을지, 조금 기대되기 시작했습니다.
(이 기사에서 소개한 시스템이 매일 아침 만들고 있는 영상은, YouTube의 아크로파파 AI 테크 뉴스(@acropapa330)에서 공개하고 있습니다)
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기