Skip to content

Repository files navigation

Voice Translation AI Server

FastAPI 기반의 음성 처리 서버입니다. 업로드한 음성을 STT로 텍스트화하고, 목표 언어로 번역한 뒤, 사용자 음성으로 TTS 결과를 생성합니다. 현재 구현은 endpoint에서 직접 비즈니스 로직을 처리하지 않고 endpoint -> runner -> LangGraph -> node -> service 계층으로 분리되어 있습니다.

Where To Look First

Features

  • POST /api/v1/voice/process 음성 업로드 후 STT -> 번역 -> 역번역 -> voice clone/reuse -> TTS -> 결과 저장
  • POST /api/v1/voice/text 등록된 voice_id를 사용해 입력 텍스트를 바로 음성으로 변환
  • POST /api/v1/voice/text/translate 입력 텍스트를 번역한 뒤 등록된 voice_id로 음성 생성
  • JWT Bearer 토큰 기반 사용자 인증
  • LangGraph 기반 workflow orchestration
  • /process 요청 fingerprint 캐시 재사용
  • 결과 메타데이터 및 오디오 파일 저장

Tech Stack

  • Python 3.12+
  • FastAPI
  • Uvicorn
  • Poetry
  • LangGraph
  • OpenAI API
  • ElevenLabs API
  • SQLite

Architecture

Client
  -> FastAPI Endpoint
  -> Runner
  -> LangGraph
  -> Graph Nodes
  -> Services
  -> OpenAI / ElevenLabs / SQLite / File System

역할 구분은 다음과 같습니다.

  • endpoint HTTP 요청 파싱, JWT 인증, 초기 state 구성, HTTP 응답 변환
  • runner graph lazy loading, workflow 실행, 공통 예외 처리, cleanup 보조
  • graph 노드 간 상태 전이와 분기 정의
  • service OpenAI, ElevenLabs, SQLite, 파일 시스템 같은 실제 작업 수행

API

Health Check

  • GET /health

응답 예시:

{
  "status": "ok",
  "service": "FastAPI AI Server"
}

Voice Process

  • POST /api/v1/voice/process
  • Authorization: Bearer <JWT>
  • Content-Type: multipart/form-data

폼 필드:

  • target_lang (string): 번역 대상 언어
  • domain (string, optional): 번역 도메인 힌트
  • glossary_json (string, optional): 용어집 JSON 배열 문자열
  • audio (file): 입력 음성 파일

처리 흐름:

  1. 업로드 파일을 uploads/에 임시 저장합니다.
  2. 요청 내용으로 fingerprint를 계산해 이전 처리 결과가 있으면 재사용합니다.
  3. 필요한 경우 WebM을 WAV로 변환합니다.
  4. STT로 원문 텍스트와 감지 언어를 추출합니다.
  5. 목표 언어로 번역하고 역번역으로 품질 확인용 텍스트를 만듭니다.
  6. 사용자 voice_id를 조회하고, 없으면 음성 클로닝을 수행합니다.
  7. TTS 결과를 생성하고 결과 리소스를 저장합니다.
  8. JSON 메타데이터를 반환합니다.

응답 예시:

{
  "requestId": "12345678",
  "voiceId": "voice-abc",
  "detectedSourceLanguage": "ko",
  "sourceText": "안녕하세요",
  "translatedText": "Hello",
  "backTranslatedText": "안녕하세요",
  "audio": {
    "url": "/internal/results/12345678/audio",
    "mimeType": "audio/mpeg"
  }
}

특징:

  • 동일한 사용자와 동일한 입력 오디오/옵션 조합이면 캐시된 결과를 재사용할 수 있습니다.
  • stale voice_id가 감지되면 /process 경로에서는 voice를 재생성한 뒤 TTS를 재시도할 수 있습니다.

Stored Audio Fetch

  • GET /internal/results/{requestId}/audio
  • Authorization: Bearer <JWT>

동작:

  • 저장된 결과 메타데이터를 조회합니다.
  • 요청 사용자와 결과 생성 사용자가 같은지 검사합니다.
  • 권한이 맞으면 저장된 audio.mp3를 반환합니다.

Text To My Voice

  • POST /api/v1/voice/text
  • Authorization: Bearer <JWT>
  • Content-Type: application/json

