AI 도구 목록

타입캐스트 API 낱말 시각으로 자막 맞추다 막힌 곳

2026년 10월 6일Importants Studio

쇼츠 영상에서 말하는 낱말에 맞춰 화면 글자가 나타나게 만들려면 음성 파일만으로는 부족합니다. 어느 낱말이 언제 시작하고 끝나는지 알아야 자막 조각의 길이를 맞출 수 있기 때문입니다. 처음에는 음성을 합성한 뒤 별도 방식으로 시각을 잡으려 했지만, 타입캐스트 응답에서 낱말 단위 시각을 함께 받을 수 있는 방법을 찾았습니다.

다만 요청 하나가 성공했다고 바로 영상 조립까지 이어지지는 않았습니다. 긴 문장이 두 번 읽히기도 했고 음성 조각과 룸톤을 붙이는 과정에서는 결과 파일이 조용히 짧아졌으며, 캐시 이름을 순번으로 정한 탓에 문장 하나를 고친 뒤 바뀌지 않은 음성까지 다시 결제한 일도 있었습니다.

먼저 결론부터

  • 화면 글자 동기화에는 granularity=word가 붙은 낱말 시각 엔드포인트를 사용합니다.
  • 응답에는 base64 오디오와 words 배열이 함께 오며, 각 낱말에 초 단위 start, end가 들어 있습니다.
POST https://api.typecast.ai/v1/text-to-speech/with-timestamps?granularity=word
X-API-KEY: <API 키>
  • 여러 구간과 쉼을 한 요청에 넣는 /text-to-speech/compose는 낱말 시각을 주지 않아 화면 동기화에 쓸 수 없었습니다.
  • 낱말 사이가 1초 넘게 벌어지면 경고를 남기고 문장을 고쳐 썼습니다.
  • 합성 음성과 룸톤은 -ar 44100 -ac 2로 맞춘 뒤 이어 붙였습니다.
  • 캐시는 순번이 아니라 본문·목소리·감정·세기의 해시로 저장하니 재합성 대상이 436자에서 140자로 줄었습니다.

낱말 시각이 나오는 요청으로 바꿨습니다

처음에는 여러 문장과 쉼을 한 번에 처리할 수 있는 compose 경로가 더 편해 보였습니다. 하지만 이 경로가 돌려주는 것은 음성뿐입니다. 낱말별 시각이 빠져 영상 편집 단계에 필요한 정보가 없었습니다.

낱말 시각 엔드포인트는 오디오와 words 배열을 같이 돌려줍니다. 각 항목의 start, end를 읽어 자막이 나타나는 시각과 사라지는 시각으로 사용했고, 음성을 다시 분석하지 않아도 됐습니다.

{
  "voice_id": "tc_637cbfeef7f00f21e8a1c6c8",
  "text": "읽을 문장",
  "model": "ssfm-v30",
  "language": "kor",
  "output": {
    "audio_format": "wav",
    "target_lufs": -14,
    "remove_silence_ms": 250
  },
  "prompt": {
    "emotion_type": "smart",
    "previous_text": "앞 문장",
    "next_text": "뒤 문장"
  }
}

smart를 쓰면 앞뒤 문장을 보고 모델이 억양을 고르는데, 문장만 따로 합성하면 어색해질 수 있어 앞 문장과 뒤 문장은 요청에 넣었습니다. 다만 이 값은 캐시 키에는 넣지 않았습니다. 이웃 문장이 바뀔 때마다 같은 본문을 다시 합성하는 일이 생기기 때문입니다.

감정 이름을 잘못 넣어 422를 만났습니다

감정 이름을 emotion_type에 넣었다가 422 응답을 받았습니다. 이 필드에 들어가는 값은 preset, embedding, smart 셋뿐이고, toneup이나 happy 같은 이름을 직접 넣는 자리가 아닙니다.

