Maskinoversættelse · Engelsk original

API og protokoller

Indfødt Apple runtime · PocketTTS

PocketTTS tilføjer indfødt CoreML talesyntesse til speech-swift. Alle trin standard til CPU- kun udførelse. Den engelske Alba forudindstillet streams 1,920- prøvesæt på 24 kHz (80 ms per frame).

Brug af Swift og 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)
}

Den AudioCommon modul definerer model- agnostic protokoller og delte typer. Enhver ensrettet model kan bruges skiftevis gennem disse grænseflader.

Protokoloversigt

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

SpeechAnerkendelse Model

Protokol for speech-to- tekst modeller.

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
}

Konformeringstyper: Qwen3ASRModel, WhisperASRModel, ParakeetASRModel, ParakeetStreamingASRModel, OmnilingualASRModel (CoreML), OmnilingualASRMLXModel (MLX)

SpeechGenerationModel

Protokol for lære- to- tale modeller.

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() har en standard implementering, der wraps generate() som et enkelt stykke. Modeller med sand streaming (fx Qwen3-TTS) tilsidesætte det.

Konformeringstyper: Qwen3TTSModel, CosyVoiceTTSModel, VoxCPM2TTSModel, KokoroTTSModel, IndexTTS2TTSModel

IndexTTS2TTSModel tilføjer en reference- audio generate overbelastning for zero-shot voice kloning og anvendelser IndexTTS2SynthesisOptions for tale- rate og pause kontrol.

Qwen3-TTS lokal indlæsning

fromLocal validerer nødvendige filer og checkpoint shard fuldstændighed, så stammer modelstørrelse, kvantisering og arkitektur fra config.jsonDen valgfrie configuration værdi er kun en fallback for udeladte metadata; misdannede eller modstridende metadata kaster Qwen3TTSLoadingError.invalidConfiguration før modeltildelingen.

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
Hukommelsespolitik

fromLocal standard til .none, så det ændrer ikke proces- wired Metal wired- memory limit. fromPretrained holder sin .pin(fraction: 0.9) standard. Begge forudtrænede læssere accepterer en separat tokenizerCacheDir.

ForceAlignmentModel

Protokol for tilpasning af tidsstempler på ord- niveau.

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

SpeechToSpeechModel

Protokol for talemålemodeller.

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

Konformeringstyper: PersonaPlexModel

HibikiTranslateModel

Speech- to- tale oversættelse driver. Er ikke i overensstemmelse med SpeechToSpeechModel Da kontrakten er forskellig: input og output er forskellige sprog, output længde er variabel (EOS-drevet, begrænset på max(tSrc * 5/2, tSrc + 20) trin - omtrent 1.0- 1.6 × kildevarighed på FLEURS- stil klip), og der er en parallel tekst- token stream ved siden af lyden. Fuld guide →

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
}

Prøvesats: 24 kHz mono, både input og output. Rammefrekvens: 12.5 Hz (Mimi codec). Kildesprog: FR / ES / PT / DE. Målsprog: EN. Set HIBIKI_GREEDY=1 ved proceslancering for deterministisk argmax-afkodning (matcher CI-kanarierne).

VoiceActivityDetectionModel

Protokol til afsløring af stemmeaktivitet.

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

TurnComptionProvider

Protokol for slutteklassifikatorer, der høres af StreamingVADProcessor på hver bekræftet VAD pause. En VAD kun hører stilhed; en turn- completing model lytter til prosody af hele ytterance, så en midtpunkts pause holder agenten venter mens en færdig sætning får et øjeblikkeligt svar. Kort til speech-core 's sc_turn_completion_vtable_t. Se Smart Turn guide.

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
}

Konformeringstyper: SmartTurnModel (Smart Turn v3.2)

SpeakerEmbeddingModel

Protocol for speaker indlejring ekstraktion.

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

Konformeringstyper: WeSpeakerModel

SpeakerDiarizationModel

Protokol for højttaler diarization modeller, der tildeler højttaler etiketter til lydsegmenter.

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