요청 바디:

{
  "text": "원하는 문장을 입력하세요."
}

동작:

  1. JWT의 사용자 ID로 저장된 voice_id를 조회합니다.
  2. voice가 있으면 ElevenLabs TTS를 생성하고 audio/mpeg 응답으로 반환합니다.
  3. voice가 없거나 stale voice면 409를 반환하고 /process 재등록을 유도합니다.

응답 헤더:

  • X-Voice-ID

Text Translate To My Voice

  • POST /api/v1/voice/text/translate
  • Authorization: Bearer <JWT>
  • Content-Type: application/json

요청 바디 예시:

{
  "text": "안녕하세요",
  "target_lang": "English",
  "domain": "casual conversation",
  "glossary": [
    {
      "source": "보이스 트윈",
      "target": "VoiceTwin"
    }
  ]
}

동작:

  1. 기존 voice_id가 있는지 확인합니다.
  2. 입력 텍스트를 번역하고 역번역을 수행합니다.
  3. 번역 결과를 사용자의 voice로 TTS 생성합니다.
  4. 결과를 audio/mpeg로 바로 반환합니다.

특징:

  • 이 경로는 입력 음성이 없기 때문에 stale voice_id가 감지되면 voice를 재생성하지 않습니다.
  • stale voice면 저장된 voice_id를 지우고 409 응답으로 다시 /process 등록을 유도합니다.

응답 헤더:

  • X-Voice-ID

Workflow Notes

/process

initialize
  -> detect audio format
  -> convert if needed
  -> transcribe
  -> translate
  -> back translate
  -> resolve voice
  -> clone if needed
  -> synthesize speech
  -> recreate stale voice if needed
  -> finalize
  -> cleanup

/text/translate

initialize
  -> require existing voice
  -> translate
  -> back translate
  -> synthesize speech
  -> clear stale voice or finalize

Result Storage

  • 업로드 임시 파일: uploads/
  • voice 매핑 DB: data/voice_map.db
  • 처리 결과 디렉터리: internal_results/<request_id>/
  • 저장 오디오: internal_results/<request_id>/audio.mp3
  • 저장 메타데이터: internal_results/<request_id>/metadata.json
  • /process 캐시 인덱스 DB: internal_results/process_cache.db

process_cache.db는 fingerprint와 request_id를 연결해서 동일 요청 재실행을 줄이는 용도입니다.

Project Structure

app/
  main.py
  api/v1/endpoints/voice_translation.py
  core/
    config.py
    security.py
  graphs/
    runner.py
    voice_process_graph.py
    text_translate_graph.py
    nodes.py
    routing.py
    state.py
    errors.py
  services/
    audio_service.py
    stt_service.py
    translation_service.py
    voice_service.py
    voice_store.py
    result_service.py
tests/
  api/
    test_voice_process_endpoint.py
  core/
    test_security_and_app.py
  graphs/
    test_graph_nodes.py
  services/
    test_stt_service.py

Docs

Setup

1) Install dependencies

poetry install

2) Create environment file

.env 파일에 아래 값을 설정하세요.

OPENAI_API_KEY=your_openai_api_key
ELEVENLABS_API_KEY=your_elevenlabs_api_key
JWT_SECRET_KEY=your_jwt_secret_key
JWT_ALGORITHMS=HS256,HS512
JWT_SECRET_IS_BASE64=false
RESULTS_DIR=internal_results
VOICE_DB_PATH=data/voice_map.db

3) Run server

poetry run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

Notes

  • JWT secret은 토큰 발급 서버와 동일해야 합니다.
  • CORS 허용 origin은 현재 http://localhost:5173, https://voicetwin-front.vercel.app 입니다.
  • uploads/, internal_results/, data/ 디렉터리는 서버 시작 시 자동 생성됩니다.
  • uploads/는 임시 업로드 작업용이며 외부 정적 경로로 공개하지 않습니다.
  • legacy uploads/user_voice_map.json이 있으면 SQLite voice store로 마이그레이션됩니다.
  • 이 저장소에서는 문서 원본 .md는 추적하고, 산출 이미지 같은 문서 부속 파일은 기본적으로 Git에서 제외하도록 설정되어 있습니다.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages