Speech Server
Apple için yerel çalışma zamanı · PocketTTS
PocketTTS, speech-swift'e yerel CoreML konuşma sentezi ekler. Tüm aşamalar varsayılan olarak yalnızca CPU kullanır. İngilizce Alba sesi 24 kHz'de 1.920 örneklik kareler, yani kare başına 80 ms ses aktarır.
pocket-tts ve alba sesini kullanın. HTTP akışı PCM gerektirir; WebSocket ses parçaları gönderir. Mevcut varsayılan modeller korunur.
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; her Soniqo modelini basit bir REST API ile sunan ve /v1/realtime adresinde OpenAI Realtime API uyumlu bir WebSocket sağlayan yerel bir HTTP + WebSocket sunucusudur. speech CLI ile aynı Homebrew bottle içinde gelir — brew install speech her ikisini birden PATH'inize yerleştirir.
Kurulum ve çalıştırma
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)
Komut satırı bayrakları
| Bayrak | Varsayılan | Açıklama |
|---|---|---|
--host | 127.0.0.1 | Bind adresi. LAN'a açmak için 0.0.0.0 olarak değiştirin. |
--port | 8080 | TCP portu. |
--preload | kapalı | Tüm modelleri başlangıçta hevesle yükler. Boot daha yavaş (~30–60 sn) ama ilk istek gecikmesi sıfırdır. |
Modeller ilk kullanımda indirilir ve ~/Library/Caches/qwen3-speech/ içinde önbelleğe alınır. Belirli bir model için ilk istek, indirme + yükleme maliyetini öder (model boyutuna göre 30 sn – 2 dk); sonraki istekler sıcaktır.
REST uç noktaları
POST /transcribe — Konuşmadan metne
Ya ham bir WAV gövdesi ya da base64 ile kodlanmış ses içeren bir JSON zarfı kabul eder.
# 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"}'
Yanıt: {"text": "…", "language": "en", "confidence": 0.93}.
POST /speak — Metinden konuşmaya
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
Yanıt gövdesi bir WAV blob'udur. Desteklenen engine değerleri: qwen3 (varsayılan), cosyvoice, kokoro.
POST /respond — Konuşmadan konuşmaya
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
PersonaPlex 7B'yi çalıştırır — ses girer, ses çıkar. Transkript bir X-Response-Text başlığında döndürülür. Ses preset adları için PersonaPlex kılavuzuna bakın.
POST /enhance — Konuşma iyileştirme
curl -X POST http://127.0.0.1:8080/enhance \
-H "Content-Type: audio/wav" \
--data-binary @noisy.wav \
--output clean.wav
48 kHz'de DeepFilterNet3. Giriş gerekirse yeniden örneklenir.
GET /health — Canlılık denetimi
curl http://127.0.0.1:8080/health
# {"status":"ok"}
HTTP ve gerçek zamanlı WebSocket testleri, 10 saniyelik başlatma süresi içinde /health uç noktasının HTTP 200 ve {"status":"ok"} döndürmesini bekler. Başlatma hataları test hazırlığını başarısız kılar; temizleme işlemi, bağlantı noktasını yeniden kullanmadan önce sunucunun kapanmasını bekler.
WebSocket: /v1/realtime
OpenAI Realtime API ile doğrudan uyumlu — aynı JSON olay şeması (session.update, input_audio_buffer.append, response.create, response.audio.delta, …) ile 24 kHz'de base64 kodlu PCM16 ses. OpenAI'ın Realtime SDK'sına karşı yazılmış istemciler, kod değişikliği olmadan (yalnızca WebSocket URL'sini değiştirerek) speech-server ile çalışır.
Sunucu VAD ile otomatik konuşma sıraları
Elle input_audio_buffer.commit varsayılan olarak kalır. Sunucuda Silero VAD çalıştırmak ve tamamlanan her konuşma sırasını otomatik yazıya dökmek için session.turn_detection değerini server_vad yapın. Ön ek ses korunur, boşta arabelleğe alma sınırlıdır, speech_started, speech_stopped ve committed olayları sırayla gönderilir ve sürekli etkin bir sıra yapılandırılan üst sınırda zorla kapatılır.
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 örneği
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 örneği
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())
Dağıtım notları
- Varsayılanda kimlik doğrulama yok.
speech-server,127.0.0.1üzerinde dinler ve her çağıranına güvenir. localhost ötesine açacaksanız bir ters proxy'nin (Caddy, nginx, tailscale) arkasına alın. - Modeller tembel yüklenir.
/transcribeiçin ilk istek ASR indirmesi + yüklemesini tetikler (~700 MB, 30–60 sn). Soğuk başlatma olmaması için--preloadkullanın, boot daha yavaş olur. - Henüz streaming transkripsiyon yok.
POST /transcribetüm WAV'ı önden bekler. Streaming için/v1/realtime'ı kullanın. - Systemd / launchd. Bugün için bir servis birimi gelmiyor. Düz bir
nohup speech-server &ya da her zamanki süreç yöneticiniz işinizi görür.
Kaynak kodu
- Sources/AudioServer — Hummingbird tabanlı HTTP yönlendirici, tembel model kayıt defteri,
/v1/realtimeWebSocket işleyicisi. - Sources/AudioServerCLI —
@maingiriş noktası, argüman ayrıştırıcı. - Üst akış: OpenAI Realtime API referansı.
İsteğe bağlı model yönetimi
SpeechRuntime paylaşılan yükleme, iptal edilebilir FIFO kabulü ve sıralı çalıştırma sağlar. Qwen3ASRRuntime açık tanımlayıcılarla MLX veya tam CoreML seçer; yerel API ve CLI seçenekleri kullanılabilir kalır.
Sunucu akış çıktısı dahil tüm istek boyunca bir çalıştırma izni tutar ve en fazla 32 isteği bekletir. ASR hataları HTTP hataları veya WebSocket hata olayları olarak iletilir; geçerli boş dökümler başarılı kalır. Oynatma, taşan örnekleri korur. Önbellekteki modeller ve bekleyen ses verisi bellekte yer kaplamaya devam eder.
Voxtral TTS
Voxtral 4B TTS 2603, VoxtralTTS modülüyle Apple Silicon üzerinde yerel çalışır: 20 hazır ses, dokuz dil ve 24 kHz tek kanallı konuşma.
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.wavYalnızca hazır sesler desteklenir; referans sesten klonlama kullanılamaz. SDK, CLI, WebSocket ve HTTP PCM, üretim sırasında ses iletir. Giriş metni başlangıçta eksiksiz verilmelidir. Model ağırlıkları CC BY-NC 4.0 lisansını kullanır.
Gemma 4 12B istem ön doldurma
Yerel çıkarım hizmeti, hazırlanan Gemma 4 12B Unified INT4 modelini agentDirectory üzerinden yükler. Sohbet için gemma4-12b-it model kimliğiyle seçin.
Gemma 4 12B ön doldurma işlemi, KV durumunu en fazla 256 tokenlık gruplarla doldurur ve ilk örnekleme logits değerlerini istemin son tokenından hesaplar. Ara konumlardaki sözcük dağarcığı izdüşümleri atlanır. İstek tamamlandığında veya iptal edildiğinde KV önbelleği serbest bırakılır.
Değişmeyen bir sistem/araç öneki tam 256 tokenlık bloklar halinde tutulabilir. Her istek bağımsız bir çalışma kopyasını genişletir; kullanıcı mesajları, konuşma geçmişi ve araç sonuçları saklanan duruma eklenmez. SPEECH_SWIFT_GEMMA4_PREFIX_CACHE_MB belleği MiB olarak sınırlar; 0 yeniden kullanımı kapatır. clearPrefixCache() saklanan durumu serbest bırakır. HTTP yeniden kullanılan tokenları cachedPrefixTokens ile bildirir; kaynak bilgisi gemma4_12b_prefix_cache_budget_bytes değerini kaydeder. Soğuk istekler istemin tamamını işlemeye devam eder.
Gemma’nın yerel araç geçmişi, araç sonuçlarını ve asistanın devam yanıtını aynı model turunda tutar. Ardından bir kullanıcı mesajı gelirse, sonraki kullanıcı turu açılmadan önce model turu kapatılır. Her sonucu özgün toolCallID değeriyle gönderin.