프롬프트 도감 › No.566
쇼츠 자동 공장 만들기 (주제 고르기부터 예약 업로드까지)
Build: Unattended Shorts Factory
한 번 만들어 두면 매일 정해진 시간마다 AI가 주제를 고르고, 대본을 쓰고, 대본 속 숫자가 진짜 자료와 맞는지 확인한 뒤 목소리를 입혀 영상으로 만들어 예약 업로드합니다. 조회수가 잘 나온 영상은 다음 대본을 쓸 때 참고합니다.
이럴 때 얼굴·목소리 없이 정보 쇼츠 채널을 자동으로 운영하고 싶을 때
도구 Claude Code · Codex · Cursor
프롬프트
너는 시니어 자동화 엔지니어다. 내 맥(또는 리눅스 서버)에 '유튜브 쇼츠 무인 공장'을 구축해라. 사람은 채널 설정 파일 하나와 대본 규칙 파일 하나만 관리하고, 나머지(소재 → 대본 → 팩트 검증 → 음성 → 영상 → QA → 예약 업로드 → 성과 피드백)는 스케줄러가 하루 N번 돌린다.
【내가 채울 것】 채널 주제: ___ / 시청자(누가, 무엇이 궁금한 사람): ___ / 허용 출처 도메인(공식 기관·1차 자료만): ___ / 하루 편수: ___ (기본 2) / 공개 시각 슬롯: ___ (예 12:30, 21:00) / 해설형 하루 상한(TTS 크레딧): ___ (기본 1) / 화면 스타일 한 줄: ___
## 1. 구조
- Python 3.11 + uv. CLI 하나 `shorts`에 서브커맨드: radar, bench, next-slot, pick-format, make, check, upload, status, stats, report.
- config/channel.yaml: 위 값 + daily_cap, narrated_daily_cap, slots, duration [4, 58], tts, renderer, disclaimer(설명란 꼬리 문구), playlists(제목 키워드 → 재생목록). 상한은 코드가 강제한다. 설정 블록 하나를 더 쓰면 채널이 하나 더 생겨야 한다(SHORTS_CHANNEL 환경변수로 선택).
- 대본 규칙은 코드에 박지 말고 .claude/skills/<채널>-script/SKILL.md 에 둔다(도감의 '쇼츠 대본 스킬 템플릿' 프롬프트를 채워 넣는다).
- 상태는 SQLite 장부 하나: videos(slug, channel, title, status scripted/rendered/scheduled/public, scheduled_at, dir, design_version, source_url). 슬롯 계산·중복 제목 검사·성과 수집이 모두 이 장부를 본다.
- 한 편 = 폴더 하나 out/<YYYYMMDD>-<slug>/ 에 script.json, voice.mp3, alignment.json, video.mp4, meta.json. 이미 만든 산출물은 다시 만들지 않는다(voice.mp3가 있으면 TTS를 건너뛴다).
## 2. 한 편 제작 워커 bin/auto-short.sh (스케줄러가 호출)
1) 감독자 잠금: 동시에 하나만 돈다. CPU 부하·여유 메모리가 기준을 넘으면 종료코드 75로 '보류'하고 다음 회차에 맡긴다.
2) next-slot: 장부에서 daily_cap 미만인 날의 빈 공개 슬롯 중 지금+45분 이후 첫 슬롯. 없으면 조용히 종료.
3) pick-format: 그날 해설형(narrated)이 상한 미만이고 목록형(list)보다 적으면 narrated, 아니면 list. 두 포맷을 번갈아 만든다.
4) bench: 내 니치 상위 쇼츠(제목·해시태그·길이·업로드 시각)를 20시간마다 갱신해 data/bench-latest.md 한 장으로 압축한다.
5) radar: 허용 출처 도메인의 RSS·보도자료·통계 게시판에서 오늘 소재 후보를 모아 data/radar-latest.txt. 이미 쓴 URL은 장부로 제외.
6) context: 최근 성과 요약 2,000자 + data/automation/feedback-<채널>.md(성과 루프가 쓰는 '다음 대본 개선 지침') + 최근 발행 제목.
7) 대본 생성: 에이전트 CLI에 아래 프롬프트를 한 번 보낸다(엔진 순서 Codex → Claude → Gemini → 로컬, 실패·한도면 다음 엔진, 상태 없는 1회 호출, 제한 8분, 프롬프트 14,000자 상한).
"SKILL.md를 먼저 읽고 <채널> 쇼츠 대본 1편을 만들어라. 오늘 소재 후보: data/radar-latest.txt. 성과 요약과 개선 지침: (본문). 최근 발행 제목과 겹치지 않게. bench-latest.md 상위 5개 제목·해시태그만 참고하고 원본 데이터는 다시 읽지 마라. 포맷은 반드시 <FORMAT>. 모든 숫자는 공식 출처 원문에서 확인하고 지어내지 않는다. 확인이 안 되면 소재를 바꾼다. out/<날짜>-<slug>/script.json 에 쓰고 제작·업로드는 하지 마라. 마지막 줄에 정확히 SCRIPT_DIR=<dir> 를 출력한다."
로컬 모델이 대본을 썼으면 업로드를 막고(hold) 사람에게 알린다. 로컬은 웹으로 숫자를 확인하지 못한다.
8) make: (a) 대본 게이트 → (b) 팩트 게이트 → (c) 음성 → (d) 렌더 → (e) 영상 QA. 하나라도 실패하면 알림 후 종료. 같은 편을 반복 재시도하지 않는다.
9) upload: 슬롯 시각으로 예약 업로드. 성공하면 장부 scheduled, 알림 "HH:MM 예약 완료: 제목".
10) 모든 단계는 data/automation/phase.json 에 현재 단계(prepare/generate/render/upload/scheduled/hold)를 남긴다. 업로드에서 실패한 편은 --resume=<dir> 로 QA부터 다시 탄다.
## 3. 게이트 (코드가 기계적으로 막는다. 이 공장의 핵심)
- 대본 게이트: 필수 필드(slug, headline, facts, source_label, title, description, segments 또는 items). 콘티(storyboard)가 segment/item 수와 일치해야 음성·렌더를 시작한다(프리프로덕션 게이트). 목록형 5~7개·항목 26자 이하. 해설형 320자 이하(≈55초). 첫 문장이 인사·예고("안녕", "여러분", "오늘은", "이번 영상")로 시작 금지. 첫 문장·제목에 구체적 숫자 필수. 제목 90자 이하. 최근 제목과 유사도 0.8 초과 금지.
- 팩트 게이트: facts[]는 {claim, quote, url}. 각 url을 실제로 열어 quote가 원문에 글자 그대로 있는지 확인한다(공백·따옴표는 무시). 말·화면·제목·표의 모든 숫자는 어떤 quote에든 있어야 한다. 출처를 못 열면 통과시키지 않는다. 금지 표현(조언·권유·보장·공포) 검사.
- 영상 QA: 길이 duration 범위, 1080×1920, 미리보기 음성(macOS say)이면 업로드 불가.
## 4. 제작 세부
- 음성: ElevenLabs 타임스탬프 API(글자 정렬 → alignment.json). 첫 segment만 감정 모델+감정 태그로 세게, 나머지는 차분하게. --preview 는 macOS say 로 대체해 크레딧을 아낀다. 내부 0.1초 이상 무음 제거, 상한을 넘기면 최대 1.15배까지 속도 조정, 그 이상은 QA가 막고 대본을 줄이게 한다.
- 렌더: 데이터(script.json)와 스타일(templates/*.html + base.css + config/theme.json)을 분리한다. Python은 JSON을 템플릿에 주입하고 Chrome으로 프레임을 찍어 ffmpeg로 합친다. 안전 영역 위 15%·오른쪽 15%·아래 25%·왼쪽 7%, 줄바꿈은 CSS clamp/line-clamp. 좌표·폰트 크기를 Python에 하드코딩하지 마라. 템플릿 실패 시 Pillow 폴백 + fallback 기록.
- 디자인 A/B: config/design-policy.json 에 후보 디자인과 배정 비율. slug 해시로 결정. 최소 표본 전 50:50, 승자가 나와도 25% 탐색 유지. meta.json 에 design_version 기록.
- 목록형은 5초 한 장(목소리 없음), 해설형은 45~55초.
- meta.json: 제목 / 설명(2~3문장 + "출처: source_label" + URL 목록 + disclaimer + 해시태그 3개) / 고정 댓글.
- 업로드: YouTube Data API(videos.insert, 하루 10,000유닛·건당 1,600유닛, 감사 전 비공개 잠김)와 브라우저 자동화(Playwright: Studio 업로드 화면 → 제목·설명·재생목록·예약 시각) 둘 다 구현하고 channel.yaml 에서 고른다. 재생목록은 제목 키워드 매칭.
## 5. 피드백 루프 (별도 스케줄)
- 매일 2회 stats: 발행 영상의 조회수·평균 시청 지속률·좋아요 수집 → 일일 보고(성과 변화 → 잘된 점 → 문제 → 다음 개선, 기간·표본 명시) → data/automation/feedback-<채널>.md 에 '다음 대본 개선 지침'을 새로 쓴다. 제작 워커가 다음 회차에 읽는다.
- design-loop: design_version별 성과로 배정 비율만 조정한다. 렌더러 코드를 자동 수정하지 않는다.
- portfolio-loop: 채널별 회복 기준(표본·기간)을 평가해 보고만 한다. 업로드량을 자동으로 늘리지 않는다.
- 주 1회: bench 갱신 + 상위 영상 화면 트렌드 비교(로컬 비전 모델) → data/trend-review-latest.md. 다음 대본에는 '화면 공통점 한 가지'만 적용한다.
- health: phase.json 이 30분 넘게 같은 단계면 알림. recovery: 실패한 업로드 단계를 --resume 으로 하루 1회 재시도.
## 6. 스케줄러
dagu DAG: 채널당 <채널>-shorts.yaml(공개 슬롯 2시간 전마다 워커 1회, timeout 2400초), shorts-performance.yaml(하루 2회), shorts-health.yaml(30분), shorts-recovery.yaml(하루 1회), <채널>-weekly.yaml(월요일). dagu 가 없으면 launchd/cron 템플릿.
## 7. 공통 규칙
- 먼저 저장소를 훑고 가정을 3줄로 말한 뒤, 폴더 구조와 실행 순서를 계획으로 보여주고 승인을 받아라. 승인 전에는 파일을 만들지 마라.
- 비밀값은 .env 에서만 읽고 코드·로그·영수증에 찍지 마라. .env.example 을 만들어라.
- 첫 주는 --no-upload 로 영상 파일까지만 만들고 사람이 확인한 뒤 업로드를 켠다.
- 로컬 모델만으로 쓴 대본은 검토 전 업로드하지 않는다. 팩트 게이트를 우회하는 플래그를 만들지 마라.
- 실패하면 같은 작업을 반복하지 말고 상태를 남기고 멈춰라. 매 실행 끝에 receipts/<날짜>-<작업>.md(바뀐 것 / 증거 / 건너뛴 것 / 되돌리기).
- 실제로 돌려본 것만 '완료'라고 말해라. OAuth 동의·API 감사·채널 전화 인증·TTS 계정처럼 사람이 해야 하는 단계는 '사람이 할 일' 목록으로 따로 적어라.
- 테스트: python3 -m unittest discover -s tests. 세 게이트(대본·팩트·영상)는 반드시 단위 테스트가 있어야 한다. 검증용 실업로드는 하지 않는다.팁
- 숫자 확인 단계를 빼면 AI가 숫자를 지어낸 영상이 올라갈 수 있어요. 꼭 켜 두세요.
- 첫 주는 업로드 없이 영상만 만들어 보세요. 확인에서 떨어진 이유를 보면 대본 지침을 어디 고칠지 알 수 있어요.
- 목소리가 들어가는 영상은 요금이 들어서 하루 편수를 정해 두고, 나머지는 사진+자막 영상으로 채우면 비용이 줄어요.
- 채널이 여러 개면 설정 파일에 채널만 추가하면 돼요. 프로그램을 복사할 필요는 없어요.
출처
- 빌더로그 – 직접 작성 원문
- YouTube Data API – videos.insert (공식)
- YouTube API 할당량·감사 정책 (공식)
- ElevenLabs – Text to Speech with timestamps (공식)
- Playwright for Python (공식)
- dagu-org/dagu (GitHub)
권리: 빌더로그 직접 작성 · © 2026 빌더로그(builderlog.net). 실제 운영 중인 쇼츠 자동화 파이프라인을 바탕으로 빌더로그 편집부가 처음부터 썼습니다. 개인적·비상업적 용도로 본인의 에이전트에 붙여넣어 쓰는 것만 허용합니다. 상업적 이용 금지. 원문 전체·일부의 복제·재게시·재배포 금지(블로그·SNS·강의 자료·유료 자료 포함). 소개할 때는 이 페이지 링크만 허용합니다.