Awtomatikong salin · Orihinal sa Ingles

API at mga protocol

Katutubong Apple runtime · PocketTTS

Ang PocketTTS ay nagdaragdag ng katutubong CoreML speech synthesis sa speech-swift. lahat ng mga yugto ay default sa CPU-lamang pagpatay. Ang Ingles na Alba preseted streams 1,920-sample frames sa 24 kHz (80 ms kada frame).

Ginamit ang Swift at CLI

import PocketTTS
let model = try PocketTTSModel.fromBundle(URL(fileURLWithPath: "/path/to/bundle"))
try await model.generateStreaming(text: "Hello world.") { chunk in
    await consume(chunk.samples)
}

Ang AudioCommon module ay nagbibigay ng kahulugan sa mga modelong-agnostikong protocol at kabahaging mga uri.Ang anumang nag-aareglong modelo ay maaaring gamitin nang halinhinan sa pamamagitan ng mga interface na ito.

Labis na Pagsusuri sa Protocol

┌─────────────────────────────────────────────────────────┐
│                    AudioCommon                          │
│                                                         │
│  AudioChunk          SpeechGenerationModel (TTS)        │
│  AlignedWord         SpeechRecognitionModel (STT)       │
│  SpeechSegment       ForcedAlignmentModel               │
│                      SpeechToSpeechModel                │
│                      VoiceActivityDetectionModel (VAD)   │
│                      TurnCompletionProvider (EOT)       │
│                      SpeakerEmbeddingModel              │
│                      SpeakerDiarizationModel            │
│                      SpeakerExtractionCapable           │
└─────────────────────────────────────────────────────────┘

UModel sa Pagsasalita

Protocol para sa mga modelong speech-to-text.

public protocol SpeechRecognitionModel: AnyObject {
    var inputSampleRate: Int { get }
    func transcribe(audio: [Float], sampleRate: Int, language: String?) -> String
    func transcribeWithLanguage(audio: [Float], sampleRate: Int, language: String?) -> TranscriptionResult
}

Mga sumusunod na uri: Qwen3ASRModel, WhisperASRModel, ParakeetASRModel, ParakeetStreamingASRModel, OmnilingualASRModel (CoreML), OmnilingualASRMLXModel (MLX)

UModel sa Pagsasalita

Protocol para sa mga modelong text-to-speech.

public protocol SpeechGenerationModel: AnyObject {
    var sampleRate: Int { get }
    func generate(text: String, language: String?) async throws -> [Float]
    func generateStream(text: String, language: String?) -> AsyncThrowingStream<AudioChunk, Error>  // has default impl
}

generateStream() ay may default na pagpapatupad na nagbabalot generate() Ang mga model na may tunay na pag-agos (hal. Qwen3-TTS) ay nangingibabaw dito.

Mga sumusunod na uri: Qwen3TTSModel, CosyVoiceTTSModel, VoxCPM2TTSModel, KokoroTTSModel, IndexTTS2TTSModel

IndexTTS2TTSModel magdagdag ng reference-audio generate verses para sa sero-shot na voice cloning at gumamit ng IndexTTS2SynthesisOptions para sa pagsasalita-rate at mga kontrol sa paghinto.

Qwen3-TTS lokal na pagkarga

fromLocal Ang mga pagpapatunay ay nangangailangan ng mga file at checkpoint strip concomplete, pagkatapos ay kumukuha ng modelong sukat, quanization, at arkitektura mula sa modelo config.json. Ang opsyonal configuration Ang halaga ay isang pagkahulog lamang para sa inalis na metadata; ang dispormado o nagkakasalungatang mga paghahagis ng metadata Qwen3TTSLoadingError.invalidConfiguration bago ang model allocation.

public static func fromLocal(
    modelDirectory: URL,
    tokenizerDirectory: URL,
    configuration: Qwen3TTSConfig? = nil,
    wiredMemoryPolicy: Qwen3TTSWiredMemoryPolicy = .none,
    progressHandler: ((Double, String) -> Void)? = nil
) throws -> Qwen3TTSModel

public static func fromPretrained(
    modelId: String = Qwen3TTSModel.defaultModelId,
    tokenizerModelId: String = "Qwen/Qwen3-TTS-Tokenizer-12Hz",
    cacheDir: URL? = nil,
    tokenizerCacheDir: URL? = nil,
    offlineMode: Bool = false,
    wiredMemoryPolicy: Qwen3TTSWiredMemoryPolicy = .pin(fraction: 0.9),
    progressHandler: ((Double, String) -> Void)? = nil
) async throws -> Qwen3TTSModel
patakaran ng memorya

fromLocal Mga hindi pagtupad sa .none, kaya't hindi nito binabago ang process-wide Metal wired-memory limit. fromPretrained panatilihin ang kaniyang .pin(fraction: 0.9) Ang parehong pretrained loaders ay tumatanggap ng hiwalay tokenizerCacheDir.

Puwersadong MIModel

Protocol para sa salitang-level timestamp na pagkakahanay.

public protocol ForcedAlignmentModel: AnyObject {
    func align(audio: [Float], text: String, sampleRate: Int, language: String?) -> [AlignedWord]
}

Pagsasalita ng USpeechModel

Protocol para sa mga speech-to-speech na mga modelong diyalogo.

public protocol SpeechToSpeechModel: AnyObject {
    var sampleRate: Int { get }
    func respond(userAudio: [Float]) -> [Float]
    func respondStream(userAudio: [Float]) -> AsyncThrowingStream<AudioChunk, Error>
}

Mga sumusunod na uri: PersonaPlexModel

HibikiTranslateModel

Talasalitaang-to-speech translation driver. ay hindi umaayon sa SpeechToSpeechModel Dahil sa ang kontrata ay iba-iba: ang input at output ay iba't ibang wika, ang haba ng output ay variable (EOS-drivin, naka-clush sa max(tSrc * 5/2, tSrc + 20) Mga hakbang – halos 1.0–1.6× source stage sa FLEURS-style clips), at may isang parallel text-token street sa tabi ng audio. Buong giya →

public final class HibikiTranslateModel {
    public let cfg: HibikiConfig
    public static var defaultModelId: String { "aufklarer/Hibiki-Zero-3B-MLX-4bit" }
    public static var modelId8bit: String  { "aufklarer/Hibiki-Zero-3B-MLX-8bit" }

    public static func fromPretrained(
        modelId: String = defaultModelId,
        cacheDir: URL? = nil,
        offlineMode: Bool = false,
        progressHandler: ((Double, String) -> Void)? = nil
    ) async throws -> HibikiTranslateModel

    public func warmUp()

    public func translate(
        sourceAudio: [Float],
        sourceLanguage: HibikiSourceLanguage = .fr,
        verbose: Bool = false
    ) -> (audio: [Float], textTokens: [Int32])

    public func translateStream(
        sourceAudio: [Float],
        sourceLanguage: HibikiSourceLanguage = .fr,
        streaming: HibikiStreamingConfig = .default,
        verbose: Bool = false
    ) -> AsyncThrowingStream<AudioChunk, Error>
}

public enum HibikiSourceLanguage: String, CaseIterable, Sendable, Codable {
    case fr, es, pt, de
}

Bilis ng Sample: 24 kHz mono, kapwa input at output. Bilis ng Frame: 12.5 Hz (Mimi codec). Pinagmulan ng mga wika: FR / ES / PT / DE. Target language: EN. Itakda HIBIKI_GREEDY=1 Sa prosesong paglunsad para sa decoding na dekoding na reterministiko (matikes ang mga canaries ng CI).

Bangkutibidad sa Boses

Protocol para malaman ang boses.

public protocol VoiceActivityDetectionModel: AnyObject {
    var inputSampleRate: Int { get }
    func detectSpeech(audio: [Float], sampleRate: Int) -> [SpeechSegment]
}

Umiikot na Tagahanda

Protocol para sa mga end-of-turn classifier na isinangguni ng StreamingVADProcessor sa bawat kompirmadong VAD huminto.Ang isang VAD ay nakaririnig lamang ng katahimikan; ang isang turn-completion model ay nakikinig sa prosody ng buong salita, kaya ang isang mid-sentence na paghinto ay nagpapanatili sa ahente na naghihintay habang ang isang tapos na pangungusap ay nakakakuha ng kagyat na tugon. Mga mapa sa speech-core's ay nagpapanatili sa agent na naghihintay habang isang tapos na sentensiya. sc_turn_completion_vtable_t. Tingnan ang Smart Turn giya.

public protocol TurnCompletionProvider: AnyObject {
    /// Probability in [0, 1] that the turn is complete, given the audio of the
    /// turn so far (Smart Turn looks at the last 8 s).
    func turnCompleteProbability(audio: [Float], sampleRate: Int) throws -> Float
}

Mga sumusunod na uri: SmartTurnModel (Smart Turn v3.2)

" SpeakerEmbedingModel "

Protocol para sa tagapagsalita na nagdurulot ng pagkuha.

public protocol SpeakerEmbeddingModel: AnyObject {
    var inputSampleRate: Int { get }
    var embeddingDimension: Int { get }
    func embed(audio: [Float], sampleRate: Int) -> [Float]
}

Mga sumusunod na uri: WeSpeakerModel

Diarisasyong Tagapagsalita

Protocol para sa mga modelo sa pagbigkas na nag - aatas ng mga etiketa ng tagapagsalita sa mga bahaging audio.

public protocol SpeakerDiarizationModel: AnyObject {
    var inputSampleRate: Int { get }
    func diarize(audio: [Float], sampleRate: Int) -> [DiarizedSegment]
}

Mga sumusunod na uri: DiarizationPipeline (Pyannote), SortformerDiarizer

Maaring Magsalita

Ang pinalawig na diarisasyon protocol para sa mga makina na sumusuporta sa pagkuha ng mga target na bahagi ng tagapagsalita gamit ang isang reperensiyang embeding. hindi lahat ng makina ay sumusuporta dito (Sort imformer ay end-to-end at hindi gumagawa ng speaker embendings).

public protocol SpeakerExtractionCapable: SpeakerDiarizationModel {
    func extractSpeaker(audio: [Float], sampleRate: Int, targetEmbedding: [Float]) -> [SpeechSegment]
}

Mga sumusunod na uri: DiarizationPipeline (Pyannote lamang)

Mga Uring May Bahagi

ISANG Parokya

public struct AudioChunk {
    public let samples: [Float]   // PCM samples
    public let sampleRate: Int    // Sample rate (e.g. 24000)
}

Pag - uusap

public struct SpeechSegment {
    public let startTime: Float   // Start time in seconds
    public let endTime: Float     // End time in seconds
}

Maling Salita

public struct AlignedWord {
    public let text: String       // The word
    public let startTime: Float   // Start time in seconds
    public let endTime: Float     // End time in seconds
}

Diarized Segment

public struct DiarizedSegment {
    public let startTime: Float   // Start time in seconds
    public let endTime: Float     // End time in seconds
    public let speakerId: Int     // Speaker identifier (0-based)
}

Di - pagkakasundo

Isang parsed segment ng multi-speak na dialogue text na may opsyonal na speaker at emosyon tags. Ginagamit gamit ang DialogueParser at DialogueSynthesizer para sa CosyVoice3 dialogue synthesis.

public struct DialogueSegment: Sendable, Equatable {
    public let speaker: String?   // Speaker identifier ("S1", "S2"), nil for untagged
    public let emotion: String?   // Emotion tag ("happy", "whispers"), nil if none
    public let text: String       // Cleaned text to synthesize
}

DialogueParser

Parses multi-specker dialogue text na may inline speaker tags ([S1]) at mga emosyonal na tag ((happy)).

public enum DialogueParser {
    static func parse(_ text: String) -> [DialogueSegment]
    static func emotionToInstruction(_ emotion: String) -> String
}

Mga emosyong itinayo-in: happy/excited, sad, angry, whispers/whispering, laughs/laughing, calm, surprised, serious. Ang mga hindi kilalang tag ay dumadaan bilang mga instruksiyong freeform.

DialogueSynthesizer

Orchestrates multi-segment dialogue synthesis na may per-speaker voice cloning, mga puwang sa katahimikan, at crossfade.

public enum DialogueSynthesizer {
    static func synthesize(
        segments: [DialogueSegment],
        speakerEmbeddings: [String: [Float]],
        model: CosyVoiceTTSModel,
        language: String,
        config: DialogueSynthesisConfig,
        verbose: Bool
    ) -> [Float]
}

DialogueSynthesisConfig

public struct DialogueSynthesisConfig: Sendable {
    public var turnGapSeconds: Float      // Default: 0.2
    public var crossfadeSeconds: Float    // Default: 0.0
    public var defaultInstruction: String // Default: "You are a helpful assistant."
    public var maxTokensPerSegment: Int   // Default: 500
}

PeplineLLEM

Ang pagkomodelo ng wika at ang mga tubo ng boses ay nagdurugtong sa isang tulay LLM sa VoicePipeline ASR → LLM → TTS daloy.

public protocol PipelineLLM: AnyObject {
    func chat(messages: [(role: MessageRole, content: String)],
              onToken: @escaping (String, Bool) -> Void)
    func cancel()
}

Itinayong-in adjuster: Qwen3PipelineLLM mga tulay Qwen35MLXChat sa protocol na ito na may bahagyang paglilinis, pagpapawalang - bisa, at pag - asa ng mga parirala na natipon.

AudioIO

Reusable audio I/O manager na nag-aalis ng AVAudioEngine boilerplate. humawak ng mic catching, resampling, playback, at audio level metering.

let audio = AudioIO()
try audio.startMicrophone(targetSampleRate: 16000) { samples in
    pipeline.pushAudio(samples)
}
audio.player.scheduleChunk(ttsOutput)
audio.stopMicrophone()

AudioIO ay kinabibilangan ng StreamingAudioPlayer para sa TTS output at isang AudioRingBuffer para sa sinulid-ligtas na audio transfer sa pagitan ng paghuli at mga sinulid na calc2.

SystemAudioTAp

Tuusin ang sistemang output na naghahalo — kung ano ang sangkap Mac ay kasalukuyang naglalaro — bilang mono Float32 sa numero ng caller-piling sampol (Core Audio process taps, macOS 14.4+). Ang mono global tap ay hindi nagpapawalang-bisa sa kasalukuyang proseso sa pamamagitan ng default, kaya ang isang appiments sariling playback ay hindi kailanman muling-captured, at ito ay nakabalot sa isang pribadong aggregate device na naglalaman lamang ng tap.

let tap = SystemAudioTap()
try tap.start(targetSampleRate: 16000) { samples in
    pipeline.pushAudio(samples)
}
tap.stop()

Ang Capture ay nakaliligtas sa default-output-device switchs – ang panloob na resampler ay muling itinatayo kapag ang mixt rate ay nagbabago. Ang host app ay dapat ipahayag ang app NSAudioCaptureUsageDescription. Kung ang permiso sa pagrerekord ay hindi mapahihiwatig, ang isang tap ay maaari pa ring likhain ngunit makapaghahatid lamang ng katahimikan: manood ka lamang framesCaptured lumalaki habang nonSilentFrames ay nananatiling 0 at nabigong magsara.

Madalas na nagsasariling mga pinagmumulan

Inilantad ng dalawang grupong ito na may dalawang huli ang labis - labis na karga. CapturedAudioChunk nagdadala ng mono samples sa sampleRate At ang Isang Responsibilidad Mach hostTime para sa unang input frame. Dahil parehong gumagamit ng parehong host clock ang parehong pinagmulan, ang isang app ay maaaring panatilihin ang kanilang PCM hiwalay at order na kinuha transcript na mga pangyayari nang hindi pinagsasama ang audio.

try tap.startTimestamped(targetSampleRate: 16000) { systemChunk in
    systemPipeline.pushAudio(systemChunk.samples)
    recordSystemTime(systemChunk.hostTime)
}

let microphone = AudioIO(enableAEC: true, enablePlayback: false)
try microphone.startMicrophoneTimestamped(targetSampleRate: 16000) { micChunk in
    microphonePipeline.pushAudio(micChunk.samples)
    recordMicrophoneTime(micChunk.hostTime)
}

Para sa pakikinig-lamang na pagbihag, enableAEC: true ay nag-udyok ng Apple Voice Process bago ang format ng mikropono, at ang enablePlayback: false ay nagreresulta sa hindi nagamit na manlalaro. Sa macOS, ang device playback ay inaalis mula sa mga sampol ng mikropono at ang hindi pagsisimula ng AEC ay iniulat sa halip na nahuhulog pabalik sa hilaw na input.

Impremental na file input at pagkilala

CapturedAudioChunk Nagdadala rin ng monotonic frameIndex at isang isFinal marker. AudioFileLoader.stream ay gumagawa ng mga tipak na ito sa pangangailangan na may natitiklop na memorya, minsang may patuloy na estadong converter, at karaniwang ginagamit ang lahat ng input channel sa pamamagitan ng default. .first o .select([indices]) kung saan nalalaman ang paglupig ng channel.

StreamingRecognitionModel at StreamingRecognitionSession ay nagbibigay ng isang cache-preving incremental API sa ibayo ng Parakeet Streaming at Nemotron Core ML/MLX:

let source = AudioFileLoader.stream(
    url: inputURL,
    options: AudioFileStreamOptions(targetSampleRate: 16_000,
                                    chunkDuration: 0.32,
                                    channelSelection: .mixAll))
let session = try model.makeStreamingSession(language: "en-US")

for try await chunk in source {
    for update in try session.push(chunk) {
        render(update.text, final: update.isFinal)
    }
}
for update in try session.finish() {
    render(update.text, final: true)
}

" DEPieceModel "

Ibinabahaging mambabasa ng protobuf para sa Pagpapahintulot na Mag - asawa .model mga talaksan, mga buhay sa AudioCommon. Bawat module na kailangang i-decode judgePiece piraso (PersonaPlex, OmnilingualASR, hinaharap ASR / TTS ports) ay nagtatayo ng sarili nitong decoder sa ibabaw ng nag-iisang mambabasang ito sa halip na muling-implement ang protobuf wire format.

public struct SentencePieceModel: Sendable {
    public struct Piece: Sendable, Equatable {
        public let text: String
        public let score: Float
        public let type: Int32
        public var pieceType: PieceType? { get }
        public var isControlOrUnknown: Bool { get }
    }
    public enum PieceType: Int32 {
        case normal = 1, unknown = 2, control = 3,
             userDefined = 4, unused = 5, byte = 6
    }
    public let pieces: [Piece]
    public var count: Int { get }
    public subscript(_ id: Int) -> Piece? { get }
    public init(contentsOf url: URL) throws
    public init(modelPath: String) throws
    public init(data: Data) throws
}

Ginagamit ng: OmnilingualASR.OmnilingualVocabulary, PersonaPlex.SentencePieceDecoder. Saklaw ng 7 unit tests sa ZXQXZ Tests/AudioCommonTests/SentencePieceModelTests.

MLXCommon.SDPA

Ang mga naka-frade na dot-product na katulong sa atensiyon ay nagbabahagi sa ibayo ng bawat isa MLX " attention module "Qwen3-ASR / Qwen3-TTS / Qwen3-Chat / CosyVoice / PersonaPlex Ang bawat module ay may kani - kaniyang produksyon — ang SDPA ay humahawak lamang ng reconstructed → atensiyon → pagsamahin ang boilerplate.

public enum SDPA {
    // Flat [B, T, H*D] input: project/reshape happens inside
    public static func multiHead(
        q: MLXArray, k: MLXArray, v: MLXArray,
        numHeads: Int, headDim: Int, scale: Float,
        mask: MLXArray? = nil
    ) -> MLXArray

    // GQA / MQA variant with separate query and KV head counts
    public static func multiHead(
        q: MLXArray, k: MLXArray, v: MLXArray,
        numQueryHeads: Int, numKVHeads: Int, headDim: Int, scale: Float,
        mask: MLXArray? = nil
    ) -> MLXArray

    // Already-shaped [B, H, T, D] (RoPE / KV cache paths)
    public static func attendAndMerge(
        qHeads: MLXArray, kHeads: MLXArray, vHeads: MLXArray,
        scale: Float,
        mask: MLXArray? = nil
    ) -> MLXArray

    // Same, with ScaledDotProductAttentionMaskMode enum (newer API)
    public static func attendAndMerge(
        qHeads: MLXArray, kHeads: MLXArray, vHeads: MLXArray,
        scale: Float,
        mask: MLXFast.ScaledDotProductAttentionMaskMode
    ) -> MLXArray

    // Low-level head merge: [B, H, T, D] → [B, T, H*D]
    public static func mergeHeads(_ attn: MLXArray) -> MLXArray
}

Lahat ng mga reformed na tawag ay gumagamit ng -1 para sa stando dimensiyon kaya ang mga katulong ay bumubuo ng MLX.compile(shapeless:) graps na nag-iiba-iba ng stage sa runtime (e.g. Qwen3-TTS Talker aregressive decode).

HTTP API Server

Ang speech-server Inilalantad ng binaryo ang bawat modelo sa speech-swift bilang HTTP REST endpoints at isang WebSocket na endpower na nag-aambag sa toolpo ng toppoint OpenAI Realtime API. Ang mga modelo ay may kargang lazily sa unang hiling; magpasa ng mga ito --preload upang initin silang lahat sa simula.

swift build -c release
.build/release/speech-server --port 8080

# Preload every model at startup
.build/release/speech-server --port 8080 --preload

REST Endpoint

Wakas Pamamaraan Kahilingan Pagtugon
/transcribePOSTaudio/wav katawanJSON { text } (Qwen3-ASR)
/v1/audio/transcriptionsPOSTMultipart { file, model, response_format?, language?, prompt?, temperature? }JSON, teksto, verose JSONs, SRT, o VTT
/v1/audio/speechPOSTJSON { model, input, voice, response_format?, speed? }audio/wav o audio/pcm body
/speakPOSTJON { text, engine?, language?, voice? }audio/wav Katawan (Qwen3-TTS, CosyVoice), Kokoro)
/respondPOSTaudio/wav katawanaudio/wav katawan (PersonaPlex)
/enhancePOSTaudio/wav katawanaudio/wav katawan (DeepFilterNet3)
/vadPOSTaudio/wav katawanListahan ng mga bahagi ng katawan
/diarizePOSTaudio/wav katawanJSON DiarizedSegment listahan
/embed-speakerPOSTaudio/wav katawanJSON [Float] (256-dim)

/v1/audio/speech mapas standard TTS modelo at pangalan ng boses sa mga lokal na makina. Ito ay may default sa WAV; response_format: "pcm" return authorless 24 kHz mono PCM16-endial audio formatpictureed.

/v1/audio/transcriptions Tanggapin ang isang talaksang WAV bilang multipart na bumubuo ng datos at default sa {"text":"..."}; response_format ay maaari ring humiling ng teksto, pandiwa, JSON, SRT, o VT. On Apple, piliin ng modelong alyas ang isang lokal na alyas ASR Ang pakete speech-core server Linux at Windows ay gumagamit ng lazing na may kargang lazi Parakeet, tanggapin PCM16/24/32 o Float32 WAV, at ang mga takip ay nakasalansan 25 MiB at 10 minuto.

# Transcribe a file
curl -X POST http://localhost:8080/transcribe \
  --data-binary @recording.wav \
  -H "Content-Type: audio/wav"

# Synthesize speech
curl -X POST http://localhost:8080/speak \
  -H "Content-Type: application/json" \
  -d '{"text": "Hello world", "engine": "cosyvoice"}' \
  -o output.wav

# OpenAI-compatible transcription
curl http://localhost:8080/v1/audio/transcriptions \
  -F "[email protected];type=audio/wav" \
  -F "model=whisper-1"

# OpenAI-compatible speech synthesis
curl http://localhost:8080/v1/audio/speech \
  -H "Content-Type: application/json" \
  -d '{"model":"tts-1","voice":"alloy","input":"Hello world","response_format":"wav"}' \
  -o openai-output.wav

# Full speech-to-speech round trip
curl -X POST http://localhost:8080/respond \
  --data-binary @question.wav \
  -o response.wav

OpenAI Realtime API (/v1/realtime)

Ang WebSocket endpoint sa ws://host:port/v1/realtime Lahat ng mensahe ay JSON na may protocol na OpenAI Realtime type Distributor; audio payloads ay base64-encoded PCM16 sa 24 kHz mono.

Sa panahon ng malamig na modelong karga o mahabang henerasyon, ang server ay naglalabas ng magaang na realtime.keepalive JSON mga kaganapan at websocket pong control frames humigit-kumulang tuwing 15 segundo hanggang sa handa na ang model output. maaaring ipagwalang-bahala ng mga Client ang mga pangyayaring ito o ituring ang mga ito bilang mga industruksyon.

Client → Mga pangyayari sa Server

Pangyayari Layunin
session.updateConfigure engine, wika, boses, audio format, at opsyonal na server VAD
input_audio_buffer.appendIlagay ang base64 PCM16 fragment sa input features
input_audio_buffer.commitIlagay ang Walang - Papantay na audio para sa transcription
input_audio_buffer.clearItapon ang kasalukuyang input neutralation
response.create Humiling ng TTS synthesis para sa inilaang teksto/turo

Tagapagsilbi → Mga pangyayaring Client

Pangyayari Kahulugan
session.created Pagyanig ng kamay na kumpleto, default pagkaayos na inilalabas
session.updated Kinikilala kamakailan ng karamihan sa session.update
input_audio_buffer.speech_started Ang server VAD ay nakatuklas ng pasimula ng isang pagliko sa pagsasalita
input_audio_buffer.speech_stoppedNatapos ng server VAD ang pagliko pagkatapos ng katahimikan o ang takdang tagal ng pag - uusap
input_audio_buffer.committed Isangudio ang tumanggap at nag - usisa para sa transcription
conversation.item.input_audio_transcription.completed Ang resulta ng ASR ay ang pangwakas na salin ng teksto
response.audio.deltaBase64 PCM16 front of synthesisd audio
response.audio.done Wala nang mga audio cluster para sa tugong ito
response.done Sagot na ginawang finalized (metadata + latency stats)
errorError sa sobre na may type at message

Awtomatikong lumiko sa server VAD

Ilabas input_audio_buffer.commit Nananatiling hindi buo. Upang ang server ay maisara at kusang iikot ang server sa pamamagitan ng Silero VAD, pagsasaayos turn_detection. Ang server ay nagpapanatili lamang sa hiniling na pre-rol habang walang ginagawa, naglalabas ng mga talumpati simula/stop at gumagawa ng mga kaganapan nang maayos, at pwersa-close ng isang patuloy na aktibong pag-ikot sa max_turn_duration_ms.

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
    }
  }
}));

// Disable automatic turns and return to explicit commits:
// { type: 'session.update', session: { turn_detection: null } }
const ws = new WebSocket('ws://localhost:8080/v1/realtime');

// ASR: push audio, request transcription
ws.send(JSON.stringify({ type: 'input_audio_buffer.append', audio: base64PCM16 }));
ws.send(JSON.stringify({ type: 'input_audio_buffer.commit' }));
// → conversation.item.input_audio_transcription.completed

// TTS: request synthesis and stream audio deltas
ws.send(JSON.stringify({
  type: 'response.create',
  response: { modalities: ['audio', 'text'], instructions: 'Hello world' }
}));
// → response.audio.delta (repeated), response.audio.done, response.done

Ang server ay nakatira sa produktong AudioServer SPM. Isang halimbawang kliyenteng browser ay ipinadadala sa Examples/websocket-client.html — buksan ito sa tabi ng isang running server upang patakbuhin ang buong ASR + TTS round trip.

Modelong mga Pagpapababa ng Pabigat

Ang lahat ng modelo ay nai - download mula sa HuggingFace sa unang paggamit at cached sa ~/Library/Caches/qwen3-speech/. Ang AudioCommon module ay nagbibigay ng kabahaging HuggingFaceDownloader na humahawak ng download, caching, verification, at verification.

Mga retries ng download

Mga modelong tagakarga at download APIs tanggapin downloadOptions: DownloadOptions. onRetry tumanggap ng isang DownloadRetryEvent bago ang bawat pag - urong, na may kasamang likod modelId, attempt, maxAttempts, ang orihinal error, at retryInSeconds. nil ay nangangahulugang walang natitirang retries; ang kumpletong-cache fallback ay maaari pa ring magtagumpay.

Ang mga kalaparan ay sabay - sabay at hindi gumagalaw @Sendable, na walang pangunahing-aktor na garantiya. Ang Cancellation ay hindi lumilikha ng retry event. retryDelaysSeconds upang gawing kaugalian ang patakaran ([] nangangahulugang isang pagtatangka); ang maliwanag na argumentong API ay nauuna. Default trance counts at byte development ay naingatan din. Ang mga bigong pagtatangka ay na-crew sa antas ng notice sa pamamagitan ng direksyon AudioLog.download.

May Pakikipagtulungang Pagkansela

Para sa MLX transcription, Qwen3ASRModel.transcribeCheckingCancellation(audio:sampleRate:options:) mga paghahagis CancellationError Kapag ang gawaing pagpapawalang - bisa ay napansin bago pa man matapos ang pag - aalis, pag - eesposi, pag - aalis ng laman sa katawan, o isang hakbang na nagpapawalang - bisa. ang gawaing GPU na isinumite na ay maaaring matapos. transcribe at transcribeBatch Pinananatili ng mga API ang kanilang hindi-paghagis na pag-uugali at binabalewala ang gawain. speech-server ay gumagamit ng puntos ng venge-acware entry para sa Qwen3-ASR.

MOS-TTS-Nano

Ang MossTSNanoModel serializes requests at lumilikha ng mga sariwang CoreML estado para sa bawat sinasabi. synthestic and syntheticStream preserve stereo; Ang SpeakGenerationModel ay nagbabalik ng isang mono downmix. Pass language: nil. Streams ay nagtatapos sa isang walang laman na final marker.

import AudioCommon
import MossTTSNano

let model = try await MossTTSNanoModel.fromPretrained()
let reference = try await model.encodeReference(url: referenceURL)
let result = try await model.synthesize(
    text: "The weather is nice today.", reference: reference,
    options: MossTTSNanoOptions(maxFrames: 300, seed: 1))
try WAVWriter.writeStereo(left: result.left, right: result.right,
    sampleRate: 48000, to: outputURL)

MOS-TTS-Nano

Ang lokal na katutubong pahiwatig

Para sa 12B, ang paulit-ulit na katabing mga kasangkapan-tawag na pagsasara ng mga marker pagkatapos ng isang kumpleto, regulatoryong tawag ay nakukwenta sa pamamagitan ng tawag na iyon. Hindi sila lumilikha ng ibang tawag o pagbabago sa mga argumento nito. Ang mga stagealone marker at mga argumentong diperensiyal ay nananatiling mga pagkakamali; E4B ay nagpapanatili ng mahigpit na paghawak.

Upang mapanatili ang bigong katutubong mga kahilingan sa chat, set failureCaptureDirectory Ang direktor ay hindi naka - default, at dapat na hindi ito kasama ng iba pang mga direktor; ang mga bagong direktory ay gumagamit ng mga bagong direktor 0700 at ang mga talaksang bigo ay gumagamit 0600. Ang mga talaksan ay kinabibilangan ng eksaktong request body, request ID at error. Completed 12B generations ay nagpapanatili rin ng iginawad na advanced, token IDs, hilaw output at top katwiran bago ang parps. E4B fails ay walang hilaw na rekord ng henerasyon. Ang mga lokal na file na ito ay naglalaman ng mga pagkakamali sa pag-uusap at kagamitan; ang HTTTP ay hindi kasama ang mga ito.

Gemma4UnifiedChat.generateResponse tanggapin ang isang opsyonal na onGeneration callback na may Gemma4GenerationTrace. Ang callback ay tumatakbo bago ang kagamitang parsing, kabilang na kapag ang pagkumpletong iyon ay tinanggihan.Ang pag-ulat ay hindi nagbabago ng mga skripsepsipsipiko o kasangkapan.

Ipinintang ng ahenteng opsyonal na Direktoryo ang isang nakadispley Gemma 4 12Ipinakilala INT4 modelo ng teksto sa tabi E4B. Gumamit ng modelo: "gemma4-12b-it" para makipag - usap sa katutubong mga kagamitan, ang resulta'y kasaysayan, at pagpapawalang - bisa. E4B ay maaari pang makuha para sa iba pang mga kahilingan. Gemma4UnifiedChat ginagamit ang pindutan MLX Ang pagpapatupad ng teksto at paglalabas ng bawat request na KV cache. Ang tugon parsing ay nag-aalis ng channel deliters mula sa ibinalik na teksto. ang mga overpled tool-call revisors ay tinatanggihan bilang mga hindi maayos na tugon. Gemma 4 12B, ang mga tool-message content ay nag-iingat sa JSON bilang teksto, na nagtutugma sa checkpoint chat template.

Ang pinagmumulan ay tumatanggap --inference-manifest mga modelo.json upang ikarga ang nakatanghal Gemma 4 E4B INT4, VoxCPM2, buo Whisper Large-v3, at Silero VAD. Ang serbisyong ito ay nagsisimula at tumatanggi sa hindi katugmang huwarang pagkakakilanlan.

VoxCPM2 ay sumusuporta sa pag-aayos ng timbang: .float16 Para sa isang nonquantized checkpoint. Ang pangunahing mga parameter nito ay gumagamit ng mga pangunahing parameter FP16; Ang AudioVAE at ang ilang kalkulasyon ay nananatili FP32. INT8 Ang mga checkpoint ay tinatanggihan dahil sa pamamaraang ito.

Gemma4ConversationMessage, Gemma4Tool, at ang paglikha ng Response ay nag-iingat ng mga katutubong mga deklarasyon ng kasangkapan, argumento, at resultang kasaysayan. Ang inferenceCancellationToken ay nagpapawalang bisa sa henerasyon nang kooperatiba. Silero ay gumagawa sa IndependentStream na magbukod ng estado, at ang prosesoChacking influsions.

Whisper ASRModel. mula sa Direktory mga karga na itinanghal nang buo Large-v3 CoreML mga bungkos. Ang 32-layer decoder ay maaaring magtayo ng prefix nito nang walang TextDecoderContPrefill.mlmodelc and releases per-steep tempories. Ang default Whisper CLI ay nananatiling model.

Ang katutubong serbisyo serializes chat, synthesis, at transcription; lightight VAD ay may hiwalay na stream state. Gemma prefill ay gumagamit ng 256-token counsions, request KV state ay inilabas, at ang MLX cache ay naka-crew sa 128 MiB na may isang 20 GiB na limitasyon.

Pagsasalita na may kasamang agos: tunay na nagbabalik ang NDJSON audio na mga pangyayari sa 48 KHz, sinundan ng ginawa o pagkakamali. Cancel by requestID sa /v1/inference/cancel. HAT /v1/ kawalang - galang/kabisayaan at /v1/inference/provence report model proccious, parameter dtypes, asset pins, at memory counters.

speech-server --inference-manifest models.json --port 8080
POST /v1/inference
{"operation":"chat","model":"gemma4-e4b-it","requestID":"chat-1","messages":[{"role":"user","content":"Hello"}],"maxTokens":128,"temperature":0}

chat: gemma4-e4b-it
speech: voxcpm2
transcribe: whisper-large-v3
vad: silero-vad

Audio: audioBase64 (mono PCM16), sampleRate
VAD: streamID, reset, endStream; 512 samples/frame at 16000 Hz
Tools: name, description, parameters
Tool call: id, name, arguments
Tool result: role="tool", toolCallID, content

Optional model pagmamay-ari

Nagbibigay ang SpeechRuntime ng kabahaging pagkarga, cancellable FIFO accounted at serialized kill. ang Qwen3ASRRuntime ay pumipili ng MLX o buong CoreML sa pamamagitan ng mga detalyadong direksyon; ang mga katutubong bandilang API at CLI ay nananatiling makukuha.

Ang audio server ay humahawak ng isang bitayan sa pamamagitan ng bawat kumpletong kahilingan, kabilang ang streeted output, na may hanggang 32 requests naghihintay. ang ASR failures ay gumagawa ng mga pagkakamaling HTTP o WebSocket error events; ang mga tanggap na walang laman na transcription ay nananatiling matagumpay.Ang mga playback reservement ay nag-apaw ng mga sampol.Ang mga modelong creached at ang mga champling playback audio ay sumasakop pa rin sa memorya.

import Qwen3ASRRuntime

let runtime = Qwen3ASRRuntime(descriptor: Qwen3ASRDescriptors.small)
let text = try await runtime.transcribe(audio: samples, sampleRate: 16000)
try await runtime.unload()

Voxtral TTS

Voxtral 4B TTS 2603 ay lokal na tumatakbo sa Apple Silicon sa pamamagitan ng Voxtral TTS module: 20 preseted voices, siyam na wika, at 24 kHz mono speech.

import VoxtralTTS

let model = try await VoxtralTTSModel.fromPretrained()
for try await chunk in model.generateStream(text: "Hello, welcome to Voxtral.", voice: "casual_male") {
    print(chunk.frameIndex, chunk.samples.count, chunk.isFinal)
}

Ang mga preset voices lamang; reference-audio cloning ay hindi makuha. Ang audio output ay dumadaloy sa SDK, CLI, WebSocket at HTTP PCM. Isumite ang kumpletong input text up front. Ang mga model weights ay gumagamit ng CC BY-NC 4.0.

import AudioCommon

let player = StreamingAudioPlayer()
player.skipInitialSilence = false

Basahin ang Voxtral TTS guide