Konformeringstyper: DiarizationPipeline (Pyannote), SortformerDiarizer

SpeakerExtractionCapable

Udvidet diariseringsprotokol for motorer, der understøtter udtrækning af en målhøjttalers segmenter ved hjælp af en reference indlejring. Ikke alle motorer understøtter dette (Sortformer er ende- to- end og producerer ikke højttalerindlejringer).

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

Konformeringstyper: DiarizationPipeline (kun Pyannote)

Fælles typer

AudioChunk

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

SpeechSegment

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

AlidredWord

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
}

DiarizedSegment

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

DialogueSegment

Et fortolket segment af multi-højtaler dialog tekst med valgfri højttaler og følelser tags. Bruges med DialogueParser og DialogueSynthesizer for CosyVoice3 dialogsyntese.

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 multihøjttalerdialogtekst med inline højttalertags ([S1]) og følelser tags ((happy)).

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

Bygge- i følelser: happy/excited, sad, angry, whispers/whispering, laughs/laughing, calm, surprised, serious. Ukendt mærker passerer igennem som freeform instruktioner.

DialogueSynthesizer

Orkestrerer multisegmentdialog syntese med per- højtaler stemme kloning, stilhed huller, og crossfade.

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

DialogueSynthesiConfig

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
}

PipelineLLM

Protokol for sprogmodel integration med voice pipelines. Broer en LLM til VoicePipeline ASR → LLM R. TTS flow.

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

Byg - i adapter: Qwen3PipelineLLM broer Qwen35MLXChat til denne protokol med token oprydning, annullering, og afventende sætning ophobning.

AudioIO

Genanvendelig lyd I / O manager, der eliminerer AVAudioEngine Mesterplate. Håndterer mic capture, resampling, afspilning, og audio niveau måling.

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

AudioIO omfatter en StreamingAudioPlayer for TTS output og en AudioRingBuffer til trådsikker overførsel af lyd mellem indfangnings- og indkøringstråde.

SystemAudioTap

Opfanger systemets output mix - hvad Mac er i øjeblikket spiller - som mono Float32 på en caller- valgt prøve rate (Core Audio process haner, macOS 14.4+). Mono global tap udelukker den aktuelle proces som standard, så en app 's egen afspilning er aldrig genfanget, og det er pakket i en privat aggregat enhed, der kun indeholder hanen.

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

Capture overlever default- output- enhedskontakter - den interne resampler genopbygges, når mixhastigheden ændres. Værtsappen skal erklære NSAudioCaptureUsageDescription. Hvis optagelse tilladelse nægtes, kan et hank stadig oprettes endnu levere kun stilhed: se framesCaptured vokse, mens nonSilentFrames forbliver 0 og mislykkes lukket.

Tidsbegrænsede uafhængige kilder

Begge indfanger klasser afslører tidsstemplede overbelastninger. CapturedAudioChunk bærer mono samples på sampleRate plus en valgfri Mach hostTime for den første inddata ramme. Fordi begge kilder bruger samme vært ur, kan en app holde deres PCM separate og orden afledt udskrift begivenheder uden at blande lyd.

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

For at lytte, kun fange, enableAEC: true aktiverer Apple Voice Processing, før mikrofonen format læses, og enablePlayback: false udelader den ubrugte spiller. På macOS fjernes afspilningen af enheden fra mikrofonens prøver, og der rapporteres om manglende start af AEC i stedet for at falde tilbage til råinput.

Input og genkendelse af flere filer

CapturedAudioChunk også bærer en monotonisk frameIndex og en isFinal markør. AudioFileLoader.stream producerer disse stykker på efterspørgsel med afgrænset hukommelse, resamples én gang med vedvarende konverter tilstand, og gennemsnit alle input kanaler som standard. .first eller .select([indices]) når kanal routing er kendt.

StreamingRecognitionModel og StreamingRecognitionSession give en cache-conservation incremental API på tværs af Parakeet Streaming og 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)
}

SentencePieceModel

