Terjemahan mesin · Versi asli bahasa Inggris

Speech Server

Asli Apple waktu jalan

PocketTTS menambahkan asli CoreML speech synthesis to speech-swift. Semua tahap baku ke CPU hanya eksekusi. Aliran Alba Inggris preset 1,920-sampel frame di 24 kHz (80 ms per frame).

Penggunaan Swift dan CLI

Gunakan pockett- tts dengan suara alba. Streaming HTTP membutuhkan PCM; WebSocket memancarkan server audio. Model baku yang ada tidak berubah.

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 adalah HTTP + lokal WebSocket server yang mengekspos setiap Soniqo model melalui sederhana REST API, ditambah OpenAI Realtime API- kompatibel WebSocket di /v1/realtimeKapal dalam Homebrew botol yang sama dengan speech CLI - brew install speech Jatuhkan keduanya di PATH Anda.

Pasang dan jalankan

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)

Flag baris-perintah

FlagBakuDeskripsi
--host127.0.0.1Alamat bind. Ganti ke 0.0.0.0 untuk mengekspos LAN.
--port8080Pelabuhan TCP.
--preloadmatiMuat semua model dengan penuh semangat pada startup. Boot lambat (~ 30-60 s) tapi nol latensi permintaan pertama.

Model diunduh pada penggunaan pertama dan cache di ~/Library/Caches/qwen3-speech/Permintaan pertama untuk model yang diberikan membayar biaya download + load (30 s - 2 min tergantung pada ukuran model); permintaan selanjutnya hangat.

REST titik akhir

POST /transcribe - Speech-to-text

Menerima jasad WAV mentah atau amplop JSON dengan 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"}'

Respon: {"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

Tubuh respon adalah gumpalan WAV. Didukung engine nilai: qwen3 (bawaan), 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

Berjalan PersonaPlex 7B - pidato masuk, pidato keluar. transkrip dikembalikan sebagai X-Response-Text tajuk. PersonaPlex panduan untuk nama-nama awal suara.

POST /enhance - Pidato peningkatan

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

DeepFilterNet3 di 48 kHz Masukan adalah resambled jika diperlukan.

GET /health - Pemrobe kesegaran

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

Tes HTTP dan realtime WebSocket menunggu hasil tes /health untuk mengembalikan HTTP 200 dengan {"status":"ok"}, dengan 10Deadline startup kedua. Kesalahan startup gagal uji setup, dan teardown menunggu server shutdown sebelum menggunakan kembali port-nya.

WebSocket: /v1/realtime

Drop-in kompatibel dengan OpenAI Realtime API - Skema acara JSON yang sama (session.update, input_audio_buffer.append, response.create, response.audio.delta, dengan base64-encoded PCM16 audio di 24 kHz. Klien ditulis melawan OpenAI Realtime SDK bekerja melawan speech-server tanpa perubahan kode (hanya switch URL WebSocket).

Otomatis berputar dengan server VAD

Manual input_audio_buffer.commit tetap baku. Set session.turn_detection ke server_vad menjalankan Silero VAD pada server dan secara otomatis menyalin setiap perubahan pidato yang telah selesai. Pengaturan audio dipertahankan, penyusunan menganggur tetap dibatasi, dan giliran aktif terus menerus tertutup pada maksimal yang dikonfigurasi.

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 contoh

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 contoh

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

Catatan pengembangan

Sumber

Inferensi lokal lokal

Untuk 12B, diulang di samping tool- call penutup penanda segera setelah panggilan lengkap, tervalidasi dikonsumsi dengan panggilan tersebut. Mereka tidak membuat panggilan lain atau mengubah argumen. Standally penanda dan argumen tetap salah tetap error; E4B mempertahankan penanganan ketat.

Untuk mempertahankan permintaan obrolan yang gagal, ditata failureCaptureDirectory dalam daftar muatan. Penangkapan tidak aktif secara baku. Direktori harus menolak grup dan akses lain; direktori baru pakai 0700 dan berkas kegagalan digunakan 0600Berkas termasuk tubuh permintaan yang tepat, permintaan ID dan error. Selesai 12B generasi juga mempertahankan prompt yang dirender, ID token, keluaran mentah dan stop alasan sebelum parsing. Kegagalan E4B tidak memiliki catatan pembuatan mentah. Berkas lokal ini berisi percakapan dan konten alat; Galat HTTP dan permintaan sukses tidak termasuk mereka.

Direktori agentDirektori opsional memuat suatu ter-stage Gemma 4 12B Disatukan INT4 model teks di samping E4B Gunakan model: "gemma4-12b-it"untuk chatting dengan alat-alat asli, hasil sejarah, dan pembatalan. E4B tetap tersedia untuk permintaan lain. Gemma4UnifiedChat gunakan jepped MLX implementasi teks dan rilis setiap cache KV permintaan. Jawaban parsing penghapus saluran dari teks yang kembali. Penghasut antar-panggil ditolak sebagai respon salah bentuk. Gagal bukan-streaming permintaan log ID, operasi, dan kesalahan yang mendasari dalam proses server. Untuk Gemma 4 12B, isi pesan tool-message mempertahankan JSON sebagai teks, cocok dengan titik pemeriksaan template obrolan.

Sumber membangun menerima --inference-manifest model. json untuk dipentaskan Gemma 4 E4B INT4, VoxCPM2, penuh Whisper Large-v3, dan Silero VADLayanan ini mulai offline dan menolak identitas model yang tidak kompatibel.

Layanan asli serialisasi percakapan, sintesis, dan transkripsi; ringan VAD memiliki keadaan aliran terpisah. Gemma prefill dievaluasi setiap 256-token batch sebelum memulai berikutnya, permintaan keadaan KV dirilis, dan MLX cache dicapped di 128 MiB dengan 20 Batas allocator GiB.

Pidato dengan stream: kejadian audio NDJSON kembali benar di 48 kHz, diikuti oleh dilakukan atau error. Batal oleh requestID di /v1/ menyimpulkan / batal. GET /v1/ kesimpulan / kemampuan dan /v1/ inferensi / provenance laporan identitas model, parameter dtypes, pin aset, dan penghitung memori.

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

Rincian API

Pemilik model opsional

SpeechRuntime menyediakan muatan bersama, penerimaan FIFO yang dapat dibatalkan dan eksekusi serialisasi. Qwen3ASRRuntime memilih MLX atau penuh CoreML melalui deskriptor eksplisit; bendera APIs dan CLI asli masih tersedia.

Server audio memiliki satu ijin eksekusi melalui setiap permintaan lengkap, termasuk keluaran streaming, dengan hingga 32 permintaan menunggu. ASR gagal menghasilkan kesalahan HTTP atau WebSocket kesalahan terjadi; transkrip kosong tetap sukses. Pemutaran mempertahankan sampel overflow. Model cache dan audio putar menunggu masih menempati memori.

Voxtral TTS

Voxtral 4B TTS 2603 berjalan lokal pada Apple Silicon melalui modul Voxtral TTS: 20 preset suara, sembilan bahasa, dan 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.wav

Hanya preset suara; reference-audio cloning tidak tersedia. Keluaran stream audio melalui SDK, CLI, WebSocket dan HTTP PCM. Pasokan teks masukan lengkap di depan. Model bobot menggunakan CC BY- NC 4.0.

Baca Voxtral TTS Panduan

Gemma 4 12B prompt prefill

Layanan inferensi asli memuat yang dipentaskan Gemma 4 12B Disatukan INT4 model menggunakan agentDirectory. Pilih untuk chatting dengan ID model gemma4-12b-it.

Gemma 4 12B prefill fill KV state in batch of up to 256 token dan komputasi logit contoh pertama dari token prompt akhir. Perbaikan proyeksi kosakata dilewatkan. cache KV permintaan dirilis setelah pelengkapan atau pembatalan.

Satu prefiks sistem / alat yang tidak berubah dapat tetap cache dalam blok token 256-lengkap. Setiap permintaan memperluas salinan kerja yang terpisah. Pesan pengguna, riwayat percakapan, dan hasil alat tidak pernah memasukkan snapshot yang ditahan. Set SPEECH_SWIFT_GEMMA4_PREFIX_CACHE_MB untuk membatasi ditahan MiB, atau 0 untuk menonaktifkan penggunaan ulang. clearPrefixCache() rilis snapshot. HTTP laporan penggunaan ulang token dalam cachedPrefixTokens; catatan provenance gemma4_12b_prefix_cache_budget_bytesPermintaan dingin masih memproses kecepatan penuh.

Asli Gemma tool history keeps tool response and an assistant continuation inside the same model turn. Pesan pengguna berikut menutup giliran model itu sebelum membuka giliran pengguna berikutnya. Kirim setiap hasil dengan aslinya toolCallID.