Traducere automată · Originalul în engleză
Speech Server
Nativ Apple runtime · PocketTTS
PocketTTS adaugă sinteze native CoreML sinteze de vorbire la speech-swift. Toate etapele sunt implicite pentru executarea exclusivă a procesorului. Fluxurile de prefixe engleze Alba sunt 1,920-frame de probe la 24 kHz (80 ms per cadru).
Utilizați buzunare cu alba voce. Streaming HTTP necesită PCM; WebSocket emite delta audio. Modelele implicite existente sunt neschimbate.
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.pcmspeech-server este un server local HTTP + WebSocket care expune fiecare model Soniqo printr-un simplu REST API, plus un OpenAI API compatibil în timp real WebSocket la /v1/realtime. Acesta nave în aceeași sticlă Homebrew ca speech CLI ? brew install speech Picături pe ambele dvs. PATH.
Instalați și executați
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)
Indicatoare linia de comandă
| Steag | Implicit | Descriere |
|---|---|---|
--host | 127.0.0.1 | Adresa obligatorie. Modificarea la 0.0.0.0 pentru expunerea la LAN. |
--port | 8080 | Port TCP. |
--preload | off | Încărcați toate modelele cu nerăbdare la pornire. Boot mai lent (~30 bază 60 s) dar zero prima cerere latență. |
Modelele sunt descărcate la prima utilizare și cached în ~/Library/Caches/qwen3-speech/. Prima cerere pentru un anumit model plătește costul de descărcare + sarcina (30 s 2 min în funcție de dimensiunea modelului); cererile ulterioare sunt calde.
REST obiective
POST /transcribe
Acceptă fie un corp WAV brut, fie un plic JSON cu audio base64-encoded.
# 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"}'
Răspuns: {"text": "…", "language": "en", "confidence": 0.93}.
POST /speak
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
Organismul de răspuns este un bloc WAV . Suportat engine valori: qwen3 (default), cosyvoice, kokoro.
POST /respond
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 bază de vorbire în, speech out. Transcript este returnat ca un X-Response-Text antet. A se vedea PersonaPlex pentru numele presetate voce.
POST /enhance
curl -X POST http://127.0.0.1:8080/enhance \
-H "Content-Type: audio/wav" \
--data-binary @noisy.wav \
--output clean.wav
DeepFilterNet3 la 48 kHz. Intrarea se reinclude dacă este necesar.
GET /health
curl http://127.0.0.1:8080/health
# {"status":"ok"}
HTTP și testele în timp real WebSocket așteaptă /health pentru a returna HTTP 200 cu {"status":"ok"}, cu un termen de pornire de 10 secunde. Erorile de pornire nu reușesc configurarea testului, iar ruperea așteaptă închiderea serverului înainte de reutilizarea portului său.
WebSocket: /v1/realtime
Drop-in compatibil cu OpenAI Realtime API Aceeași schemă de evenimente JSON (session.update, input_audio_buffer.append, response.create, response.audio.delta, ...) cu base64-encoded PCM16 audio la 24 kHz. Clientii contra OpenAI's RealTime SDK Împotriva speech-server fără modificări de cod (doar comutați URL-ul WebSocket).
Rânduri automate cu server VAD
Manual input_audio_buffer.commit rămâne implicit. Set session.turn_detection to server_vad to run Silero VAD on the server and automatly transcribe each completed speech turn. Prefix audio is reţinuted, light tamponing stays delimited, and a continuely active turn is force-closed at the configurated maximum.
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
}
}
}));
// Event order for each detected turn:
// input_audio_buffer.speech_started
// input_audio_buffer.speech_stopped
// input_audio_buffer.committed
// conversation.item.input_audio_transcription.completed
// Set turn_detection to null (or { type: "none" }) for manual commits.
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())
Note privind desfășurarea activității
- Nici un aut în mod implicit.
speech-serverse leagă127.0.0.1și are încredere în fiecare apelant. Pune-l în spatele unui proxy inversat (Caddy, nginx, tailscale) dacă îl expuneți dincolo de localhost. - Modelele sunt încărcate cu lene. Prima cerere pentru
/transcribedeclanşează ASR descărcare + sarcină (~700 MB, 30 de60 s). Utilizaţi--preloadpentru pornirea la rece, dar mai lentă. - Nici o transcriere de streaming încă.
POST /transcribese așteaptă ca WAV complet în față./v1/realtimepentru streaming. - Systemd / launched. Niciun serviciu de nave astăzi. Un simplu
nohup speech-server &sau supervizorul de proces obișnuit funcționează.
Sursă
- Surse/AudioServer اHummingbird-based HTTP router, leneș model registry,
/v1/realtimeWebSocket Handler. - Surse/AudioServerCLI ا
@mainpunct de intrare, argument parser. - Upstream: OpenAI Realtime API reference.
Inference locală nativă
Pentru 12B, markerii de închidere a apelului de instrument adiacenti repetati imediat dupa un apel complet, validat sunt consumati cu acel apel. Ei nu creeaza un alt apel sau isi schimba argumentele. Markerii si argumentele malformate raman erori; E4B retine manipularea stricta.
Pentru a păstra cereri de chat native eșuate, set failureCaptureDirectory în manifestul de inferență. Capture este oprit în mod implicit. Directorul trebuie să refuze grupul și alte acces; noi directoare folosesc 0700 și utilizarea de fișiere de eșec 0600. Fișierele includ organismul de cerere exactă, ID-ul cererii și eroarea. Generațiile de 12B finalizate păstrează, de asemenea, prompte, ID-uri token, producția brută și motiv de oprire înainte de parsare. E4B eșecurile nu au înregistrări de generație brută. Aceste fișiere locale conțin conținut conversație și instrumente; erorile HTTP și cererile de succes nu le includ.
Agent opţionalDirector încarcă o etapă Gemma 4 12B Unificat INT4 model text alături E4B. Utilizați modelul: "gemma4-12b-it" pentru chat cu instrumente native, istorie rezultat, și anularea. E4B rămâne disponibilă pentru alte cereri. Gemma4UnifiedChat Foloseşte-l prins. MLX Implementarea și lansarea de text fiecare cerere . Cache KV. Răspunsul elimină delimitatorii canalului din textul returnat. Terminatorii orfani de instrumente de apel sunt respinse ca răspunsuri malformate. Solicitări eșuate de non-streaming log ID-ul lor cerere, operare, și eroarea de bază în procesul serverului. Gemma 4 12B, conținutul de mesaje de instrumente păstrează JSON ca text, potrivind șablonul de chat punct de control.
Sursa construiește acceptă --inference-manifest modele.json pentru a încărca înscenat Gemma 4 E4B INT4, VoxCPM2, plin Whisper Large-v3, și Silero VAD. Acest serviciu începe offline și respinge identitățile de model incompatibile.
Serviciul nativ serializează chat-ul, sinteza și transcrierea; ușor VAD are starea de flux separată. Gemma prefill evaluează fiecare lot 256-token înainte de a începe următorul, cerere starea KV este eliberată, iar cache-ul MLX este limitat la 128 MiB cu o limită de 20 GiB allocator.
Discursul cu flux: adevărat întoarce NDJSON evenimente audio la 48 kHz, urmat de făcut sau eroare. Anulați prin cerereID la /v1/inferință/cancel. GET /v1/inference/capabilități și /v1
speech-server --inference-manifest models.json --port 8080{
"runtimeRevision": "your-source-revision",
"gemmaDirectory": "/models/gemma4-e4b-it-int4",
"voxDirectory": "/models/voxcpm2-unquantized",
"whisperDirectory": "/models/whisper-large-v3-coreml",
"vadDirectory": "/models/silero-vad-coreml"
}Proprietate opțională a modelului
SpeechRuntime oferă încărcare comună, admitere FIFO canelabilă și execuție serializată. Qwen3ASRRuntime selectează MLX sau complet CoreML prin descriptori expliciti; API-urile native și steagurile CLI rămân disponibile.
Serverul audio deţine un permis de execuţie prin fiecare cerere completă, inclusiv fluxul de ieşire, cu până la 32 de cereri de aşteptare. ASR eşecuri produc erori HTTP sau WebSocket evenimente de eroare; transcrieri goale valabile rămân de succes. Playback păstrează mostrele de supraîncărcare. Modele cache şi audio în curs de redare ocupa încă memorie.
Voxtral TTS
Voxtral 4B TTS 2603 ruleaza local pe Apple Silicon prin modulul VotralTTSS: 20 voci prestabilite, nouă limbi, și 24 kHz mono speech.
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.wavDoar vocile presetate; clonarea de referință-audio nu este disponibilă. Fluxuri de ieșire audio prin SDK, CLI, WebSocket și HTTP PCM. Furnizarea textului complet de intrare în față. Greutate model de utilizare CC BY-NC 4.0.
Gemma 4 12B prefill prompt
Serviciul nativ de inferență încarcă regia Gemma 4 12B Unified INT4 model folosind agentDirectory. Selectaţi-l pentru chat cu modelul ID gemma4-12b-it.
Gemma 4 12B prefill umple starea KV în loturi de până la 256 jetoane și calculează primele logit-uri de eșantionare din tokenul prompt final. Proiecțiile vocabularului intermediar sunt omise. Cererea de cache KV este eliberată după finalizarea sau anularea.
Un prefix/sistem nemodificat poate rămâne cached în blocuri complete 256 token. Fiecare cerere extinde o copie de lucru separată. Mesaje de utilizator, istoricul conversației și rezultatele instrumentului nu intră niciodată în instantaneu reținut. Set SPEECH_SWIFT_GEMMA4_PREFIX_CACHE_MB pentru a limita MiB reținut, sau 0 pentru a dezactiva refolosirea. clearPrefixCache() eliberează instantaneu.Rapoarte HTTP reutilizate tokens in cachedPrefixTokens; înregistrări de proveniență gemma4_12b_prefix_cache_budget_bytes
Nativ Gemma Istoricul uneltelor păstrează răspunsurile la instrumente și o continuare asistentă în interiorul aceluiași model de turn. Un mesaj de utilizator următor închide acel model înainte de a deschide următorul turn de utilizator. Trimite fiecare rezultat cu original toolCallID.