Fælles protobuflæser til SentencePiece .model filer, bor i AudioCommon. Hvert modul, der har brug for at afkode SentenePiece stykker (PersonaPlex, OmnilingualASR, fremtidige ASR / TTS porte) bygger sin egen dekoder på toppen af denne enkelt læser i stedet for at gen- gennemføre 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
}

Anvendt af: OmnilingualASR.OmnilingualVocabulary, PersonaPlex.SentencePieceDecoder. Dækket af 7 enhedstests i Tests/AudioCommonTests/SentencePieceModelTests.

MLXAPP.SDPA

Skalerede dot- produkt opmærksomhed hjælpere delt på tværs af hver MLX opmærksomhed modul (Qwen3-ASR / Qwen3-TTS-Qwen3-Chat, CosyVoice eller PersonaPlex og OmnilingualASR). Hvert modul holder sine egne fremskrivninger - SDPA kun håndterer omformningen → opmærksomhed → fletning Medicerplate.

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
}

Alle omformer kald brug -1 for batch dimension, så hjælpere komponere med MLX.compile(shapeless:) Grafer, der varierer batch ved runtime (f.eks. Qwen3-TTS Talker auto regressive dekode).

HTTP API Server

Den speech-server binær udsætter hver model i speech-swift som HTTP REST endepunkter plus et WebSocket endpoint, der gennemfører OpenAI Realtime API. Modeller er indlæst dovenskab på første anmodning; pass --preload at varme dem alle ved opstart.

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

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

REST Endpoints

SlutpunktMetodeAnmodningRespons
/transcribePOSTaudio/wav organJSON { text } (Qwen3-ASR)
/v1/audio/transcriptionsPOSTMultipart { file, model, response_format?, language?, prompt?, temperature? }JSON, tekst, verbose JSON eller SRT eller VTT
/v1/audio/speechPOSTJSON { model, input, voice, response_format?, speed? }audio/wav eller audio/pcm organ
/speakPOSTJSON { text, engine?, language?, voice? }audio/wav organ (Qwen3-TTS, CosyVoice og Kokoro)
/respondPOSTaudio/wav organaudio/wav organ (PersonaPlex)
/enhancePOSTaudio/wav organaudio/wav organ (DeepFilterNet3)
/vadPOSTaudio/wav organJSON-segmentliste
/diarizePOSTaudio/wav organJSON DiarizedSegment liste
/embed-speakerPOSTaudio/wav organJSON [Float] (256- dim)

/v1/audio/speech kortlægger standard TTS model og talenavne til lokale motorer. Det er standard for WAV; response_format: "pcm" returnerer hovedløs 24 kHz mono PCM16 little- endian audio. Ikke-understøttede komprimerede formater afvises eksplicit.

/v1/audio/transcriptions accepterer en WAV fil som multipart form data og standard til {"text":"..."}; response_format kan også anmode om tekst, verbose JSON, SRT eller VTT. På Apple, model aliaser vælge en lokal ASR motor. Den emballerede speech-core server tændt Linux og Windows bruger lasagtigt indlæst Parakeet, accepterer PCM16/24/32 eller Float32 WAV, og hætter uploads på 25 MiB og 10 minutter.

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

WebSocket endpoint ved ws://host:port/v1/realtime implementerer OpenAI Realtime protokollen. Alle meddelelser er JSON med en type Diskriminator; lyd nyttelast er base64-encoded PCM16 på 24 kHz mono.

Under kolde modelbelastninger eller lange generationer udsender serveren letvægts realtime.keepalive JSON begivenheder og websocket pong kontrol rammer omtrent hver 15 sekunder indtil model output er klar. Klienter kan ignorere disse begivenheder eller behandle dem som aktivitetsindikatorer.

Klient → Serverbegivenheder

BegivenhedFormål
session.updateIndstil motor, sprog, stemme, lydformat og valgfri server VAD
input_audio_buffer.appendTilsæt en base64 PCM16-del til inputbufferen
input_audio_buffer.commitIndsend den buffered lyd til transskription
input_audio_buffer.clearKassér den aktuelle inputbuffer
response.createAnmodning om TTS syntese for den leverede tekst / instruktioner

