실시간 번역 지연의 대부분은 기다림입니다. 스트림을 기다리고, 다음 단어를 기다리고, 문장이 끝나기를 기다립니다. 직접 조절할 수 있는 부분은 지연 시간 모드 하나뿐입니다. 지연을 줄일지, 수정을 줄일지 고르는 것입니다.
번역 자막을 읽는 청취자는 발표자가 말한 뒤 몇 초가 지나서야 각 줄을 봅니다. 이 간격은 하나의 지연이 아니라, 사슬을 따라 차례로 쌓인 여러 지연의 합이며, 그중 대부분은 일종의 기다림입니다. 어떤 기다림이 무엇인지 알면 지연 시간 모드를 쉽게 고를 수 있고, 리더를 만드는 개발자는 언제 무엇을 렌더링해야 하는지 판단할 수 있습니다.
숫자를 보기 전에 기준으로 삼을 만한 값이 하나 있습니다. 사람 동시통역사는 보통 발화자보다 2~4초 뒤처져 말합니다. 통역사들은 이 간격을 이어-보이스 간격(ear-voice span)이라고 부릅니다. 동사가 문장 끝에 오는 언어에서는 동사를 기다리는 대신 동사를 예측하거나, 문장을 혼자 설 수 있는 조각으로 나누어 대응합니다. 1~2초의 지연은 소프트웨어의 결함이 아닙니다. 아주 뛰어난 사람 통역사가 내는 지연과 대략 같은 수준입니다.
VocalStack의 모든 실시간 전사는 같은 단계를 같은 순서로 거치며, 각 단계는 앞 단계를 기다립니다.
원문 텍스트는 말하는 것과 거의 같은 순간에 독자에게 도착합니다. 번역은 1~2초 뒤에 따라오고, 음성은 번역문을 읽은 뒤에 나오므로 음성 클립이 항상 가장 나중에 도착합니다. 다만 이 사슬이 처음으로 눈에 보이게 작동하는 순간은 음성보다 훨씬 먼저, 텍스트 자체가 움직일 때입니다.
실시간 자막에서 사람들이 가장 먼저 알아차리는 것은 맨 끝의 단어들이 움직인다는 점입니다. 구절이 나타났다가 바뀌고, 그다음 자리를 잡습니다. 이것이 초안 단계가 하는 일이며, 이 단계가 필요한 이유는 모든 음성 인식기에 해당합니다.
인식기는 단어를 확정하기 위해 그 뒤에 오는 말을 봅니다. "I scream"과 "ice cream"은 다음 단어가 들리기 전까지 소리가 같습니다. 단어 끝의 "s"도 이 단어에 속하는지 다음 단어에 속하는지 알 수 없습니다. 단어 오른쪽에 오디오가 들리기 전까지 그 철자는 추측일 뿐이므로, 실시간 전사에서 가장 최근의 단어들은 언제나 가장 불확실합니다. 초안은 그 추측을 숨기지 않고 일찍 보여 주는 것입니다.
각 초안은 실시간 꼬리 부분, 즉 마지막 확정본 이후에 들린 단어들을 통째로 대체합니다. 이 단어들은 아직 바뀌고 있습니다. 확정본은 최종입니다. 절대 바뀌지 않으며, 단어 단위의 타이밍을 담고, 번호가 빠짐없이 매겨지므로 리더는 놓친 확정본이 있는지 알 수 있습니다.
개발자가 실시간 API에서 반드시 지켜야 할 규칙은 이것 하나입니다. 확정된 세그먼트를 모두 렌더링한 다음, 그 뒤에 최신 초안을 렌더링하고, 확정본이 도착하면 초안을 지웁니다. 초안을 계속 덧붙이면 텍스트가 중복되고 깜빡입니다. 확정본이 도착하면 꼬리 부분을 대신 채우기 때문입니다. WebSocket 튜토리얼이 바로 이 방식으로 리더를 만듭니다.
호스트에게 움직이는 텍스트는 낮은 지연의 대가입니다. 구절이 끝나기 전에 단어를 보여 주는 것이 자막을 실시간처럼 느끼게 만듭니다. 하지만 번역에는 같은 방식을 쓸 수 없습니다. 단어는 구절의 절반만 듣고도 추측할 수 있지만, 번역은 그렇게 할 수 없기 때문입니다.
어순 때문에 번역은 초안의 속도를 따라갈 수 없습니다. 독일어 동사는 절의 끝에 놓일 수 있고, 일본어는 동사를 맨 뒤에 둡니다. 어떤 번역기든 충실하게 옮기려면 절 전체가 필요합니다. 단어별로 번역하면 청취자는 절이 끝날 때에야 이해할 수 있는 조각들을 받게 됩니다. 독일어 통역사들은 소프트웨어가 이 문제에 도전하기 훨씬 전부터 동사를 기다려 왔습니다.
그래서 VocalStack은 세그먼트가 아니라 문장을 번역합니다. 문장 번역은 기본으로 켜져 있으며, 이 설정이 켜져 있으면 서버가 확정본들을 하나의 문장으로 묶어 문장 전체를 번역합니다. 문장이 열려 있는 동안 그 번역문은 임시이고, 문장이 닫히면 번역이 확정됩니다. 리더는 문장마다 항목 하나만 유지하고, 업데이트가 도착할 때마다 그 항목을 교체합니다.
음성은 더 오래 기다립니다. 닫힌 문장만 읽히는데, 아직 바뀌고 있는 문장은 수정될 때마다 다시 합성되어야 하기 때문입니다. 긴 문장은 조각으로 나누어 읽으므로, 나머지 조각을 만드는 동안 첫 조각을 재생할 수 있습니다.
문장 번역을 끄면 대신 확정본마다 자체 번역 프레임이 생깁니다. 이 방식은 아무것도 기다리지 않지만, 문장 단위 번역이 훨씬 더 읽기 좋습니다.
이 모든 대기 시간은 오디오가 VocalStack에 도착한 순간부터 측정됩니다. 많은 방송에서는 오디오가 도착할 때 이미 늦은 상태입니다.
소스가 마이크가 아니라 스트림이면, 전사가 시작되기 전에 이미 오디오가 뒤처져 있습니다. 스트림의 라이브 지점, 즉 스트림이 공개한 가장 최근 순간보다 뒤에 있는 것입니다.
대부분의 인터넷 라디오 방송이 공개하는 일반 HTTP 오디오 스트림은 보통 1~3초 뒤처집니다. 서버는 버스트 버퍼를 유지합니다. 최근 몇 초의 오디오를 한꺼번에 보내서, 새 청취자의 플레이어가 끊김 없이 바로 재생을 시작할 수 있게 하는 것입니다. 모든 청취자는, VocalStack도 포함해서, 그만큼 과거에서 시작합니다. HLS는 더 심합니다. HLS 재생목록은 클라이언트를 라이브 지점에서 세그먼트 3개만큼 뒤에서 시작하게 하므로, 세그먼트 길이에 따라 실제로는 몇 초에서 30초 가까이 뒤처집니다. 표준 DASH도 보통 HLS와 비슷한 범위에 들고, 저지연 변형만 그보다 훨씬 짧습니다. 방송사의 "라이브" 스트림은 신문 기사가 "최신 소식"인 정도로만 라이브일 수 있습니다.
이 수치는 대략적이며, 전사가 아니라 스트림에 속합니다. VocalStack 쪽의 어떤 설정으로도 이 시간을 되찾을 수 없습니다. 이 몇 초가 행사에 중요하다면, 공개 스트림 대신 마이크나 인코더에서 오디오를 스테이지로 넣으세요. 스트림 지연은 VocalStack이 단어를 듣기 전에 이미 정해지며, 실제로 움직일 수 있는 것은 지연 시간 모드뿐입니다.
지연 시간 모드는 한 가지 일을 합니다. 지연과 정확도 사이의 균형을 정합니다. 이 설정은 실시간 전사를 만들 때 Advanced 아래에 있고, 실행 중에는 Speed 탭에 있습니다. 거기서 칩에는 AUTO, SPEED 또는 ACCURACY가 표시됩니다(Fast는 SPEED로 나타납니다). API에서는 session.update로 스트림 중간에 모드를 바꿀 수 있습니다.
모드 사이의 거래는 이름이 말해 주는 그대로입니다. Fast는 텍스트를 더 빨리 내보내지만 더 많이 수정하고, Accuracy는 조금 더 걸리는 대신 수정을 적게 합니다. 번역 자막을 읽는 좌석의 관객은 1초 더 걸리는 것을 거의 알아채지 못하지만, 단어가 계속 바뀌는 것은 알아챕니다. 그래서 지연 차트가 평평하게 유지되는 한, Accuracy가 종종 더 나은 설정입니다. Auto는 자신이 무엇을 하는지 드러냅니다. 격차를 메우려고 속도를 올린 줄에는 호스트의 전사본에 FAST MODE 배지가 붙고, 그 줄의 정확도가 더 낮을 수 있다는 안내가 함께 표시됩니다.
모드가 무엇이든, 첫 단어 전에 전사가 준비되어 있어야 합니다. 그 준비 과정이 이 사슬이 한 번만 치르는 유일한 지연입니다.
일부 요금제에서는 실시간 전사가 시작되는 데 몇 초가 걸립니다. 시간은 요금제마다 다릅니다. 요금제 페이지의 Start-up speed 행을 보면, 종량제는 최대 15초의 콜드 스타트부터 Enterprise는 항상 준비된 상태까지 나와 있습니다.
API에서는 이 대기가 세션이 시작되는 동안 session.loading 프레임으로 나타나고, 그다음 session.ready가 옵니다. 클라이언트는 그 이후에만 오디오를 보냅니다. 그 사이 링크를 여는 청취자에게는 "라이브. 첫 줄이 곧 나타납니다."라는 문구가 보입니다. 전사가 한번 실행되면 이 지연은 지나간 일이며, 남은 질문은 이제 남아 있는 지연 중 얼마나 많은 몫을 감당할 것인가 하나뿐입니다.
실시간 전사가 실행되는 동안, 호스트의 Speed 탭에는 이 모든 것이 합쳐진 결과가 표시됩니다. 발화자와 텍스트 사이의 현재 간격과 옆의 모드 칩, 그리고 녹화 전체에 걸친 간격 차트와 평균 및 최댓값이 나옵니다. 전사본에서는 청취자에게 늦게 도착한 줄에 발화 시점부터 도착 시점까지 몇 초가 걸렸는지 알려 주는 배지가 붙습니다.
차트가 낮고 평평하게 유지되면 그 모드가 오디오에 맞는 것입니다. 차트가 올라가면 파이프라인이 뒤처지고 있는 것입니다. Accuracy 모드에서 이런 상황이 보인다면, 격차가 줄어들 때까지 정확도 일부를 속도와 맞바꾸는 Auto로 옮길 때일 수 있습니다.
개발자는 대신 숫자 하나를 받습니다. 실시간 세션이 끝나면 session.done에 stats.realtimeFactor가 담겨 옵니다. 이 값은 전사한 오디오 길이를 그것을 전사하는 데 쓴 시간으로 나눈 것입니다. 한 가지 규약에 주의하세요. 음성 인식 문헌에서 실시간 계수(real-time factor)는 보통 그 역수, 즉 처리 시간을 오디오 시간으로 나눈 값을 뜻하며, 낮을수록 좋습니다. VocalStack은 반대로 보고하므로 여기서는 높을수록 좋습니다. 실시간 세션은 1 근처에 있고, 1보다 낮다는 것은 파이프라인이 전사할 수 있는 속도보다 오디오가 더 빨리 들어왔다는 뜻입니다.
이 모든 초는 신비로울 것이 없습니다. 일부는 스트림의 몫이고, 일부는 다음 단어를 기다리는 단어의 몫이며, 일부는 번역에 필요한 문장의 몫이고, 나머지는 여러분이 고른 지연 시간 모드의 몫입니다. 프레임 단위의 자세한 내용은 API 레퍼런스에 있으며, 홈페이지의 데모에서 이 사슬이 실제로 돌아가는 모습을 볼 수 있습니다.