Maskinoversettelse · Engelsk original

Speech Server

Native Apple Runtime · PocketTTS

PocketTTS legger til opprinnelig CoreML talesyntese til speech-swift. Alle stadier er standard til CPU-beskyttelse. Den engelske Alba-forhåndsinnstilte strømmer 1.920-prøverammer ved 24 kHz (80 ms per ramme).

Swift og CLI-bruk

Bruk lommeknepninger med stemmealba. Strømming HTTP krever PCM; WebSocket sender ut lyddeltaer. De eksisterende standardmodellene er uendret.

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 er en lokal HTTP + WebSocket server som avslører hver Soniqo modell gjennom en enkel REST API, pluss en OpenAI Realtime API-kompatible WebSocket på /v1/realtime. Det skip i samme Homebrew flaske som speech CLI — brew install speech dråper på PATH.

Installer og kjør

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)

Kommandolinjeflagg

FlagStandard Beskrivelse
--host127.0.0.1 Bindeadresse. Endre til 0.0.0.0 for å eksponere på LAN.
--port8080TCP-port.
--preloadavLast alle modeller ivrig ved oppstart. Slower boot (~30-60 s) men null første-spørre latens.

Modellene lastes ned ved første bruk og cached i ~/Library/Caches/qwen3-speech/. Den første forespørselen om en gitt modell betaler nedlastingen + belastningskostnaden (30 s- 2 min avhengig av modellstørrelse); påfølgende forespørsler er varme.

REST endepunkter

POST /transcribe — Tale-til-tekst

Aksepterer enten en rå WAV kropp eller en JSON konvolutt med base64-encoded lyd.

# 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"}'

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

POST /speak — Tekst-til-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

Svarkroppen er en WAV blob. Støttet engine verdier: qwen3 (standard), cosyvoice, kokoro.

POST /respond — Tale-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

Kjører PersonaPlex 7B - tale i, tale ut. Transkript returneres som en X-Response-Text-topptekst. Se PersonaPlex for stemmeforvalgte navn.

POST /enhance — Taleforbedring

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

DeepFilterNet3 ved 48 kHz. Inngang blir reprøvet om nødvendig.

GET /health — Levetidssonde

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

HTTP og sanntid WebSocket-testene venter på /health for å returnere HTTP 200 med {"status":"ok"}, med en 10 sekunders oppstartsfrist. Oppstartsfeil mislykkes testoppsett, og nedbrytning venter på at serveren avsluttes før den gjenbruker porten.

WebSocket: /v1/realtime

Drop-in-kompatible med OpenAI Realtime API — det samme arrangementsskjemaet JSON (session.update, input_audio_buffer.append, response.create, response.audio.delta, ...) med base64-encoded PCM16-lyd på 24 kHz. Kunder skrevet mot OpenAI s Realtime SDK arbeid mot speech-server uten kodeendringer (bare bytte WebSocket-URL).

Automatiske svinger med serveren VAD

Manuell input_audio_buffer.commit forblir standard. Set session.turn_detection til server_vad å kjøre Silero VAD på serveren og automatisk overføre hver fullført taletur. Prefiks lyd blir beholdt, inaktiv buffering forblir bundet, og en kontinuerlig aktiv tur er tvangslukket på det konfigurerte maksimum.

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 eksempel

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 eksempel

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())

Utdelingsnotater

Kilde

Lokalt innfødt inferens

For 12B, gjentatte tilstøtende verktøy-kall stenge markører umiddelbart etter en fullstendig, validert samtale er forbrukt med det anropet. De oppretter ikke et annet anrop eller endrer argumentene. Standalone markører og feilaktige argument forblir feil; E4B beholder streng håndtering.

For å beholde feil innfødte chatforespørsler, sett failureCaptureDirectory i inferien manifest. Fange er av som standard. Katalogen må nekte gruppe og annen tilgang; nye kataloger bruker 0700 og feilfiler bruker 0600. Filene inkluderer nøyaktige forespørselsorgan, be om ID og feil. Fullførte 12B generasjoner beholder også den gjengitte spørrings-, token-ID-er, rå utgangs- og stoppgrunn før tolking. E4B feil har ingen rågenerasjonspost. Disse lokale filene inneholder konversasjon og verktøyinnhold; HTTP-feil og vellykket forespørsler inkluderer dem ikke.

Valgfritt agentDirectory laster en scened Gemma 4 12B-samlede INT4 tekstmodell ved siden av E4B. Bruk modell: .gemma4-12b-itFor chat med innfødte verktøy, resultathistorie og kansellering. E4B Forblir tilgjengelig for andre forespørsler. Gemma4UnifiedChat bruk av festet MLX tekst implementasjon og frigjør hver forespørsels KV cache. Response parsing fjerner kanalskillerne fra returnert tekst. Orphanede verktøy-kall terminatorer blir avvist som feilaktige svar. Feil ikke-strømsforespørsler logger deres forespørsler ID, operasjon og underliggende feil i serverprosessen. For Gemma 4 12B, verktøy-melding innhold bevarer JSON som tekst, samsvarer med checkpoint chat malen.

Kildebygg aksepterer --inference-manifest modeller.json å laste iscenelagt Gemma 4 E4B INT4, VoxCPM2, full Whisper Large-v3, og Silero VAD. Denne tjenesten starter offline og avviser ikke-kompatibel modellidentiteter.

Den opprinnelige tjenesten serialiserer chat, syntese og transkripsjon; lett VAD har separat stream-tilstand. Gemma forhåndsfylling vurderer hver 256-token batch før start den neste, ber KV-tilstanden frigjøres, og MLX cacheen er caped på 128 MiB med en 20 GiB allocator grense.

Tal med stream: ekte returnerer NDJSON-lydhendelser ved 48 kHz, etterfulgt av gjort eller feil. Avbryt ved forespørselID på /v1/inferens/cancel. GET /v1/inference/capabilities og /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"
}

API detaljer

Valgfritt modelleierskap

SpeechRuntime gir delt lasting, kancellerbar FIFO-opptak og seriealisert utførelse. Qwen3ASRRuntime velger MLX eller full CoreML gjennom eksplisitte deskriptorer; innfødte API-er og CLI-flagg forblir tilgjengelige.

Lydserveren har én utføringstillatelse gjennom hver fullstendige forespørsel, inkludert streamingutgang, med opptil 32 forespørsler som venter. ASR feil produserer HTTP-feil eller WebSocket feilhenvisninger; gyldige tomme transkripsjoner forblir vellykket. Avspilling bevarer overflytprøver. Cachede modeller og avventende lyd fortsatt okkupasjonsminne.

Voxtral TTS

Voxtral 4B TTS 2603 kjører lokalt på Apple Silicon gjennom Voxtral TTS-modulen: 20 forhåndsinnstilte stemmer, ni språk og 24 kHz mono tale.

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

Bare forhåndsinnstillinger; referanse-audio kloning er utilgjengelig. Lydutgangsstrømmer gjennom SDK, CLI, WebSocket og HTTP PCM. Gi den komplette inngangsteksten opp foran. Modellvekter bruker CC BY-NC 4.0.

Les Voxtral TTS guide

Gemma 4 12B-førfylling

Den opprinnelige inferenstjenesten laster den iscenelagte Gemma 4 12B Unified INT4 modellen ved hjelp av agentDirectory. Velg den for chat med modellen ID gemma4-12b-it.

Gemma 4 12B påfyller KV-tilstand i partier på opptil 256 token og beregner de første prøvetakingsloggene fra den endelige hurtigsymbolet. Mellomliggende ordforrådsprojeksjoner hoppes over. Forespørselens KV-buffer frigjøres etter fullføring eller kansellering.

Et uendret system/verktøyprefiks kan forbli cached i fullstendig 256-token blokker. Hver forespørsel utvider en separat arbeidskopi. Brukermeldinger, samtalehistorikk og verktøyresultater kan aldri gå inn i det beholdte øyeblikksbildet. Sett SPEECH_SWIFT_GEMMA4_PREFIX_CACHE_MB for å begrense beholdt MBB, eller 0 for å deaktivere gjenbruk. clearPrefixCache() frigjør øyeblikksbilde. HTTP-rapporter gjenbrukte poliner i cachedPrefixTokens; dokumenteringsposter gemma4_12b_prefix_cache_budget_bytes. Kalde forespørsler prosesserer fortsatt i full kontakt.

Native Gemma verktøyloggen holder verktøyresponsene og en assistent fortsetter i samme modell. En etterfølgende brukermelding lukker den modellens sving før neste brukersving. Send hvert resultat med sin opprinnelige toolCallID.