일괄 전사 API: 여러 오디오 파일을 텍스트로 변환하기

API 일괄 전사는 파일마다 음성 인식 Job을 하나씩 보내는 루프입니다. 키는 파일 ID로 만들고, 결과는 웹훅이나 폴링으로 모읍니다. Sume에서 동작하는 방식을 설명합니다.

읽는 시간 5분Sume
전체 글

Job 기반 음성 인식 API에서 일괄 전사는 루프입니다. 오디오 파일마다 그 파일에서 만든 멱등성 키를 붙여 Job을 하나씩 제출하고, 아직 시작할 수 없는 Job은 서비스가 큐에 넣도록 두고, Job이 끝날 때마다 전사문을 저장하세요. Sume STT 1.0도 이렇게 동작합니다. 파일마다 별도의 POST /v1/stt-1.0/transcribe Job이 되며, 워크스페이스의 동시성 한도를 넘는 Job은 큐 용량이 남아 있는 동안 queued 상태로 기다립니다.

STT 1.0은 Sume API 레퍼런스의 바탕이 되는 OpenAPI 문서에 명세되어 있으며, API 레퍼런스 문서 페이지는 정확한 요청·응답 형태의 기준으로 이 문서를 안내합니다. 큐와 폴링은 Generation admission과 Job과 결과 (영문) 문서를 따릅니다. 모두 2026-09-27에 확인했습니다. 파일 하나만 전사한다면 단어별 타임스탬프를 주는 음성 인식 API를 참고하세요.

여러 파일을 한 번에 보내는 일괄 엔드포인트가 있나요?

없습니다. STT 1.0 요청은 audio_url 문자열 하나를 받고 스키마에 정의되지 않은 필드는 거부하므로, 파일 목록을 보낼 수 없습니다. 일괄 처리는 여러분의 서버에서 도는 루프이며, 파일 하나에 요청을 하나씩 보냅니다.

  • audio_url: 파일의 공개 HTTPS URL입니다. 요청에 업로드 필드가 없으므로, 각 파일은 이미 URL로 접근할 수 있어야 합니다.
  • duration_seconds: 파일 길이로, 1–600 범위입니다. 사용량 예약의 크기를 정하며, 생략하면 Sume가 1분을 예약합니다. 10분이 넘는 파일은 먼저 여러 조각으로 나눠야 합니다.
  • segmentation: { "mode": "sentence" }를 넣으면 각 결과에 문장 타임스탬프가 추가됩니다.
  • webhook_url: 각 Job이 끝날 때 호출할 공개 HTTPS 콜백입니다. 대신 폴링하려면 생략하세요.
  • Idempotency-Key: 파일 자체의 ID로 만듭니다. 그래서 같은 본문으로 다시 보내면 두 번째 Job 대신 원래 Job이 반환됩니다.
// Server-side Node 18+. files: [{ id, url, seconds }] from your own storage.
const jobIds = new Map(); // your file id -> Sume job id; persist it
for (const file of files) {
  const res = await fetch("https://api.sume.com/v1/stt-1.0/transcribe", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + process.env.SUME_API_KEY,
      "Content-Type": "application/json",
      "Idempotency-Key": "stt-" + file.id, // same key, same body on every retry
    },
    body: JSON.stringify({
      audio_url: file.url,
      duration_seconds: file.seconds,
      segmentation: { mode: "sentence" },
      webhook_url: "https://example.com/webhooks/sume",
    }),
  });
  if (res.status === 429) break; // queue full or rate limited: wait, then resume
  if (!res.ok) throw new Error(await res.text());
  const { data } = await res.json();
  jobIds.set(file.id, data.request_id); // request_id is the job id
}

동시에 실행할 수 있는 것보다 많은 파일을 제출하면 어떻게 되나요?

남는 Job은 기다립니다. Sume는 유료 Job을 큐 우선(queue-first) 방식으로 접수합니다. 유효한 Job은 곧바로 시작하거나, 워크스페이스 동시성 슬롯이 열릴 때까지 queued에서 기다립니다. 현재 코드에서 speech_to_text는 이 슬롯을 차지하는 Job 유형 중 하나입니다.

동시성 한도는 요금제가 정하며, 큐 용량의 기본값은 max(3, concurrency_limit × 5)입니다. Sume가 계산할 수 있을 때는 제출 응답에 generation_limits 스냅샷이 담깁니다. 이 스냅샷으로 제출 묶음(wave)마다 크기를 정하는 방법은 영상 Job 동시성과 큐에서 다룹니다. 루프는 다음 응답을 처리해야 합니다.

Generation admission과 Job과 결과 (영문) 기준, 2026-09-27 확인.
응답의미루프가 할 일
2xxJob이 존재하고 유료 작업이 진행 중이라는 뜻. 끝났다는 뜻은 아님.Job ID를 저장하고 다음 파일로 넘어감.
429 queue_full워크스페이스에 남은 수락 생성 용량이 없음.멈추고 Job이 끝나기를 기다린 뒤, 같은 파일을 같은 키로 재시도.
429 rate_limited요청량이 남용 방지 한도를 넘음.retry-after가 있으면 그 값을 따라 백오프하고, 같은 키로 재시도.
402 insufficient_credits잔액으로 예상 금액을 감당할 수 없음. 아무것도 시작되지 않음.잔액이 감당할 수 있을 때까지 일괄 처리를 멈춤.
409 idempotency_conflict그 키가 이미 다른 페이로드에 쓰였음.키를 만드는 방식을 고침. 키는 똑같은 요청을 재시도할 때만 재사용.

전사문은 어떻게 모으나요?

웹훅을 받거나, 폴링하거나, 둘 다 쓰세요. 문서는 웹훅을 유일한 복구 경로가 아니라 전달 최적화라고 설명하므로, 폴링도 쓸 수 있게 남겨 두세요.

  • 웹훅: 각 Job이 끝나면 Sume가 job.completed, job.failed, job.canceled 중 하나의 서명된 이벤트를 보내며, 진행 상황 콜백은 없습니다. 서명을 검증한 다음 그 Job의 결과를 가져오세요.
  • 폴링: terminal이 true가 될 때까지 next_poll_after_seconds를 지키며 백오프로 GET /v1/jobs/{id}/status를 호출하세요. GET /v1/jobs/{id}/result는 Job이 완료될 때까지 409 job_not_completed로 응답합니다.
  • 복구: GET /v1/jobs?type=speech_to_text는 Job을 최신순으로, 페이지당 최대 100개까지 나열합니다. 각 행에는 생성할 때 쓴 idempotency_key가 담기므로, 결과는 순서가 아니라 이 키로 파일과 맞추세요.
  • 완료된 결과에는 text, 각 단어의 start와 end를 초 단위로 담은 words[], 문장을 요청했다면 segments[], 그리고 있는 경우 language_code가 들어 있습니다.
  • 같은 키로 다시 보내면 원래 Job이 반환됩니다. 그러니 실패한 파일을 다시 시도하려면 파일 ID에 시도 번호를 붙이는 식으로 새 키를 만들어 보내세요.

일괄 전사 비용은 얼마인가요?

파일을 하나씩 전사할 때와 같습니다. API 요금에 나온 오디오 분당 $0.01에 기본 5.5% 에이전트 수수료가 더해집니다. 5분짜리 녹음 100개가 밀려 있다면 오디오는 500분이고, 수수료 전 비용은 $5.00입니다.

Sume는 제출을 수락할 때 Job마다 예상 금액을 예약하고, Job이 완료되면 확정하며, Job이 실패하면 해당하는 경우 예약을 해제하거나 환불합니다. 큐에서 대기 중인 Job이 더 이상 필요 없다면 POST /v1/jobs/{id}/cancel로 취소하세요. Job이 이미 시작된 뒤에는 취소 요청이 409 job_generation_already_started로 응답하고, Job은 끝까지 실행됩니다.

어떤 제한이 있나요?

  • 요청 하나에 파일 하나, 오디오는 최대 10분입니다. duration_seconds의 최댓값이 600입니다.
  • webhook_url은 공개 HTTPS여야 하며 최대 2,048자입니다. localhost와 사설 네트워크 URL은 거부됩니다.
  • mode: "sync"는 요청을 최대 30초까지만 붙잡고 있으므로, 일괄 처리에는 async나 webhook을 쓰세요.
  • 워크스페이스에서 수락되는 Job은 동시성 한도에 큐 용량을 더한 수까지입니다. 그 이상이면 제출이 429 queue_full로 응답합니다.

출처

관련 글

개발자 카테고리의 다른 글

개발자 글 전체 보기

작성자 Sume