Ofox API와 Scribe로 녹음 파일을 SRT 자막으로 만드는 방법
Ofox의 Scribe로 음성을 전사하고 단어 타임스탬프에서 SRT를 만든 뒤 MP4에 자막 트랙을 추가합니다. 실제 응답과 변환 스크립트로 따라 할 수 있습니다.
Ofox의 /v1/audio/transcriptions 엔드포인트에 WAV 또는 MP3 파일을 업로드하고, verbose_json을 요청한 다음 응답에 포함된 단어별 타임스탬프를 확인하세요. 반환된 타임스탬프를 사용해 로컬에서 SRT 파일을 만들고, 자막을 녹음 파일과 대조해 검토할 수 있습니다. 이 튜토리얼에서 검증한 게이트웨이 경로에서는 SRT를 바로 요청하는 방식이 동일하게 지원되는 작업 흐름이 아닙니다. 어댑터가 JSON 출력을 받으며, 다운로드할 수 있는 변환기는 실제 응답을 바탕으로 자막 파일을 만듭니다.
2026년 10월 10일 테스트에서는 실제 10.00초 분량의 ElevenLabs 오디오 파일을 전사했습니다. Scribe는 스크립트의 단어를 반환했으며 문장부호에는 차이가 있었습니다. 단어별 타임스탬프는 0.14초부터 9.78초까지였습니다. 이 타임스탬프를 세 개의 자막 큐로 변환해 MP4에 선택 가능한 영어 자막 트랙으로 넣었습니다. 이는 전체 작업 경로의 한 가지 사례일 뿐, 음성 인식 정확도 벤치마크나 잡음이 있는 회의 녹음에 대한 테스트는 아닙니다.
결과물 묶음과 각 파일이 보여 주는 내용
다운로드 가능한 도구 모음에는 생성된 오디오 원본, 수정하지 않은 API JSON 응답, 변환기, SRT 파일, 선택 가능한 자막이 포함된 MP4가 들어 있습니다. 자막 편집기에서 각 큐의 타이밍이 어디에서 왔는지 확인할 수 있도록 파일을 한곳에 보관하세요.
ElevenLabs 생성 음성
| 파일 | 용도 | 이 파일만으로 입증되지 않는 내용 |
|---|---|---|
elevenlabs.mp3 | 실제 입력 녹음 파일 | 실제 사람의 음성이나 잡음이 있는 음성에서의 성능 |
narration-transcript.json | 수정하지 않은 Scribe 응답 | 사람이 교정한 최종 전사문 |
narration.srt | 로컬에서 묶고 타이밍을 지정한 자막 | 모든 대상 플레이어에서 SRT가 똑같이 표시된다는 점 |
subtitled-selectable.mp4 | 동영상, 오디오, 자막 스트림 | 플레이어 지원 없이도 보이는 영상에 합성된 자막 |
샘플 음성은 합성 음성이며, 대본은 이 튜토리얼을 위해 새로 작성한 자료입니다. 비공개 고객 녹음은 포함되어 있지 않습니다. 실제 인터뷰, 강의 또는 통화 녹음으로 바꾸려면 업로드 권한이 있는 자료를 사용하세요. 녹음을 들을 권한이 있다고 해서 클라우드 전사 서비스에 전송할 권한까지 자동으로 확보되는 것은 아닙니다.
1. 증거를 훼손하지 않고 녹음 파일 준비하기
테스트한 게이트웨이는 WAV와 MP3를 지원합니다. 원본이 MP4 또는 다른 컨테이너 파일이라면 먼저 오디오 사본을 추출하세요. 원본 파일을 보존하고 변환 명령도 기록해 두세요. 무음 구간, 편집 또는 샘플레이트 변환으로 타임스탬프 오프셋이 바뀌었다는 사실을 발견하면 원본 타임라인으로 되돌아갈 수 있어야 합니다.
ffmpeg -i original-video.mp4 -vn -c:a pcm_s16le recording.wav
ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 recording.wav
이 추출 과정에서는 압축되지 않은 오디오를 만들기 때문에, 압축된 원본보다 파일이 훨씬 커질 수 있습니다. WAV 파일이 더 크다고 해서 원래 음성 품질이 더 좋다고 판단하지 마세요. 작업에 적합한 지원 형식을 선택하고, 긴 녹음 파일이 언제나 요청 한 번에 들어간다고 가정하지 말고 계정의 현재 업로드 한도를 확인하세요.
첫 전사 전에 불필요한 편집은 피하세요. 2초짜리 도입부를 제거하면 이후 모든 자막의 위치가 편집하지 않은 동영상과 달라집니다. 클립만 따로 전사한다면 원본에서 클립이 시작된 시간을 저장하고, 전체 동영상에 자막을 되돌려 넣을 때 그 오프셋을 더하세요.
녹음 파일에 오디오 트랙이 여러 개라면 사용할 오디오 스트림을 명시적으로 선택하세요. 그렇지 않으면 음성 해설, 번역 또는 비어 있는 트랙이 추출될 수 있습니다. 입력 파일의 스트림을 확인하고, 잘못된 자료를 전사하는 데 비용을 쓰기 전에 내보낸 파일을 들어 보세요.
2. 올바른 모델로 멀티파트 요청 보내기
Ofox API 키를 OFOX_API_KEY에 설정하고 Python requests를 설치한 뒤, 제공된 클라이언트를 실행하세요.
python3 audio_api.py transcribe \
--input elevenlabs.mp3 \
--output my-transcript.json
클라이언트는 model=elevenlabs/scribe_v2와 response_format=verbose_json을 전송합니다. HTTP 라이브러리가 멀티파트 경계 문자열을 생성하도록 하고, 오디오를 바이너리 파일로 열며, 응답을 확인하고 입력 길이를 비롯한 메타데이터를 보존합니다. 실패했거나 시간 초과된 POST 요청을 자동으로 다시 보내지는 않습니다.
같은 요청을 cURL로 보내려면 다음과 같이 실행할 수 있습니다.
curl --fail-with-body --silent --show-error \
https://api.ofox.run/v1/audio/transcriptions \
-H "Authorization: Bearer $OFOX_API_KEY" \
-F 'model=elevenlabs/scribe_v2' \
-F 'response_format=verbose_json' \
-F 'file=@elevenlabs.mp3;type=audio/mpeg' \
--output my-transcript.json
추가로 요금이 발생하는 요청을 의도한 것이 아니라면 두 방법 중 하나만 사용하세요. 생성된 경계 문자열 없이 Content-Type: multipart/form-data를 직접 추가하지 마세요. 인증 헤더와 멀티파트 필드 선언의 역할은 서로 다릅니다. 키는 Authorization에 넣고, 모델과 파일은 폼 필드로 전달합니다.
계정에 제공되는 경로는 현재 Ofox Scribe 모델 페이지에서 확인하세요. 기본 제공업체 인터페이스를 설명하는 ElevenLabs 전사 문서에는 어댑터가 전달하지 않는 필드가 나올 수 있습니다. 기본 제공업체가 지원하는 기능만으로 Ofox를 통해서도 같은 매개변수가 작동한다고 볼 수는 없습니다.
3. 변환기를 작성하기 전에 실제 JSON 확인하기
응답에는 text, language, duration, usage, logprobs, words가 포함되어 있습니다. words의 각 항목에는 word, start, end가 들어 있습니다. 다른 스키마를 기준으로 작성한 코드에서는 각 단어 항목에 text가 있거나 segments 목록이 있다고 예상할 수 있지만, 실제로 받은 파일을 확인하는 대신 어느 쪽이든 가정해서는 안 됩니다.
예시 응답의 텍스트는 “A clear product video starts with a clear brief.”로 시작합니다. 마지막 단어는 9.78초에 끝나고, 오디오 컨테이너의 길이는 10.00초입니다. 발화가 끝나는 시점과 파일이 끝나는 시점은 같을 필요가 없습니다. 뒤에 무음이나 인코딩 패딩이 있을 수 있습니다.
다음 코드는 API를 다시 호출하지 않고 저장된 응답을 확인합니다.
import json
from pathlib import Path
result = json.loads(Path('my-transcript.json').read_text())
print(result['text'])
print(result.get('language'))
print(result.get('usage'))
for item in result.get('words', [])[:5]:
print(item['start'], item['end'], item['word'])
철자나 문장부호를 바꾸기 전에 원본 응답을 보존하세요. words가 없다면 일반 전사문만으로 정확한 자막 타이밍을 재구성할 근거가 충분하지 않습니다. 지원되는 타임스탬프 응답을 사용하거나 별도의 정렬 단계를 거치세요. 전체 길이를 단어 수로 똑같이 나누면 타이밍을 지어내는 셈이며, 이는 동등한 대안이 아닙니다.
텍스트에 이름이 나왔다고 해서 화자의 신원을 추정하지 마세요. 이 예시의 응답에는 단어별 타이밍은 있지만 검증된 화자 신원은 없습니다. 관련 회의 내용을 실행 항목으로 정리하는 작업 흐름에서도 담당자와 결정을 추출할 때 이 구분을 유지합니다.
4. 단어를 읽기 쉬운 자막 큐로 묶기
자막 큐에는 순번, 시작 및 종료 시각, 읽기 쉬운 텍스트가 필요합니다. 제공된 make_subtitles.py는 간단한 문자 수 및 길이 제한에 따라 실제 단어별 타이밍을 자막 큐로 묶습니다. 각 묶음에서 첫 단어의 시작 시각과 마지막 단어의 종료 시각을 보존하며, 새로운 정렬을 만들어 내지는 않습니다.
python3 make_subtitles.py my-transcript.json my-subtitles.srt
제공된 샘플에서 첫 번째 큐는 다음과 같습니다.
1
00:00:00,140 --> 00:00:02,980
A clear product video starts with a clear brief.
다음 두 큐는 각각 3.567.36초와 7.429.78초를 다룹니다. 타임라인을 연속으로 보이게 하려고 자막을 채워 넣지 않고, 첫 번째 문장 뒤의 간격을 그대로 유지합니다.
변환기의 58자 및 5초 묶음 제한은 이 짧은 영어 예시를 위한 구현상의 선택이지, 보편적인 접근성 표준이나 방송 표준이 아닙니다. 일본어, 한국어처럼 단어 사이 띄어쓰기 방식이 다른 언어에는 해당 언어에 맞는 분절 방식이 필요합니다. 영어 기준을 기계적으로 재사용하기보다 읽는 속도, 줄바꿈, 휴대전화 화면에 표시되는 텍스트 분량을 고려하는 것이 더 중요합니다.
모든 경계 지점을 검토하세요. 예시의 두 번째 큐는 “and”로 끝나는데, 기술적으로는 문제가 없더라도 편집상 좋은 끊김은 아닐 수 있습니다. 편집자는 해당 단어의 실제 타임스탬프를 유지하면서 인접한 큐 사이에서 단어를 옮길 수 있습니다. 수정한 자막 버전을 따로 보관하고 어떤 편집을 했는지 기록하세요. 차이를 감추기 위해 원본 전사를 덮어쓰지 마세요.
변환기는 누락되었거나 음수이거나 유한하지 않거나 단조 증가하지 않는 시작 시각을 거부합니다. 이는 구조상의 문제를 잡아낼 뿐 모든 시각적 결함을 찾아내지는 않습니다. 타임스탬프가 스키마 검사를 통과해도 자막을 읽기에는 너무 짧거나 문구가 부자연스러울 수 있습니다.
5. 출처를 보존하면서 전사문 교정하기
전사문을 녹음 파일 및 승인된 원본 자료와 대조하세요. 합성 예시에서는 의도한 단어가 반환됐지만 짧은 내레이션의 마지막 문장부호가 누락됐습니다. 문장부호 정규화는 제품명이 바뀌거나 부정어가 빠진 오류와는 다르므로 별도로 기록해야 합니다.
실제 녹음에서는 이름, 숫자, 날짜, 단위, “not”이 들어간 표현을 우선해서 확인하세요. 이런 세부 사항은 시청자가 무엇을 해야 하는지를 바꿀 수 있습니다. 발표 자료에 맞추려고 화자가 실제로 말한 내용과 다른 단어를 불확실한 부분에 조용히 끼워 넣지 마세요. 불확실성을 표시하거나 권한이 있는 검토자에게 확인하세요.
유용한 교정 표에는 원문 구절, 제안하는 수정, 오디오 시간 범위, 수정 이유, 검토 상태를 기록합니다. 오디오, 원본 JSON, 편집한 SRT는 각각 별도 결과물로 보관하세요. 자막이 바뀐 이유를 누군가 물으면 모델의 요약에 의존하는 대신 구체적인 원본 구간을 제시할 수 있습니다.
6. 동영상에 자막을 넣고 스트림 확인하기
선택 가능한 MP4 자막 트랙을 추가하면서 동영상과 오디오는 변경하지 않으려면 다음 명령을 사용하세요.
ffmpeg -i narration-video.mp4 -i my-subtitles.srt \
-map 0:v:0 -map 0:a:0 -map 1:0 \
-c:v copy -c:a copy -c:s mov_text \
-metadata:s:s:0 language=eng \
-disposition:s:0 default subtitled-selectable.mp4
자막에 맞는 언어 코드를 사용하세요. 이 명령은 텍스트 트랙을 추가할 뿐, 자막을 영상에 합성하지 않습니다. 데스크톱 플레이어에서 표시되더라도 일부 웹 플레이어는 이 트랙을 무시할 수 있습니다. 기본 트랙 플래그는 선호 설정을 나타낼 뿐, 모든 플랫폼에서 자막을 표시한다는 보장은 아닙니다.
제공된 10초 분량의 MP4에는 H.264 동영상, AAC 오디오, mov_text 자막 스트림이 들어 있습니다. 화면에는 앞서 소개한 튜토리얼 데모 동영상의 일부를 넣고 실제 내레이션을 결합했습니다. 이는 패키징 방법을 보여 주는 예시이지, API가 동영상 자체를 생성했다는 증거는 아닙니다.
스트림을 확인하고 삽입된 자막을 추출해 비교하세요.
ffprobe -v error -show_entries stream=codec_type,codec_name \
-of json subtitled-selectable.mp4
ffmpeg -i subtitled-selectable.mp4 -map 0:s:0 \
recovered-subtitles.srt
자막을 영상에 합성하려면 자막을 렌더링할 수 있는 도구를 사용하고 동영상을 다시 인코딩하세요. 이 튜토리얼에 사용한 FFmpeg 빌드는 시도한 자막 렌더링 필터를 지원하지 않았으므로, 제공된 예시에는 선택 가능한 자막을 사용했습니다. 이 결과물을 영상에 합성된 자막이 포함된 파일이나 플레이어에서 시각적으로 검증한 파일이라고 설명하지 않습니다. 특정 플랫폼에 게시하기 전에 해당 플랫폼에 실제로 업로드한 결과물을 의도한 플레이어에서 테스트하세요.
7. 잘못된 요청을 반복하지 않고 오류 진단하기
지원되지 않는 형식이라는 오류가 나오면 게이트웨이에서 허용하는 입력 및 응답 형식을 확인하세요. 이 오류만으로 Scribe의 기본 API에도 해당 기능이 전혀 없다고 볼 수는 없습니다. 사본을 WAV 또는 MP3로 변환한 뒤, 형식 불일치를 해결한 경우에만 다시 시도하세요.
쿼터와 관련된 401 오류가 발생하면 전체 응답 본문과 요청 ID를 확인해야 합니다. 이 프로젝트의 이전 요청은 업스트림 경로에서 실패했으며, 경로가 복구된 뒤 새 요청은 성공했습니다. 지갑 잔액이 양수라는 사실만으로는 어떤 제공업체 계정이 요청을 처리했는지 알 수 없습니다. 같은 녹음 파일을 반복해서 보내기보다 증거를 보존하세요.
자막이 시간이 지날수록 계속 어긋난다면 실제로 전사한 오디오와 동영상의 오디오를 비교하세요. 일정한 오프셋은 도입부가 잘렸거나 클립 시작 지점이 달라졌음을 시사할 수 있습니다. 오프셋이 변한다면 편집 내용이나 재생 속도가 다를 수 있습니다. 두 타임라인이 같은지 확인하기 전에는 추측으로 모든 큐를 “수정”하지 마세요.
파일이 길다면 분할하기 전에 원본 오프셋과 구간 중복 검토를 포함한 분할 계획을 세우세요. 청크 경계에서 단어가 중복되거나 문맥이 빠지면 자막이 달라질 수 있습니다. 이 짧은 파일용 변환기가 긴 녹음의 정렬까지 자동으로 해결한다고 볼 수는 없습니다.
8. 올바른 단위를 확인하고 검토 절차 마련하기
전사 사용량은 반환된 단어 수가 아니라 오디오 길이에 따라 계산됩니다. 이 파일의 컨테이너 길이는 ffprobe 기준 10.00초이고, 원본 API 응답의 usage.seconds는 10.083265306122449입니다. 차이를 반올림해 없애지 말고 두 값을 모두 보존하세요. 마지막 발화 단어의 종료 시각을 입력 파일의 청구 대상 길이로 대신 사용하지 말고, 이 사용량 필드만으로 확정된 청구 금액을 추정하지도 마세요.
자막이 완성됐다고 판단하기 전에 다섯 가지를 확인하세요. 권한이 있는 올바른 녹음 파일을 업로드했는지, 저장된 JSON이 성공 응답인지, 타이밍이 실제 단어 정보에서 왔는지, 편집한 텍스트를 검토했는지, 대상 플레이어에서 의도한 자막 버전이 표시되는지 확인해야 합니다. 다운로드 가능한 도구 모음은 API 요청, 변환, 컨테이너 확인까지 보여 줍니다. 시청자에게 공개하기 전의 재생 확인은 사용 환경에서 별도로 진행해야 합니다.
자주 묻는 질문
- 이 Ofox 엔드포인트에 SRT를 바로 요청할 수 있나요?
- 여기서 검증한 경로는 JSON 또는 verbose JSON을 받습니다. 기본 제공업체의 SRT 옵션이 전달된다고 가정하는 대신, 반환된 단어별 타임스탬프를 로컬에서 변환하는 방법을 설명합니다.
- 응답에 텍스트는 있지만 words 배열이 없으면 어떻게 하나요?
- 전사문은 보존하되 단어별 타이밍을 지어내지는 마세요. 타임스탬프가 포함된 지원 응답을 받거나 별도의 정렬 절차를 거친 뒤 시간 지정 자막을 만드세요.
- 이 자막은 영상에 합성된 자막인가요?
- 아니요. 제공된 MP4에는 선택 가능한
mov_text자막 스트림이 들어 있습니다. 플레이어마다 지원 여부가 다르며, 영상 프레임에 텍스트를 합성하려면 자막을 렌더링해야 합니다. - 이 테스트로 회의에서 Scribe의 정확도를 확인할 수 있나요?
- 아니요. 이 테스트는 깨끗한 짧은 합성 내레이션을 대상으로 했습니다. 실제 회의에는 겹치는 발화, 잡음, 이름, 화자 식별의 모호성 등이 있어 별도의 평가와 교정 절차가 필요합니다.


