유튜브 쇼츠를 직접 촬영하지 않고 Python으로 자동 생성하는 시스템을 실제로 운영하고 있다.
UGREEN DXP4800PLUS NAS에서 YouTube API로 트렌드 데이터를 수집하고,
성장률 분석 → 주제 선정 → 대본 생성 → 음성 합성 → 영상 합성까지 자동으로 처리한다.
현재 약 1,100개 영상 데이터를 수집 중이며, 30분마다 트렌드 분석을 수행한다.
이 글은 그 파이프라인 전체 구조와 실제로 막혔던 부분들을 정리한다.
전체 파이프라인 구조
YouTube API ↓ PostgreSQL (영상 데이터 저장) ↓ 성장률 분석 (6시간 / 24시간) ↓ AI 언어 모델 (대본 생성) ↓ Edge-TTS (한국어 음성 합성) ↓ FFmpeg (자막 + 배경 합성) ↓ drafts/ 폴더 저장 ↓ 수동 검토 ↓ YouTube 업로드
각 단계가 독립적인 Python 스크립트로 구성돼 있어서
문제가 생긴 단계만 수정하고 나머지는 그대로 쓸 수 있다.
1. PostgreSQL에서 트렌드 주제 선정
단순히 조회수 높은 영상이 아니라 6시간 성장률 기준으로 지금 뜨는 주제를 고른다.
성장률 계산 구조는 이전 글
PostgreSQL로 YouTube 조회수 성장률 계산하기에서 다뤘다.
import asyncpg
async def get_trending_topics():
conn = await asyncpg.connect(DATABASE_URL)
rows = await conn.fetch("""
SELECT v.title, v.content_cluster, s.growth_6h
FROM videos v
JOIN video_snapshots s ON v.video_id = s.video_id
WHERE s.recorded_at = (SELECT MAX(recorded_at) FROM video_snapshots)
AND s.growth_6h IS NOT NULL
AND v.content_cluster = 'AI_AUTOMATION'
ORDER BY s.growth_6h DESC
LIMIT 5
""")
await conn.close()
return [dict(r) for r in rows]
content_cluster = 'AI_AUTOMATION'으로 필터링해서
채널 방향성과 맞는 주제만 고른다.
2. AI 언어 모델로 대본 생성
주제가 정해지면 AI 언어 모델로 60초 분량의 쇼츠 대본을 생성한다.
import httpx, os
async def generate_script(topic: str) -> str:
# OpenRouter를 통해 AI 언어 모델 호출 (모델명은 env로 관리)
api_key = os.getenv("OPENROUTER_API_KEY")
prompt = f"""
다음 주제로 유튜브 쇼츠 대본을 작성해줘.
주제: {topic}
조건:
- 60초 분량 (약 250자)
- 첫 3초 안에 핵심 내용 언급
- 구어체로 작성
- 영어 단어는 한국어 발음으로 변환 (API → 에이피아이)
"""
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json={
"model": os.getenv("SCRIPT_MODEL"),
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 500,
},
)
return resp.json()["choices"][0]["message"]["content"]
영어 단어를 한국어 발음으로 변환하는 조건이 중요하다.
Edge-TTS가 영어 단어를 만나면 발음이 어색해지기 때문이다.
이 부분은 이전 글
Edge-TTS 한국어 음성 생성 시 발음 오류와 자막 싱크 문제 해결 방법에서 자세히 다뤘다.
3. Edge-TTS로 음성 합성
import edge_tts
import asyncio
async def text_to_speech(text: str, output_path: str):
communicate = edge_tts.Communicate(
text=text,
voice="ko-KR-SunHiNeural",
rate="+20%"
)
await communicate.save(output_path)
asyncio.run(text_to_speech(script, "output/audio.mp3"))
rate="+20%"는 실험 끝에 정착한 값이다.
기본 속도는 쇼츠용으로 약간 느리고, +20%가 약 4.2자/초로 60초 분량에 맞다.
4. FFmpeg으로 영상 합성
import subprocess
def create_video(audio_path: str, bg_image: str, output_path: str):
cmd = [
"ffmpeg",
"-loop", "1",
"-i", bg_image,
"-i", audio_path,
"-c:v", "libx264",
"-tune", "stillimage",
"-c:a", "aac",
"-b:a", "192k",
"-pix_fmt", "yuv420p",
"-shortest",
"-vf", "scale=1080:1920",
"-r", "30",
output_path
]
subprocess.run(cmd, check=True)
-r 30으로 fps를 고정하는 게 중요하다.
소스 클립마다 fps가 25~29.97로 제각각이라 고정하지 않으면
자막 싱크가 어긋나는 문제가 생긴다.
실제로 막혔던 문제들
문제 1: 자막 싱크 어긋남
음성 길이와 자막 타임라인이 맞지 않았다.
원인은 fps 불일치였다. 소스마다 fps가 달라서 자막 타임코드 계산이 틀렸다.
-r 30으로 고정 후 해결됐다.
문제 2: 영어 단어 발음 오류
“FastAPI”를 Edge-TTS가 어색하게 읽었다.
대본 생성 프롬프트에 영어 단어 한국어 변환 조건을 추가해서 해결했다.
문제 3: 생성 영상이 세로형이 아님
유튜브 쇼츠는 9:16 비율(1080×1920)이어야 한다.
-vf scale=1080:1920을 추가해서 강제 변환했다.
실제 운영 결과
- 수집 영상: 약 1,100개
- 저장 스냅샷: 약 74,000개
- 트렌드 분석 주기: 30분
- 쇼츠 1개 생성 시간: 평균 2~3분
- 생성 결과물: drafts/ 폴더 저장 후 수동 검토 → 업로드
- 채널: AI자동화휴게소
완전 자동 업로드는 아직 적용하지 않았다.
대본 품질 검토가 필요한 단계라 지금은 생성 → 검토 → 수동 업로드 흐름을 유지한다.
마무리
Python으로 쇼츠를 자동 생성하는 건 기술적으로 어렵지 않다.
핵심은 트렌드 데이터 → 주제 선정 → 대본 → 음성 → 영상의 흐름을 자동화하는 것이다.
각 단계를 독립적으로 구성해두면 한 단계에 문제가 생겨도 전체를 다시 짜지 않아도 된다.
관련 글: