Automatische vertaling · Engels origineel
Speech Server
Inheemse Apple runtime · PocketTTS
PocketTTS voegt native CoreML spraaksynthese toe aan speech-swift. Alle fasen zijn standaard voor CPU-uitvoering. De Engelse Alba-voorinstelling streamt 1.920-sample frames op 24 kHz (80 ms per frame).
Gebruik pocket-tts met voice alba. Streaming HTTP vereist PCM; WebSocket zendt audio delta's uit. De bestaande standaardmodellen zijn ongewijzigd.
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 is een lokale HTTP + WebSocket server die elk Soniqo model blootlegt via een eenvoudige REST API, plus een OpenAI Realtime API-compatibel WebSocket op /v1/realtime. Het schipt in dezelfde Homebrew als de speech CLI CLI › brew install speech install speague daalt zowel op uw PATH.
Installeren en uitvoeren
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)
Opdrachtregelvlaggen
| Vlag | Standaard | Omschrijving |
|---|---|---|
--host | 127.0.0.1 | Bind adres. Verander naar 0.0.0.0 om te ontmaskeren op LAN. |
--port | 8080 | TCP poort. |
--preload | off | Alle modellen gretig laden bij het opstarten.30–60 s) maar nul eerste aanvraag latentie. |
Modellen worden gedownload bij eerste gebruik en ingecached ~/Library/Caches/qwen3-speech/. De eerste aanvraag voor een bepaald model betaalt de download + laadkosten (30 s 2 min afhankelijk van de modelgrootte); volgende verzoeken zijn warm.
REST eindpunten
POST /transcribe
Accepteert een ruwe WAV body of een JSON envelop met 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"}'
Respons: {"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
Response body is a WAV blob. Ondersteund engine waarden: qwen3 (standaard), 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 . speech in, speech out. Transcript wordt teruggegeven als een X-Response-Text Kop. PersonaPlex-gids voor vooraf ingestelde namen.
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 bij 48 kHz. Invoer wordt indien nodig opnieuw ingedeeld.
GET /health
curl http://127.0.0.1:8080/health
# {"status":"ok"}
De HTTP en realtime WebSocket testen wachten op /health om HTTP 200 terug te geven met {"status":"ok"}, met een deadline voor het opstarten van 10 seconden. Opstartfouten falen tijdens het testen, en de server wordt afgebroken voordat de poort wordt hergebruikt.
WebSocket: /v1/realtime
Drop-in compatibel met de OpenAI Realtime API Het JSON-evenementschema (session.update, input_audio_buffer.append, response.create, response.audio.delta, ...) met base64-encoded PCM16 audio op 24 kHz. Klanten geschreven tegen OpenAI's Realtime SDK werken tegen speech-server zonder codewijzigingen (schakel gewoon de WebSocket URL).
Automatische draaien met server VAD
Handmatig input_audio_buffer.commit blijft de standaardinstelling. Stel session.turn_detection in server_vad in om Silero VAD op de server te draaien en schrijf automatisch elke voltooide spraakomslag over. Prefix audio wordt behouden, stationair bufferen blijft begrensd, en een continu actieve draai wordt met kracht afgesloten bij het geconfigureerde 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 voorbeeld
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 voorbeeld
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())
Tenuitvoerleggingsnotities
- Geen auth standaard.
speech-serverbindt127.0.0.1en vertrouwt elke beller. Zet het achter een omgekeerde proxy (Caddy, nginx, staartschaal) als je het buiten localhost stelt. - Modellen zijn lui geladen. Eerste verzoek om
/transcribeactiveert de ASR download + lading (~700 MB, 30–60 s) Gebruik--preloadvoor nul koude start maar langzamere laars. - Geen streaming transcriptie nog niet.
POST /transcribeverwacht de volledige WAV vooraan. Gebruik/v1/realtimevoor streaming. - Systeem/gestart. Er wordt vandaag geen diensteenheid geleverd. Een gewone
nohup speech-server &of uw gebruikelijke proces supervisor werkt.
Bron
- Bronnen/AudioServer Op Hummingbird gebaseerde HTTP-router, luie modelregister,
/v1/realtimeWebSocket handler. - Bronnen/AudioServerCLI —
@mainingangspunt, argumentparser. - Upstream: OpenAI Realtime API referentie.
Lokale lokale gevolgtrekking
Voor 12B worden herhaalde naast elkaar liggende tool-call sluitmarkers direct na een volledige, gevalideerde oproep gebruikt. Ze maken geen andere oproep of wijzigen de argumenten ervan. Standalone markers en onjuist gevormde argumenten blijven fouten; E4B behoudt strikte behandeling.
Om mislukte native chatverzoeken te behouden, moet failureCaptureDirectory worden ingesteld in het gevolg manifest. Capture is standaard uitgeschakeld. De directory moet groep en andere toegang weigeren; nieuwe mappen gebruiken 0700 en foutbestanden gebruiken 0600. Bestanden omvatten de exacte aanvraagformulier, ID-aanvraag en foutmelding. Gereed 12B-generaties behouden ook de weergegeven prompt, token-ID's, ruwe uitvoer en stoppen reden voor het verwerken. E4B fouten hebben geen ruwe generatierecord. Deze lokale bestanden bevatten conversatie- en gereedschapsinhoud; HTTP-fouten en succesvolle verzoeken bevatten ze niet.
Facultatief agentDirectory laadt een geënsceneerd Gemma 4 12B Unified INT4 tekstmodel naast E4B. Gebruik model: "gemma4-12b-it" voor chat met native tools, resultaatgeschiedenis, en annulering. E4B blijft beschikbaar voor andere verzoeken. Gemma4UnifiedChat gebruikt de gepinde MLX tekstimplementatie en releases van elk verzoek. KV-cache. Response parsing verwijdert kanaalgrenzen van teruggestuurde tekst. Orphaned tool-call terminators worden afgewezen als misvormde antwoorden. Foute niet-streaming verzoeken log hun verzoek ID, operatie en onderliggende fout in het serverproces. Voor Gemma 4 12B, inhoud van gereedschapsberichten bewaart JSON als tekst, die overeenkomt met het checkpoint chat-sjabloon.
Bronbouwen accepteren --inference-manifest modellen.json om gefaseerd Gemma 4 E4B INT4, VoxCPM2, volledig Whisper Large-v3 en Silero VAD. Deze dienst start offline en wijst incompatibele modelidentiteit af.
De native service serialiseert chat, synthese en transcriptie; lichtgewicht VAD heeft een aparte streamstatus. Gemma prefill evalueert elke 256-token batch voordat de volgende start, de KV-status wordt vrijgegeven, en de MLX cache wordt begrensd op 128 MiB met een 20 GiB allocatorlimiet.
Speech with stream: true returns NDJSON audio events at 48 kHz, followed by done or error. Annuleren op verzoekID at /v1/inferentie/ancel. GET /v1/invloed/capaciteiten en /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"
}Facultatief modelbezit
SpeechRuntime biedt gedeelde laden, opzegbare FIFO-toegang en seriematige uitvoering. Qwen3ASRRuntime selecteert MLX of volledige CoreML via expliciete descriptoren; de oorspronkelijke API's en CLI-vlaggen blijven beschikbaar.
De audioserver heeft één uitvoervergunning door elke volledige aanvraag, inclusief gestreamde uitvoer, met maximaal 32 verzoeken die wachten. ASR storingen veroorzaken HTTP-fouten of WebSocket error events; geldige lege transcripten blijven succesvol. Afspelen behoudt overflowsamples. Gecachede modellen en in afwachting van afspeelaudio blijft het geheugen bezet.
Voxtral TTS
Voxtral 4B TTS 2603 draait lokaal op Apple Silicon via de Voxtral tTS module: 20 vooraf ingestelde stemmen, negen talen en 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.wavUitsluitend stemmen vooraf instellen; referentie-audio klonen is niet beschikbaar. Audiouitvoer stroomt door de SDK, CLI, WebSocket en HTTP PCM. Geef de volledige invoertekst vooraf. Modelgewichten gebruiken CC BY-NC 4.0.
Gemma 4 12B prompt prefill
De inheemse inferentiedienst laadt het geënsceneerde Gemma 4 12B Unified INT4 model met agentDirectory. Selecteer het om te chatten met het model ID gemma4-12b-it.
Gemma 4 12B voorvulling vult KV-status in batches van maximaal 256 tokens en berekent de eerste sampling logits van de laatste prompt token. De tussenliggende woordenschat projecties worden overgeslagen. De aanvraag KV cache wordt vrijgegeven na voltooiing of annulering.
Een ongewijzigd systeem/gereedschapsvoorvoegsel kan in volledige 256-getoken blokken blijven opgeslagen. Elk verzoek breidt een aparte werkkopie uit. Gebruikersberichten, gespreksgeschiedenis en gereedschapsresultaten geven nooit de bewaarde snapshot in. Stel SPEECH_SWIFT_GEMMA4_PREFIX_CACHE_MB in om bewaarde MiB te beperken, of 0 om hergebruik uit te schakelen. clearPrefixCache() geeft de snapshoot uit. HTTP-rapporten hergebruikt tokens in cachedPrefixTokens; herkomstrecords gemma4_12b_prefix_cache_budget_bytes. Koude verzoeken verwerken nog steeds de volledige prompt.
Native Gemma gereedschapsgeschiedenis houdt gereedschapsresponsen en een assistent-vervolging in hetzelfde model draaien. Een volgende gebruikersbericht sluit dat model draaien voordat de volgende gebruiker draaien. Stuur elk resultaat met zijn originele toolCallID.