Server → Klientbegivenheder

BegivenhedBetydning
session.createdHåndtryk komplet, standardkonfiguration udsendt
session.updatedSenest session.update anerkendt
input_audio_buffer.speech_startedServer VAD detekterede begyndelsen af en tale drejning
input_audio_buffer.speech_stoppedServer VAD sluttede drejning efter stilhed eller varighed grænse
input_audio_buffer.committedLyd accepteret og i kø til transskription
conversation.item.input_audio_transcription.completedASR resultat med endelig udskrift tekst
response.audio.deltaBase64 PCM16 stykke af syntetiseret lyd
response.audio.doneIkke flere lydstykker til dette svar
response.doneResponse finalized (metadata + latency statistik)
errorFejlkonvolut med type og message

Automatiske drejninger med server VAD

Ekplicit input_audio_buffer.commit forbliver standard. For at lade serveren lukke og transskribere drejes automatisk med Silero VAD, konfigurere turn_detection. Serveren holder kun den ønskede pre-roll mens tomgang, udsender tale start / stop og begå begivenheder i rækkefølge, og kraft- lukker en kontinuerlig aktiv drejning på 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

Serveren bor i AudioServer SPM produkt. Et eksempel browser klient sendes på Examples/websocket-client.html - åbne den sammen med en kørende server for at køre hele ASR + TTS rundturen.

Model Downloads

Alle modeller downloades fra HuggingFace ved første brug og cache i ~/Library/Caches/qwen3-speech/. AudioCommon modul giver en delt HuggingFaceDownloader der håndterer download, caching og integritetskontrol.

Download forsøg igen

Model læssere og download API 'er acceptere downloadOptions: DownloadOptions. onRetry modtager en DownloadRetryEvent før hver backoff, med modelId, attempt, maxAttempts, originalen error, og retryInSeconds. nil betyder, at der ikke er nogen tilbageværende; komplet-cache fallback kan stadig lykkes.

Callbacks er synkrone og @Sendable, uden main- actor garanti. Annullering producerer ingen prøve begivenhed. Sæt retryDelaysSeconds at tilpasse politikken ([] betyder et forsøg); det eksplicitte download API argument har forrang. Standardforsøg tæller og byte fremskridt er bevaret. Fejlslagne forsøg er også logget på opslagsniveau gennem AudioLog.download.

Annullering af samarbejde

For MLX transskription, Qwen3ASRModel.transcribeCheckingCancellation(audio:sampleRate:options:) kaster CancellationError når opgaveaflysning observeres før feature extraction, kodning, dekoderpræfill eller et dekodertrin. GPU arbejde, der allerede er indsendt, kan afslutte. Synkron transcribe og transcribeBatch Api 'er bevarer deres ikke-kaste adfærd og ignorere opgave annullering. speech-server bruger annullerings-aware indgang for Qwen3-ASR.

MOSS- TTS- Nano

MossTTSNanoModel serialiserer anmodninger og skaber frisk CoreML tilstand for hver ytter. syntetisering og synthesize Stream bevare stereo; SpeechGenerationModel returnerer en mono downmix. Pass sprog: nul. Streams slutter med en tom sidste markør.

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)

MOSS- TTS- Nano

Lokal indfødt inferens

For 12B, gentagne tilstødende værktøjs- call lucking markører umiddelbart efter et komplet, valideret opkald forbruges med dette opkald. De skaber ikke et andet opkald eller ændre sine argumenter. Standalone markører og misdannede argumenter forbliver fejl; E4B bevarer streng håndtering.

For at beholde fejlbehæftede native chat-forespørgsler, sæt failureCaptureDirectory i inferens manifest. Fanget er som standard slukket. Mappen skal nægte gruppe og anden adgang; nye mapper bruges 0700 og fejlfiler bruger 0600. Filer omfatter den nøjagtige anmodning organ, anmode om ID og fejl. Færdiggjort 12B generationer også beholde den afleverede prompt, token id 'er, rå output og stop grund før fortolkning. E4B fejl har ingen rå generation rekord. Disse lokale filer indeholder samtale og værktøj indhold; HTTP fejl og succesfulde anmodninger ikke omfatter dem.

Gemma4UnifiedChat.generateResponse accepterer en valgfri onGeneration callback med en Gemma4GenerationTrace. Callback kører før værktøj fortolkning, herunder når denne afslutning er afvist. Registrering ændrer ikke prøveudtagning eller accepteret værktøj syntaks.

Valgfri agentDirectory indlæser en iscenesat Gemma 4 12B Ensartet INT4 tekstmodel ved siden af E4B. Brug model: "gemma4-12b-it"for chat med indfødte værktøjer, resultat historie, og annullering. E4B forbliver til rådighed for andre anmodninger. Gemma4UnifiedChat bruger den fæstnede MLX tekst implementering og frigiver hver anmodning KV cache. Response parsing fjerner kanal afgrænsere fra returnerede tekst. Orphoned tool- call terminatorer afvises som misdannede svar. Gemma 4 12B, værktøjs- message indhold bevarer JSON som tekst, der matcher checkpoint chat skabelonen.

Kildeopbygninger accepterer --inference-manifest models.json at indlæse iscenesat Gemma 4 E4B INT4, VoxCPM2, fuld Whisper Large-v3, og Silero VADDenne tjeneste starter offline og afviser uforenelige model identiteter.

VoxCPM2 understøtter vægtPræcision: .float16 for et ukvantiseret checkpoint. Dens vigtigste parametre bruger FP16; AudioVAE og nogle beregninger forbliver FP32. INT8 checkpoints afvises for denne tilstand.

Gemma4ConversationMessage, Gemma4Tool og generateResponse bevare indfødte værktøjer erklæringer, argumenter og resultathistorie.InferenceCancellationToken annullerer generationen samarbejde. Silero makeIndependenStream isolater stat, og procesChunkThroing udbreder inferensfejl.

Whisper ASRModel.fromDirectory ladninger iscenesat fuld Large-v3 CoreML bundter. 32- layer dekoder kan bygge sin præfiks uden TextDecoderContextPrepill.mlmodelc og frigiver per- step temporaries. Standard Whisper CLI model forbliver Turbo.

Den indfødte service serialiserer chat, syntese og transskription; letvægts VAD har separat stream tilstand. Gemma prefill bruger 256- token batcher, anmodning KV tilstand er frigivet, og MLX cache er begrænset til 128 MiB med en 20 GiB tildelingsgrænse.

Tale med stream: true returnerer NDJSON audio events på 48 kHz, efterfulgt af gjort eller fejl. Annullér af request at /v1/ inferens / aflys. GET /v1/ inferens / kapaciteter og /v1/ inferens / herkomst rapport model identiteter, parameter dtypes, aktiv pins, og 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

Valgfri modelejerskab

SpeechRuntime giver delt indlæsning, annullerbar FIFO optagelse og serialiseret udførelse. Qwen3ASRRuntime vælger MLX eller fuld CoreML via eksplicitte deskriptorer; indfødte API 'er og CLI-flag forbliver tilgængelige.

Lydserveren har en udførelsestilladelse gennem hver komplet anmodning, herunder streamet output, med op til 32 anmodninger venter. ASR fejl producerer HTTP fejl eller WebSocket fejlbegivenheder; gyldige tomme udskrifter forbliver vellykket. Playback bevarer overløb prøver. Cached modeller og venter afspilning lyd stadig optager hukommelse.

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 kører lokalt Apple Silicon gennem Voxtral TTS-modulet: 20 forudindstillet stemmer, ni sprog, og 24 kHz mono tale.

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

Foretag kun stemmer; reference- audio kloning er ikke tilgængelig. Lydoutput strømme gennem SDK, CLI, WebSocket og HTTP PCM. Levere den komplette input tekst op foran. Model vægte bruge CC BY-NC 4.0.

import AudioCommon

let player = StreamingAudioPlayer()
player.skipInitialSilence = false

Læs vejledningen Voxtral TTS