Translation pending

이 페이지의 번역은 아직 제공되지 않습니다. 아래 내용은 영어입니다 — 참조: 영어 버전.

Speech Server

Apple 네이티브 런타임 · PocketTTS

PocketTTS는 speech-swift에 네이티브 CoreML 음성 합성을 추가합니다. 모든 단계는 기본적으로 CPU만 사용합니다. 영어 Alba 프리셋은 24 kHz에서 프레임당 1,920개 샘플(80밀리초)을 스트리밍합니다.

Swift 및 CLI 사용법

pocket-tts와 alba 음성을 사용하세요. HTTP 스트리밍은 PCM이 필요하고 WebSocket은 오디오 델타를 전송합니다. 기존 기본 모델은 유지됩니다.

curl http://localhost:8080/v1/audio/speech \
  -H 'Content-Type: application/json' \
  -d '{"model":"pocket-tts","voice":"alba","input":"Hello world.","response_format":"pcm","stream":true}' \
  -o hello.pcm

speech-server is a local HTTP + WebSocket server that exposes every Soniqo model through a simple REST API, plus an OpenAI Realtime API-compatible WebSocket at /v1/realtime. It ships in the same Homebrew bottle as the speech CLI — brew install speech drops both on your PATH.

Install and run

brew install speech

speech-server --port 8080
# Starting server on http://127.0.0.1:8080
# Endpoints:
#   POST /transcribe  - Speech-to-text (WAV body or JSON with audio_base64)
#   POST /speak       - Text-to-speech (JSON: {text, engine?, language?})
#   POST /respond     - Speech-to-speech (WAV body, voice/max_steps via query)
#   POST /enhance     - Speech enhancement (WAV body)
#   GET  /health      - Health check
#   WS   /v1/realtime - OpenAI Realtime API (JSON events, base64 PCM16 audio)

Command-line flags

FlagDefaultDescription
--host127.0.0.1Bind address. Change to 0.0.0.0 to expose on LAN.
--port8080TCP port.
--preloadoffLoad all models eagerly at startup. Slower boot (~30–60 s) but zero first-request latency.

Models are downloaded on first use and cached in ~/Library/Caches/qwen3-speech/. The first request for a given model pays the download + load cost (30 s – 2 min depending on model size); subsequent requests are warm.

REST endpoints

POST /transcribe — Speech-to-text

Accepts either a raw WAV body or a JSON envelope with base64-encoded audio.

# WAV body (preferred — lower overhead)
curl -X POST http://127.0.0.1:8080/transcribe \
  -H "Content-Type: audio/wav" \
  --data-binary @recording.wav

# JSON with base64
curl -X POST http://127.0.0.1:8080/transcribe \
  -H "Content-Type: application/json" \
  -d '{"audio_base64":"'"$(base64 -i recording.wav)"'","language":"en"}'

Response: {"text": "…", "language": "en", "confidence": 0.93}.

POST /speak — Text-to-speech

curl -X POST http://127.0.0.1:8080/speak \
  -H "Content-Type: application/json" \
  -d '{"text":"Hello, world!","engine":"kokoro","language":"en"}' \
  --output hello.wav

Response body is a WAV blob. Supported engine values: qwen3 (default), cosyvoice, kokoro.

POST /respond — Speech-to-speech

curl -X POST "http://127.0.0.1:8080/respond?voice=en_female_calm&max_steps=256" \
  -H "Content-Type: audio/wav" \
  --data-binary @question.wav \
  --output answer.wav

Runs PersonaPlex 7B — speech in, speech out. Transcript is returned as an X-Response-Text header. See PersonaPlex guide for voice preset names.

POST /enhance — Speech enhancement

curl -X POST http://127.0.0.1:8080/enhance \
  -H "Content-Type: audio/wav" \
  --data-binary @noisy.wav \
  --output clean.wav

DeepFilterNet3 at 48 kHz. Input is resampled if needed.

GET /health — Liveness probe

curl http://127.0.0.1:8080/health
# {"status":"ok"}

HTTP 및 실시간 WebSocket 테스트는 최대 10초 동안 /health가 HTTP 200과 {"status":"ok"}를 반환할 때까지 기다립니다. 시작 오류가 발생하면 테스트 설정이 실패하며, 정리 단계에서는 서버 종료를 기다린 뒤 포트를 다시 사용합니다.

