광고 자리 모집 중 · 제휴 문의

Listnr TTS API를 활용한 음성 스트리밍 및 커스텀 음성 파라미터 설정 가이드

365Finds Editorial
Wiki 문서 11,430편 수록

내 AI에서 365 Wiki 사용하기

아래 프롬프트를 복사해 평소 사용하는 AI에 붙여넣고 바로 질문하세요.

전체 Skill 다운로드

먼저 프롬프트로 체험해 보세요. 365 Wiki를 자주 쓴다면 전체 365Wiki Skill을 설치해 매번 붙여넣는 수고를 줄일 수 있습니다. 평소 쓰는 AI가 없다면 Gemini나 Microsoft Copilot 웹 버전도 사용할 수 있습니다.

현대 웹 애플리케이션에서 실시간 텍스트 음성 변환(TTS: Text-to-Speech)을 구축할 때 가장 중요한 과제는 초기 재생 지연 시간(TTFB) 단축, 음성의 자연스러운 억양, 그리고 API 인증 키의 보안을 동시에 확보하는 것입니다. Listnr는 개발자를 위해 두 가지 형태의 API를 제공합니다. 하나는 Microsoft Azure, Google Cloud, AWS Polly, IBM Watson의 음성 라이브러리를 단일 규격으로 통합한 표준 V1 REST API이며, 다른 하나는 Ultra Premium 보이스 및 음성 복제(Cloned Voices)를 위한 저지연 V2 스트리밍 엔드포인트 /stream-voice입니다.

웹 프론트엔드에서 보안 키를 노출하지 않고 저지연 음성 합성을 구현하는 표준 아키텍처는 백엔드 프록시를 배치하는 것입니다. 백엔드에서 인증 토큰을 추가해 Listnr 스트리밍 엔드포인트를 호출하고 세부 파라미터를 조율한 뒤, 반환되는 바이너리 오디오 청크를 브라우저로 직접 파이프(pipe) 전송합니다.

sequenceDiagram
    autonumber
    actor User as 브라우저(클라이언트)
    participant Server as 백엔드 프록시 서버
    participant Listnr as Listnr V2 스트리밍 API
    
    User->>Server: POST /api/tts (텍스트, voiceId, 음성 설정)
    Note over Server: x-listnr-token 안전한 주입
    Server->>Listnr: POST /api/v2/stream-voice
    Listnr-->>Server: 청크 분할 바이너리 오디오 스트림 (WAV / MP3)
    Server-->>User: 파이프 스트리밍 전송 (Transfer-Encoding: chunked)
    Note over User: Web Audio API / HTML5 Audio로 즉시 버퍼 재생

1. 인증 체계와 보안 아키텍처 원칙

웹 브라우저의 클라이언트 측 스크립트에 상용 Listnr API 키를 직접 포함해서는 안 됩니다. Listnr는 전용 요청 헤더(x-listnr-token)를 통해 호출을 인증하며, 이 키는 개발자 계정의 글자 수 크레딧 및 결제 플랜과 직접 연동됩니다. 클라이언트 코드에 키가 노출될 경우 무단 사용으로 인한 크레딧 소진 및 과금 피해가 발생할 수 있습니다.

자격 증명 보호와 백엔드 프록시 구조

권장되는 운영 패턴은 브라우저와 Listnr 인프라 사이에 가벼운 백엔드 중계 계층(Next.js API Routes, Express, Fastify 또는 FastAPI)을 구축하는 것입니다.

API 컴포넌트기본 호스트 / 엔드포인트핵심 역할보안 및 호출 요건
V2 스트리밍 APIhttps://cloning.listnr.tech/api/v2/stream-voiceUltra Premium 및 복제 음성의 저지연 바이너리 청크 스트리밍서버 측 전용 호출; x-listnr-token 필수
V2 음성 목록 조회https://cloning.listnr.tech/api/v2/available-voices사용 가능한 기본 음성 및 계정 내 복제 음성 모델 식별자 반환서버 메모리 캐싱 후 프론트엔드 선택용 제공
V1 멀티 프로바이더 RESThttps://bff.listnr.tech/api/tts/v1/convert-textAzure, Google, AWS 등 복수 벤더 음성의 일괄 파일 합성배치 작업에 적합; 표준 SSML 루트 태그 지원

2. 음성 모델 탐색: Voice ID 확보

음성 합성을 요청하기 전, 애플리케이션은 유효한 음성 모델 식별자(voice_id)를 확보해야 합니다. 서버 초기화 시점에 음성 목록 엔드포인트를 호출하여 결과를 Redis나 메모리에 캐싱해 두는 방식이 효율적입니다.

# 계정에서 사용 가능한 기본 음성 및 복제 음성 목록 조회
curl -X GET "https://cloning.listnr.tech/api/v2/available-voices" \
  -H "x-listnr-token: YOUR_LISTNR_API_KEY" \
  -H "Accept: application/json"

응답으로 반환되는 배열에는 고유 영숫자 ID(예: 21m00Tcm4TlvDq8ikWAM)가 포함되어 있습니다. 프론트엔드가 선택한 ID를 백엔드로 전달하면 원하는 음향 모델로 합성이 진행됩니다.


3. 오디오 스트리밍 합성 및 세부 파라미터 튜닝

Listnr V2 스트리밍 엔드포인트는 변환할 텍스트 문자열, 음성 모델 ID, 그리고 발화 특성을 세밀하게 조율하는 settings 객체를 포함한 JSON 요청을 수신합니다.

