Python으로 영상에 자막을 넣는 방법
Python Requests로 영상에 자막을 넣으세요. 영상 URL을 Sume의 /v1/video-captions로 POST하고, Job을 폴링한 뒤 자막을 입힌 video_url을 읽으면 됩니다.

ffmpeg나 음성 모델을 직접 돌리지 않고 Python으로 영상에 자막을 넣으려면, 영상 URL을 자막 API로 보내고 자막을 입힌 파일을 받아 오세요. Sume와 Requests 라이브러리로는 Idempotency-Key와 함께 URL을 https://api.sume.com/v1/video-captions에 POST하고, 돌려받은 status_url을 terminal이 true가 될 때까지 폴링한 다음, GET /v1/video-captions/{id}에서 자막을 입힌 video_url을 읽으면 됩니다.
Sume 관련 내용은 영상 캡션과 Job과 결과 (영문) 문서, Sume API 레퍼런스에서, Requests 동작은 Requests의 빠른 시작에서 가져왔으며, 모두 2026-09-27에 확인했습니다. Sume의 SDK는 TypeScript용이고 SDK가 하는 일은 모두 일반 HTTP로도 할 수 있으므로, 이 글은 Sume 문서의 Python 예제처럼 일반 HTTPS 호출을 씁니다.
전체 스크립트는 어떻게 생겼나요?
제출, 폴링, 조회를 25줄로 처리합니다. 문구 필드가 없으면 Sume가 음성을 전사해 자막으로 입히며, language는 선택 사항인 음성 인식 힌트입니다. 키는 신뢰할 수 있는 서버나 본인 컴퓨터의 환경 변수에 두고, 프론트엔드 JavaScript나 모바일 앱에는 절대 넣지 마세요.
import os, time, requests
API = "https://api.sume.com/v1"
AUTH = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def get(url):
r = requests.get(url, headers=AUTH, timeout=30)
r.raise_for_status()
return r.json()["data"]
body = {"video_url": "https://example.com/clip.mp4", "language": "en"}
r = requests.post(f"{API}/video-captions", json=body, timeout=30,
headers={**AUTH, "Idempotency-Key": "clip-captions-001"})
r.raise_for_status()
job = r.json()["data"]
status = get(job["status_url"])
while not status["terminal"]:
time.sleep(status["next_poll_after_seconds"] or 5)
status = get(job["status_url"])
caption = get(f"{API}/video-captions/{job['video_caption_id']}")
if caption["status"] != "completed":
raise RuntimeError(caption["error"])
print(caption["video_url"])각 호출은 무엇을 보내고 무엇을 돌려받나요?
이 응답들은 모두 페이로드를 data로 감쌉니다. 스크립트가 읽는 필드는 다음뿐입니다.
json=을 쓰면 Requests가 본문을 인코딩하고Content-Type: application/json을 설정합니다.timeout=이 중요합니다. 타임아웃을 지정하지 않으면 Requests는 타임아웃되지 않으며, Requests 문서는 프로그램이 무기한 멈출 수 있다고 경고합니다.raise_for_status()는 오류 상태를 받으면 예외를 발생시킵니다. Requests 문서는 JSON 본문을 디코딩할 수 있다고 해서 호출이 성공한 것은 아니라고 짚습니다. Sume의 오류도 JSON이며, 분기 기준으로 쓸 수 있는 안정적인error.code가 있습니다.- 같은
Idempotency-Key와 같은 본문으로 제출을 다시 보내면, 두 번째 Job이 과금되지 않고 원래 Job이 돌아옵니다.
| 단계 | 요청 | 스크립트가 읽는 필드 |
|---|---|---|
| 제출 | video_url(필수)과 Idempotency-Key 헤더를 담은 POST /v1/video-captions | status_url, video_caption_id |
| 폴링 | status_url에 GET | terminal, next_poll_after_seconds |
| 조회 | GET /v1/video-captions/{id} | status, video_url, error |
스크립트는 얼마나 기다려야 하나요?
terminal이 true가 될 때까지 폴링하고, next_poll_after_seconds가 있으면 조회 사이에 그만큼 기다리세요. 없으면 백오프하세요. 스크립트를 멈춰도 Job은 취소되지 않습니다. Job은 계속 실행되고 과금도 되므로, Job을 저장해 두었다가 status_url에서 다시 이어 가세요.
폴링을 건너뛰려면 webhook_url을 보내세요. 그러면 Sume는 종료 이벤트인 job.completed, job.failed, job.canceled만 서명된 POST로 전달합니다. 서버 쪽은 Python 웹훅 수신기에서 다루며, 폴링은 백업으로 유지하세요.
무엇이 잘못될 수 있고, 비용은 얼마인가요?
실패한 자막에는 error.public_reason과 error.next_action이 담깁니다. 흔한 경우는 다음과 같습니다.
caption_no_speech, 다음 동작use_overlay_captions: 클립에 들리는 음성이 없습니다. 대신 직접 쓴 줄을cues로 보내세요. 형태는 SRT 자막 파일을 영상에 입히는 방법에 있습니다.script_alignment_mismatch또는script_alignment_failed, 다음 동작simplify_script_text_or_omit: 보낸script_text가 음성과 맞지 않았습니다.caption_hangul_text_latin_style이 담긴400: 한국어 텍스트를slam,punch,tiktok-green으로 보낸 경우입니다. 한글 스타일을 지정하세요.- 현재 자막 워커는 60초보다 긴 원본이나 오디오 스트림이 없는 원본도 거부합니다. 더 긴 영상은 긴 영상에 자막 넣기를 참고하세요.
- 접수된 Job마다 60초 이하 영상에 대해 영상 캡션 페이지에 나온 고정 금액이 예약되고 확정됩니다.
출처
관련 글
연동 카테고리의 다른 글
- Claude 커스텀 커넥터로 Sume 추가하기 (원격 MCP)
Customize > Connectors에서 Sume 호스팅 MCP 서버를 Claude에 추가하고, Sume OAuth 동의가 무엇을 부여하는지 확인한 뒤, 유료 도구를 허용할지 정하세요.
- Airflow HTTP 센서로 AI 영상 Job 완료 기다리기
Airflow의 HttpOperator로 AI 영상 Job을 제출한 뒤, Job 상태가 completed가 되면 통과하는 reschedule 모드의 HttpSensor로 기다리세요.
- Airtable 자동화 영상 생성 API: 레코드마다 영상 하나
Airtable Run a script 액션으로 callback_url과 함께 POST /v1/videos를 호출하고, 두 번째 자동화에서 Sume 웹훅을 받아 URL을 저장하세요.
- Amazon Q MCP 서버: IDE에 Sume 호스팅 MCP 추가
IDE의 Amazon Q Developer는 HTTP MCP 서버를 지원합니다. API 키 헤더나 OAuth로 Sume 호스팅 MCP를 추가한 뒤, 유료 도구는 Ask로 설정하세요.
작성자 Sume