Python 141줄로 만드는 전화 통화용 실시간 AI 번역 브릿지
요약
Telnyx의 Voice Call Control과 AI Inference API만을 사용하여 단 141줄의 Python 코드로 구현한 실시간 전화 통화 번역 브릿지 기술을 소개합니다. 별도의 외부 번역 API 없이 서버 측에서 음성 인식, 번역, TTS 과정을 통합하여 구현하는 아키텍처를 다룹니다.
핵심 포인트
- Telnyx API를 활용한 서버 측 실시간 음성 번역 구현
- Flask와 인메모리 딕셔너리를 이용한 단순하고 효율적인 아키텍처
- BCP-47 언어 코드를 활용한 STT/TTS 정확도 개선 방법
- 별도의 앱 설치 없이 전화 통화만으로 작동하는 사용자 경험
서로 다른 언어를 사용하는 두 통화자를 동일한 전화 통화에 연결하세요. 각 통화자는 자신의 언어로 말하고 상대방의 말을 자신의 언어로 듣습니다. 통역사 없이 실시간으로 동일한 통화 내에서 이루어집니다.
Google Translate, AWS Translate, DeepL, 또는 기타 제3자 번역 API를 사용하지 않습니다. 오직 Telnyx Voice Call Control (전화 통화용)과 Telnyx AI Inference (번역용)만 사용합니다. 동일한 API 키, 동일한 플랫폼, 동일한 결제 체계를 사용합니다.
단 141줄의 Python 코드입니다. 작동 방식은 다음과 같습니다.
기능 (What It Does)
두 개의 전화번호와 두 개의 언어를 POST 합니다:
curl -X POST http://localhost:5000/bridge \
-H "Content-Type: application/json" \
-d '{"number_a": "+13125550001", "lang_a": "English",
...
앱이 통화자 A에게 전화를 겁니다. A가 전화를 받으면 B에게 전화를 겁니다. B가 전화를 받으면 번역 브릿지가 활성화됩니다:
- 통화자 A가 영어로 말합니다.
- Telnyx가 음성을 텍스트로 변환 (transcribe) 하여 귀하의 웹훅 (webhook)으로 전송합니다.
- 귀하의 앱이 텍스트 변환 내용을 AI Inference로 보냅니다: "영어를 스페인어로 번역해줘"
- 번역된 텍스트는 TTS (Text-to-Speech)를 통해 스페인어로 통화자 B에게 전달됩니다.
- 통화자 B가 스페인어로 말하면 → 텍스트로 변환 → 영어로 번역 → 통화자 A에게 전달됩니다.
- 어느 한 쪽이 전화를 끊을 때까지 이 루프가 반복됩니다.
두 통화자 모두 동일한 전화 통화에 머무릅니다. 아무도 별도의 앱을 설치할 필요가 없습니다. 번역은 서버 측 (server-side)에서 투명하게 이루어집니다.
아키텍처 (The Architecture)
모든 것이 하나의 Flask 파일 안에 존재합니다. 데이터베이스, Redis, 메시지 큐 (message queue)가 필요 없습니다. 브릿지 상태는 모든 웹훅 이벤트 시 Telnyx의 client_state 필드에 전달되는 브릿지 ID를 키로 사용하는 인메모리 딕셔너리 (in-memory dict)에 저장됩니다.
POST /bridge → A에게 전화 → A가 받음 → B에게 전화 → B가 받음 → 브릿지 활성화
↓
A의 음성 수집 → 번역 → B에게 TTS 전달 → B의 음성 수집 → 번역 → A에게 TTS 전달 → 루프
...
모든 Telnyx 작업의 client_state 필드는 브릿지 ID와 해당 통화가 어느 쪽(a 또는 b)에 속하는지를 담고 있습니다. 웹훅이 발생하면 base64로 인코딩된 상태를 디코딩하여 브릿지를 조회함으로써, 현재 처리 중인 통화 단계가 정확히 무엇인지 알 수 있습니다. 별도의 세션 저장소 (session store) 없이도 통화 자체가 스스로를 설명하는 구조입니다.
언어 코드 버그 (The Language Code Bug)
기존 샘플은 스페인어의 경우를 포함하여 모든 TTS (Text-to-Speech) 및 음성 인식 (Speech Recognition)이 language_code="en-US"로 하드코딩되어 있었습니다. 통화는 "작동"했지만 (오디오가 흐르고 에러가 발생하지 않음), 번역은 무용지물이었습니다:
- en-US 설정의 스페인어 TTS: TTS 엔진이 스페인어 단어를 영어 음소 (phonemes)로 읽습니다. 알아들을 수 없습니다.
- en-US 설정의 스페인어 STT (Speech-to-Text): STT 엔진이 영어 소리를 기다립니다. 스페인어 음성 인식률이 급락합니다.
해결 방법은 언어 이름에서 BCP-47 코드로 매핑하는 것입니다:
LANG_CODES = {
"english": "en-US", "spanish": "es-US", "french": "fr-FR",
"german": "de-DE", "italian": "it-IT", "portuguese": "pt-BR",
...
이제 TTS는 대상 (target) 언어를 사용하고 (스페인어 텍스트 → es-US 발음), STT는 화자 (speaker) 의 언어를 사용합니다 (스페인어 음성 → es-US 인식).
번역 호출 (The Translation Call)
OpenAI와 호환되는 /v2/ai/chat/completions 엔드포인트인 Telnyx AI Inference를 사용합니다:
def translate(text, from_lang, to_lang):
resp = requests.post(INFERENCE_URL,
headers={"Authorization": f"Bearer {TELNYX_API_KEY}"},
...
결정론적인 (deterministic) 번역을 위해 Temperature는 0.1로 설정했습니다. 대화형 문구를 위해 최대 토큰(max tokens)은 200으로 설정했습니다. 모델은 기본적으로 moonshotai/Kimi-K2.6을 사용하지만, AI_MODEL 환경 변수를 통해 Telnyx 카탈로그에 있는 어떤 모델로든 교체할 수 있습니다.
별도의 번역 API 계정은 필요하지 않습니다. 전화 통화를 수행하는 것과 동일한 Telnyx API 키가 번역도 수행합니다.
웹훅 서명 검증 (Webhook Signature Verification)
Telnyx는 모든 웹훅 (webhook)에 Ed25519 키로 서명합니다. 앱은 이를 신뢰하기 전에 검증을 수행합니다:
@app.route("/webhooks/voice", methods=["POST"])
def handle_voice():
try:
...
이 과정이 없다면, 웹훅 URL을 아는 누구나 가짜 통화 이벤트를 주입할 수 있습니다. telnyx SDK의 webhooks.unwrap()이 Ed25519 검증을 처리합니다.
통화 루프 (The Call Loop)
각 Telnyx 이벤트는 다음 동작을 트리거합니다:
# 발화자 말하기 종료 → 전사(transcript) 확보
elif event_type == "call.gather.ended" and bridge:
speech = p.get("speech", {}).get("result", "")
...
한쪽 통화자가 전화를 끊으면 다른 쪽도 함께 끊깁니다. 한 명의 통화자만 있는 번역 브릿지는 의미가 없기 때문입니다:
elif event_type == "call.hangup" and bridge:
other_side = "b" if side == "a" else "a"
other_ccid = bridge.get("ccids", {}).get(other_side)
...
직접 시도해보기
git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/ai-real-time-translation-bridge-python
cp .env.example .env # TELNYX_API_KEY, TELNYX_PUBLIC_KEY, BRIDGE_NUMBER, CONNECTION_ID
...
그 다음:
ngrok http 5000
Telnyx Portal에서 Call Control Application의 webhook URL을 https://<id>.ngrok.io/webhooks/voice로 설정하세요.
브릿지를 실행합니다:
curl -X POST http://localhost:5000/bridge \
-H "Content-Type: application/json" \
-d '{"number_a": "+13125550001", "lang_a": "English",
...
두 대의 전화기로 전화를 거세요. 서로 다른 언어로 말해보세요. 실시간 번역을 들을 수 있습니다.
주요 링크:
- Repo: https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-real-time-translation-bridge-python
- Telnyx Portal: https://portal.telnyx.com
- Call Control 문서: https://developers.telnyx.com/docs/voice/call-control
- AI Inference 문서: https://developers.telnyx.com/docs/inference
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기