{
  "voice_id": "21m00Tcm4TlvDq8ikWAM",
  "text": "시스템 경고: 데이터베이스 복제 지연이 발생했습니다.<break time=\"0.4s\"/><break strength=\"strong\"/>대체 전환 프로토콜을 가동합니다.",
  "settings": {
    "stability": 0.71,
    "similarity_boost": 0.50,
    "style": 0.05,
    "use_speaker_boost": false
  }
}

파라미터 세부 조율 가이드

각 파라미터가 음성 합성에 미치는 영향을 정확히 이해하면 음질 왜곡 없이 이상적인 발화를 얻을 수 있습니다:

SSML 일시 정지 및 호흡 조절 태그

V2 /stream-voice 파이프라인에서는 번거로운 <speak> 루트 태그를 작성하지 않고도 텍스트 내에 SSML break 태그를 직접 삽입할 수 있습니다:


4. 웹 애플리케이션 엔드투엔드 구현 코드

다음 코드는 Node.js/Express 기반의 백엔드 스트리밍 프록시와 브라우저 환경에서 스트림을 전달받아 즉각 재생하는 프론트엔드 예제입니다.

백엔드 스트리밍 중계 서버 (server.js)

import express from 'express';
import fetch from 'node-fetch';

const app = express();
app.use(express.json());

const LISTNR_API_KEY = process.env.LISTNR_API_KEY;
const STREAM_URL = 'https://cloning.listnr.tech/api/v2/stream-voice';

app.post('/api/tts/stream', async (req, res) => {
  try {
    const { text, voiceId, settings } = req.body;

    if (!text || !voiceId) {
      return res.status(400).json({ error: 'text 또는 voiceId 파라미터가 누락되었습니다.' });
    }

    const payload = {
      voice_id: voiceId,
      text: text,
      settings: {
        stability: settings?.stability ?? 0.71,
        similarity_boost: settings?.similarity_boost ?? 0.50,
        style: settings?.style ?? 0.0,
        use_speaker_boost: settings?.use_speaker_boost ?? false
      }
    };

    const upstreamResponse = await fetch(STREAM_URL, {
      method: 'POST',
      headers: {
        'x-listnr-token': LISTNR_API_KEY,
        'Content-Type': 'application/json',
        'Accept': '*/*'
      },
      body: JSON.stringify(payload)
    });

    if (!upstreamResponse.ok) {
      const errorText = await upstreamResponse.text();
      return res.status(upstreamResponse.status).json({
        error: `Listnr API 오류: ${upstreamResponse.statusText}`,
        details: errorText
      });
    }

    // 스트리밍을 위한 청크 전송 헤더 구성
    res.setHeader('Content-Type', 'audio/wav');
    res.setHeader('Transfer-Encoding', 'chunked');

    // 상위 API의 응답 스트림을 브라우저 응답으로 직접 파이프 연결
    upstreamResponse.body.pipe(res);
  } catch (err) {
    console.error('TTS 스트리밍 처리 실패:', err);
    res.status(500).json({ error: '서버 내부 중계 오류가 발생했습니다.' });
  }
});

app.listen(3000, () => console.log('오디오 프록시 서버 실행 중 (포트 3000)'));

프론트엔드 오디오 수신 및 재생 (client.js)

/**
 * 백엔드로부터 오디오 스트림을 수신하여 즉시 재생
 */
async function streamAndPlayAudio(text, voiceId) {
  const response = await fetch('/api/tts/stream', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      text: text,
      voiceId: voiceId,
      settings: {
        stability: 0.65,
        similarity_boost: 0.60,
        style: 0.0
      }
    })
  });

  if (!response.ok) {
    throw new Error(`오디오 요청 실패: ${response.status}`);
  }

  // 스트림 바이너리를 Blob으로 변환한 후 HTML5 Audio로 재생
  const audioBlob = await response.blob();
  const audioUrl = URL.createObjectURL(audioBlob);
  const audio = new Audio(audioUrl);
  
  audio.onended = () => URL.revokeObjectURL(audioUrl);
  await audio.play();
}

5. 프로덕션 운영을 위한 아키텍처 고려사항

실제 서비스에 Listnr TTS를 적용할 때 검토해야 할 기술적 트레이드오프는 다음과 같습니다:

  1. V1 REST와 V2 스트리밍의 선택 기준: 기존 클라우드 음성(Azure Neural 등)이 필요하거나 자막 싱크를 위해 단어 단위 타임스탬프가 필수적인 경우에는 V1을 채택합니다. 사람과 대화하듯 반응성이 중요한 대화형 인터페이스에는 V2 스트리밍이 적합합니다.
  2. 크레딧 보호 및 디바운싱(Debounce): 모든 텍스트 변환마다 계정 크레딧이 차감되므로, 사용자 입력에 반응하는 UI에서는 디바운스를 적용하고 재입력 발생 시 AbortController를 통해 이전 요청을 취소해야 합니다.
  3. 정적 음성 에셋의 엣지 캐싱: 시스템 고정 안내 멘트나 정형화된 알림은 서버에서 1회 생성한 뒤 AWS S3 등 오브젝트 스토리지에 저장하고 CDN을 통해 캐시 배포합니다. 고비용의 실시간 스트리밍 호출은 동적 생성 텍스트에 한해 집중시키는 것이 비용 최적화의 핵심입니다.

참고 자료