고정 감정을 쓸 때는 emotion_type을 preset으로 두고 감정 이름은 emotion_preset에 넣고, 세기는 emotion_intensity로 조절하며 범위는 0~2이고 기본값은 1.0입니다. 반대로 smart는 세기를 조절하지 못합니다.

이 구분을 모르면 음성 품질 문제가 아니라 요청 형식 문제로 막힙니다. 응답이 안 올 때는 목소리나 문장보다 감정 필드부터 다시 봅니다.

긴 문장은 길이보다 낱말 간격을 봤습니다

45자 문장과 54자 문장에서 구간을 두 번 읽는 현상이 있었고, 낱말 시각 배열에는 2.0초, 2.9초짜리 구멍이 생기면서 파일 길이도 그만큼 늘었습니다. 처음에는 글자 수 제한이라고 생각했습니다.

그런데 77자 문장은 멀쩡했습니다. 길이는 기준이 아닙니다. 대신 응답의 낱말 시각을 훑어 낱말 사이가 1초 넘게 벌어지면 경고를 찍도록 바꿨고, 경고가 난 문장은 다시 요청하지 않고 표현을 고쳐 썼습니다.

나누는 위치도 문제입니다. 낱말 시각을 받으려면 문장별로 요청해야 했고 조각 사이에는 룸톤이 들어갔는데, 마침표와 물음표에서 나눈 조각은 자연스러웠지만 문장 중간에서 자른 조각은 말이 끊겨 들렸습니다.

모노 음성과 스테레오 룸톤을 그대로 붙이지 않았습니다

응답 오디오는 모노입니다. 반면 영상에 넣을 룸톤은 스테레오로 만들어 두었습니다. 처음에는 두 파일을 그대로 ffmpeg에 넘겼는데, 형식이 다른 조각을 조용히 버리는 일이 있었습니다.

56초짜리여야 할 결과가 31초로 잘린 적이 있는데, 오류 메시지가 뚜렷하지 않아 합성 요청이 덜 왔는지부터 확인했습니다. 실제 원인은 결합 단계였습니다.

이후 음성 조각과 룸톤을 모두 같은 형식으로 맞춘 뒤 이어 붙였습니다.

ffmpeg -i input.wav -ar 44100 -ac 2 output.wav

낱말 시각은 정상이어도 최종 음성의 길이나 위치가 달라지면 자막 시각도 함께 어긋납니다. 그래서 합성 응답을 받은 뒤에는 낱말 배열만 저장하지 않고 변환 뒤 음성 파일도 함께 확인합니다.

순번 캐시를 버리고 내용 해시로 바꿨습니다

처음 캐시는 p00.wav, p01.wav처럼 순번으로 저장했는데, 문장 하나를 둘로 나누자 뒤의 번호가 전부 밀렸고, 이미 만든 음성이 있어도 다른 파일로 인식되어 다시 합성됐습니다.

이 방식에서는 문장 수정이 곧 대량 재요청입니다. 실제로 다시 합성하는 분량이 해시 캐시를 적용한 뒤 436자에서 140자로 줄었습니다. 비용 차이도 있었지만, 먼저 줄어든 쪽은 기다리는 시간입니다.

캐시 키에는 본문, 목소리, 감정, 세기를 넣습니다. 앞뒤 문장은 요청에는 전달하되 키에서는 뺐습니다. 앞 문장이 바뀌었다는 이유만으로 바뀌지 않은 음성 파일까지 다시 만들 필요는 없었기 때문입니다.

요금은 1글자에 1크레딧으로 계산됩니다. 무료 구간은 15,000자이며 상업적 이용이 안 되고 출처 표기가 필요합니다. Lite는 월 $15에 20만 자를 쓸 수 있고 상업 이용과 표기 조건이 달라집니다. 초과분은 10만 크레딧 단위로 청구되므로, 요청 전에 대시보드 잔액을 확인합니다. 잔액 조회 API는 찾지 못했습니다.