WebSocket: /v1/realtime

Drop-in compatible with the OpenAI Realtime API — the same JSON event schema (session.update, input_audio_buffer.append, response.create, response.audio.delta, …) with base64-encoded PCM16 audio at 24 kHz. Clients written against OpenAI's Realtime SDK work against speech-server without code changes (just switch the WebSocket URL).

서버 VAD를 사용한 자동 발화 구간

수동 input_audio_buffer.commit이 기본값으로 유지됩니다. session.turn_detection을 server_vad로 설정하면 서버에서 Silero VAD를 실행하여 완료된 각 발화 구간을 자동으로 전사합니다. 접두 오디오가 보존되고 유휴 버퍼는 제한되며 speech_started, speech_stopped, committed 이벤트가 순서대로 전송됩니다. 계속 활성 상태인 구간은 설정된 최대 시간에 강제로 종료됩니다.

ws.send(JSON.stringify({
  type: "session.update",
  session: {
    turn_detection: {
      type: "server_vad",
      threshold: 0.5,
      prefix_padding_ms: 300,
      silence_duration_ms: 500,
      max_turn_duration_ms: 120000
    }
  }
}));

JavaScript example

const ws = new WebSocket("ws://127.0.0.1:8080/v1/realtime");

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: "session.update",
    session: { modalities: ["audio", "text"] }
  }));

  // Stream PCM16 mono 24kHz audio from the mic:
  const audioBase64 = await capturePCM16Chunk();
  ws.send(JSON.stringify({
    type: "input_audio_buffer.append",
    audio: audioBase64
  }));

  ws.send(JSON.stringify({ type: "response.create" }));
};

ws.onmessage = ev => {
  const msg = JSON.parse(ev.data);
  if (msg.type === "response.audio.delta") {
    playPCM16Base64(msg.delta);
  }
};

Python example

import asyncio, base64, json, wave, websockets

async def main():
    async with websockets.connect("ws://127.0.0.1:8080/v1/realtime") as ws:
        await ws.send(json.dumps({"type": "session.update",
                                  "session": {"modalities": ["audio", "text"]}}))

        with wave.open("question.wav", "rb") as wav:
            pcm16 = wav.readframes(wav.getnframes())
        await ws.send(json.dumps({"type": "input_audio_buffer.append",
                                  "audio": base64.b64encode(pcm16).decode()}))
        await ws.send(json.dumps({"type": "response.create"}))

        async for raw in ws:
            msg = json.loads(raw)
            if msg["type"] == "response.audio.delta":
                open("answer.pcm", "ab").write(base64.b64decode(msg["delta"]))
            elif msg["type"] == "response.done":
                break

asyncio.run(main())

Deployment notes

Source

선택적 모델 관리

SpeechRuntime은 공유 로딩, 취소 가능한 FIFO 진입 제어, 직렬 실행을 제공합니다. Qwen3ASRRuntime은 명시적 설명자로 MLX 또는 전체 CoreML을 선택하며 기존 API와 CLI 플래그도 계속 사용할 수 있습니다.

서버는 스트리밍 출력을 포함한 전체 요청 동안 실행 허가를 유지하며 최대 32개 요청을 대기시킵니다. ASR 실패는 HTTP 오류 또는 WebSocket 오류 이벤트로 전달되고 유효한 빈 전사는 성공으로 처리됩니다. 재생은 넘치는 샘플을 보관합니다. 캐시된 모델과 재생 대기 오디오는 메모리를 차지합니다.

Voxtral TTS

Voxtral 4B TTS 2603은 VoxtralTTS 모듈로 Apple Silicon에서 로컬 실행되며, 프리셋 음성 20개, 언어 9개, 24 kHz 모노 음성을 지원합니다.

curl http://localhost:8080/v1/audio/speech \
  -H 'Content-Type: application/json' \
  -d '{"model":"voxtral-tts","input":"Hello, welcome to Voxtral.","voice":"casual_male","response_format":"wav"}' \
  -o hello.wav

사전 설정 음성만 지원하며 참조 오디오 복제는 지원하지 않습니다. SDK, CLI, WebSocket 및 HTTP PCM에서 생성 중인 오디오를 출력합니다. 입력 텍스트는 처음에 전체를 제공해야 합니다. 모델 가중치는 CC BY-NC 4.0 라이선스를 사용합니다.

Voxtral TTS 가이드 읽기