Maskinoversettelse · Engelsk original
API og protokoller
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).
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)
}Modulen AudioCommon definerer modell-agnostiske protokoller og delte typer. Enhver samsvarende modell kan brukes utskiftelig gjennom disse grensesnittene.
Protokol Oversikt
┌─────────────────────────────────────────────────────────┐
│ AudioCommon │
│ │
│ AudioChunk SpeechGenerationModel (TTS) │
│ AlignedWord SpeechRecognitionModel (STT) │
│ SpeechSegment ForcedAlignmentModel │
│ SpeechToSpeechModel │
│ VoiceActivityDetectionModel (VAD) │
│ TurnCompletionProvider (EOT) │
│ SpeakerEmbeddingModel │
│ SpeakerDiarizationModel │
│ SpeakerExtractionCapable │
└─────────────────────────────────────────────────────────┘SpeechRecensionModel
Protokoll for tale-til-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
}
Forenlige typer: Qwen3ASRModel, WhisperASRModel, ParakeetASRModel, ParakeetStreamingASRModel, OmnilingualASRModel (CoreML), OmnilingualASRMLXModel (MLX)
TaleGenerationModel
Protokoll for tekst-til-speech 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 implementasjon som wraps generate() som en enkelt del. Modeller med sann streaming (f.eks. Qwen3-TTS) overstyrer den.
Forenlige typer: Qwen3TTSModel, CosyVoiceTTSModel, VoxCPM2TTSModel, KokoroTTSModel, IndexTTS2TTSModel
IndexTTS2TTSModel legger til en referanse-audio generate overbelastning for null-shot stemmekloning og bruker IndexTTS2SynthesisOptions for talerate- og pausekontroller.
Qwen3-TTS lokal lasting
fromLocal validerer nødvendige filer og kontrollpunktshard-fullføring, deretter stammer modellstørrelse, kvantisering og arkitektur fra config.json. Den valgfrie configuration verdien er bare en reserveverdi for utelatt metadata; feilaktige eller motstridende metadatakast Qwen3TTSLoadingError.invalidConfiguration før modelltildeling.
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
fromLocal standard til .none, så det endrer ikke prosessen-vidt Metal wired-hukommelsesgrense. fromPretrained holder sin .pin(fraction: 0.9) standard. Begge forhåndsutdannede lasere aksepterer en egen tokenizerCacheDir.
TvungetAjustmentModel
Protokol for ord-nivå tidsstempeljustering.
public protocol ForcedAlignmentModel: AnyObject {
func align(audio: [Float], text: String, sampleRate: Int, language: String?) -> [AlignedWord]
}
TaleTo speelingModel
Protokoll for tale-til-speech dialogmodeller.
public protocol SpeechToSpeechModel: AnyObject {
var sampleRate: Int { get }
func respond(userAudio: [Float]) -> [Float]
func respondStream(userAudio: [Float]) -> AsyncThrowingStream<AudioChunk, Error>
}
Samarbeidstyper: PersonaPlexModel
HibikiTranslateModel
Speech-to-speech oversettelsesdriver. Oversettelsesdriver er ikke i samsvar med SpeechToSpeechModel fordi kontrakten er forskjellig: inngang og utgang er forskjellige språk, er utgangslengden variabel (EOS-drevet, dekket på max(tSrc * 5/2, tSrc + 20) trinn - ca. 1.0-1.6× kilde varighet på FLEURS-stil klipp), og det er en parallell tekst-tokenstrøm ved siden av lyden. Full 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øvehastighet: 24 kHz-mono, både inngang og utgang. Rammerate: 12.5 Hz (Mimi codec). Kildespråk: FR / ES / PT / DE. Målspråk: EN. Sett HIBIKI_GREEDY=1 ved prosess lansering for deterministisk argmax dekoding (samler CI-kanariene).
VoiceActivity DefinitionModel
Protokol for deteksjon av stemmeaktivitet.
public protocol VoiceActivityDetectionModel: AnyObject {
var inputSampleRate: Int { get }
func detectSpeech(audio: [Float], sampleRate: Int) -> [SpeechSegment]
}
TurnClubProvider
Protokol for sluttklassifiseringsklassifisering som konsulteres av StreamingVADProcessor på hver bekreftet VAD pause. En VAD hører bare stillhet; en tur-fullføringsmodell lytter til prosodien til hele uttalelsen, så en midt-sentens pause holder agenten venter mens en ferdig setning får et øyeblikkelig svar. Kart til speech-cores sc_turn_completion_vtable_t. Se den 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
}
Samarbeidstyper: SmartTurnModel (Smart Turn v3.2)
SpeakerEinbyggingModel
Protokoll for utvinning av høyttalere.
public protocol SpeakerEmbeddingModel: AnyObject {
var inputSampleRate: Int { get }
var embeddingDimension: Int { get }
func embed(audio: [Float], sampleRate: Int) -> [Float]
}
Samarbeidstyper: WeSpeakerModel
SpeakerDiarizationModel
Protokol for høyttaler diariseringsmodeller som tildeler høyttalermerker til lydsegmenter.
public protocol SpeakerDiarizationModel: AnyObject {
var inputSampleRate: Int { get }
func diarize(audio: [Float], sampleRate: Int) -> [DiarizedSegment]
}
Samarbeidstyper: DiarizationPipeline (Pyannote), SortformerDiarizer
SpeakerExtractionCapable
Utvidet diariseringsprotokoll for motorer som støtter å trekke ut målhøyttalerens segmenter ved hjelp av en referanseinnbygging. Ikke alle motorer støtter dette (Sortformer er slutt-til-ende og produserer ikke høyttalerinnbygginger).
public protocol SpeakerExtractionCapable: SpeakerDiarizationModel {
func extractSpeaker(audio: [Float], sampleRate: Int, targetEmbedding: [Float]) -> [SpeechSegment]
}
Conforming typer: DiarizationPipeline (Pyannote bare)
Delte 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
}
Justert ord
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)
}
DialogSegment
Et tolket segment av multi-høyttaler dialogtekst med valgfrie høyttaler- og følelserstagger. Brukt 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
}
DialogParser
Tolker flerspråklig dialogtekst med innlinjehøyttalertagger ([S1]) og følelsestagger ( (happy)).
public enum DialogueParser {
static func parse(_ text: String) -> [DialogueSegment]
static func emotionToInstruction(_ emotion: String) -> String
}
Innbyggede følelser: happy/excited, sad, angry, whispers/whispering, laughs/laughing, calm, surprised, serious. Ukjente tagger passerer gjennom som freeform instruksjoner.
DialogSynthesizer
Orkesterer fler-segment dialog syntese med per-speaker stemme kloning, stillhet hull og crossfade.
public enum DialogueSynthesizer {
static func synthesize(
segments: [DialogueSegment],
speakerEmbeddings: [String: [Float]],
model: CosyVoiceTTSModel,
language: String,
config: DialogueSynthesisConfig,
verbose: Bool
) -> [Float]
}
Dialog SynteseConfig
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
Protokoll for språkmodellintegrasjon med stemmerørledninger. Broer en LLM til VoicePipélines ASR → LLM → TTS flyt.
public protocol PipelineLLM: AnyObject {
func chat(messages: [(role: MessageRole, content: String)],
onToken: @escaping (String, Bool) -> Void)
func cancel()
}
Built-in adapter: Qwen3PipelineLLM broer Qwen35MLXChat til denne protokollen med token opprydding, kansellering og avventende frase akkumulering.
AudioIO
Reusable lyd I/O manager som eliminerer AVAudioEngine kjeleplate. Hanterer mikrofon fangst, resampling, avspilling og lydnivåmåling.
let audio = AudioIO()
try audio.startMicrophone(targetSampleRate: 16000) { samples in
pipeline.pushAudio(samples)
}
audio.player.scheduleChunk(ttsOutput)
audio.stopMicrophone()
AudioIO inkluderer en StreamingAudioPlayer for TTS utgang og en AudioRingBuffer for trådsikre lydoverføring mellom fangst- og inferenstråder.
SystemAudioTap
Fanger systemets utgangsblanding - hva Mac spiller for tiden - som mono Float32 ved en caller-chosen prøvehastighet (Kore lydprosesstrykk, macOS 14.4+). Det mono globale trykket utelukker den gjeldende prosessen som standard, så en apps egen avspilling er aldri gjeninnpakket, og det er pakket i en privat aggregert enhet som inneholder bare trykk.
let tap = SystemAudioTap()
try tap.start(targetSampleRate: 16000) { samples in
pipeline.pushAudio(samples)
}
tap.stop()
Fangst overlever standardutgangsavviksbrytere - den interne resuppleren gjenoppbygges når blandingshastighetsendringene endres. Vertsappen må erklære NSAudioCaptureUsageDescription. Hvis opptaksgodkjennelsen blir nektet, kan det fortsatt opprettes et trykk ennå bare levere stillhet: se framesCaptured vokse mens nonSilentFrames blir 0 og mislykkes stengt.
Tidsstemplet uavhengige kilder
Begge fange klasser eksponerer tidsstemplede overbelastninger. CapturedAudioChunk bærer mono samples på sampleRate pluss en valgfri Mach hostTime for den første inngangsrammen. Fordi begge kildene bruker samme vertsklokke, kan en app holde PCM-separerte og bestille avledede transkripsjonshendelser uten å blande lyden.
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 å lytte-bare fange, enableAEC: true aktiverer Apple Voice Processing før mikrofonformatet leses, og enablePlayback: false om den ubrukte spilleren. På macOS fjernes enhetens avspilling fra mikrofonprøver og manglende oppstart av AEC rapporteres i stedet for å falle tilbake til rå inndata.
Økt filinnmating og gjenkjennelse
CapturedAudioChunk bærer også en monoton frameIndex og en isFinal marker. AudioFileLoader.stream produserer disse bitene etterspørselen med avgrenset minne, omdemper en gang med vedvarende konverteringstilstand, og i gjennomsnitt alle inngangskanaler som standard. Bruk .first eller .select([indices]) når kanalruten er kjent.
StreamingRecognitionModel og StreamingRecognitionSession gi én cache-bevarende inkremental API på tvers av Parakeet Strømming 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
Delt protobuf-leser for SentencePiece .model-filer, bor i AudioCommon. Hver modul som trenger å dekode Sentence Piece-stykker (PersonaPlex, OmnilingualASR, fremtids ASR / TTS-porter) bygger sin egen dekoder på toppen av denne enkeltleseren i stedet for å implementere protobuft-trådformatet.
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
}
Brukt av: OmnilingualASR.OmnilingualVocabulary, PersonaPlex.SentencePieceDecoder. Dekkert av 7 enhetsprøver i Tests/AudioCommonTests/SentencePieceModelTests.
MLXCommon.SDPA
Skalert dot-produkt oppmerksomhetshjelpere delt på alle MLX oppmerksomhetsmodul (Qwen3-ASR / Qwen3-TTS / Qwen3-Chat / CosyVoice / PersonaPlex / OmnilingualASR. Hver modul holder sine egne projeksjoner - SDPA håndterer bare reshape → oppmerksomhet → flett kjeleplate.
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 reshape-samtaler bruker -1 for batchdimensjonen slik at hjelperne komponerer med MLX.compile(shapeless:) grafer som varierer batch ved kjøringstid (f.eks. Qwen3-TTS Talker autoregressiv dekode).
HTTP API Server
speech-server binær eksponerer hver modell i speech-swift som HTTP REST endepunkter pluss en WebSocket endepunkt som implementerer OpenAI Realtime API. Modeller lastes lazily på første forespørsel; pass --preload for å varme dem alle ved oppstart.
swift build -c release
.build/release/speech-server --port 8080
# Preload every model at startup
.build/release/speech-server --port 8080 --preload
REST Endepunkter
| Endepunkt | Metode | Forespørsel | Svar |
|---|---|---|---|
/transcribe | POST | audio/wav kropp | JSON { text } (Qwen3-ASR) |
/v1/audio/transcriptions | POST | Multipart { file, model, response_format?, language?, prompt?, temperature? } | JSON, tekst, ekstra JSON eller VTT |
/v1/audio/speech | POST | JSON { model, input, voice, response_format?, speed? } | audio/wav eller audio/pcm kropp |
/speak | POST | JSON { text, engine?, language?, voice? } | audio/wav kropp (Qwen3-TTS, CosyVoice og Kokoro) |
/respond | POST | audio/wav kropp | audio/wav kropp (PersonaPlex) |
/enhance | POST | audio/wav kropp | audio/wav kropp (DeepFilterNet3) |
/vad | POST | audio/wav kropp | JSON segmentliste |
/diarize | POST | audio/wav kropp | JSON DiarizedSegment-liste |
/embed-speaker | POST | audio/wav kropp | JSON [Float] (256-dim) |
/v1/audio/speech kart standard TTS modell og talenavn til lokale motorer. Det standard til WAV; response_format: "pcm" returnerer headerless 24 kHz mono PCM16 lite-endisk lyd. Ustøttede komprimerte formater blir eksplisitt avvist.
/v1/audio/transcriptions aksepterer en WAV-fil som multiparts skjemadata og standard til {"text":"..."}; response_format kan også be om tekst, ekstra JSON, SRT eller VTT. På Apple velger modell alias en lokal ASR motor. Den pakkede speech-core server på Linux og Windows bruker lazily lastet Parakeet, godtar PCM16/24/32 eller Float32 WAV, og caps uploads på 25 MiB og 10 Minutt.
# 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 endepunkt ved ws://host:port/v1/realtime implementerer OpenAI Realtime protokoll. Alle meldinger er JSON med en type diskriminator; lyd nyttelast er base64-encoded PCM16 ved 24 kHz mono.
Under kalde modeller belastninger eller lange generasjoner, sender serveren ut lette realtime.keepalive JSON hendelser og websocket pong kontrollrammer omtrent hvert 15. sekund til modellen utdata er klar. Kunder kan ignorere disse hendelsene eller behandle dem som aktivitetsindikatorer.
Kunde → Servere hendelser
| Begivenhet | Formål |
|---|---|
session.update | Konfigurer motor, språk, stemme, lydformat og valgfri server VAD |
input_audio_buffer.append | Legg til en base64 PCM16 bit til inngangsbufferen |
input_audio_buffer.commit | Legg til den bufferte lyden for transkripsjon |
input_audio_buffer.clear | Forkast den gjeldende inndatabufferen |
response.create | Forespørsel TTS syntese for den medfølgende teksten/instrumentene |
Server → Kundehendelser
| Begivenhet | Betydning |
|---|---|
session.created | Handshake komplett, standardoppsett sendt ut |
session.updated | Siste session.update anerkjent |
input_audio_buffer.speech_started | Server VAD oppdaget begynnelsen på en taletur |
input_audio_buffer.speech_stopped | Server VAD avsluttet turen etter stillhet eller varighetsgrensen |
input_audio_buffer.committed | Lyd akseptert og køet for transkripsjon |
conversation.item.input_audio_transcription.completed | ASR resultat med endelig transkripsjonstekst |
response.audio.delta | Base64 PCM16 bit av syntetisert lyd |
response.audio.done | Ingen flere lydbiter for dette svaret |
response.done | Response finalized (metadata + latensstatistikk) |
error | Feil konvolutt med type og message |
Automatiske svinger med serveren VAD
Eksplisitt input_audio_buffer.commit forblir standard. For å la serveren lukke og transcribe svinger automatisk med Silero VAD, konfigurer turn_detection. Serveren holder bare den etterspurte forhåndsrullen mens den er inaktiv, sender talestart/stop og forplikte hendelser i rekkefølge, og tvinge-lukker en kontinuerlig aktiv sving 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 lever i AudioServer SPM-produktet. En eksempelleserklient sendes på Examples/websocket-client.html - åpner den sammen med en kjørende server for å kjøre hele ASR + TTS rundtur.
Modellnedlastninger
Alle modeller lastes ned fra HuggingFace ved første bruk og cached i ~/Library/Caches/qwen3-speech/. AudioCommon-modulen tilbyr en delt HuggingFaceDownloader som håndterer nedlasting, cacheing og verifisering av integritet.
Last ned retries
Modelllastere og laste ned APIs aksepterer downloadOptions: DownloadOptions. onRetry mottar en DownloadRetryEvent Før hvert backoff, med modelId, attempt, maxAttempts, den opprinnelige error, og retryInSeconds. nil betyr at ingen retries forblir; full-cache tilbakefall kan fortsatt lykkes.
Tilbaketrekk er synkrone og @Sendable, uten hovedaktørgaranti. Avbestilling produserer ingen gjenprøve hendelse. Sett retryDelaysSeconds for å tilpasse policyen ([] betyr ett forsøk); eksplisitt nedlasting API argumentet har forrang. Standard forsøkstal og byteframgang er bevart. Feil forsøk er også logget på varslingsnivå gjennom AudioLog.download.
Samarbeidsavbestilling
For MLX transkripsjon, Qwen3ASRModel.transcribeCheckingCancellation(audio:sampleRate:options:) kaster CancellationError når oppgaveavbestilling observeres før utvinning av funksjon, koding, dekoder forhåndsfylling eller et dekodingstrinn. GPU arbeider allerede sendt kan avsluttes. Synkronen transcribe og transcribeBatch APIs beholder sin ikke-strekkende oppførsel og ignorerer oppgaveavbelysning. speech-server bruker avbestillingsvare-oppføringspunktet for Qwen3-ASR.
MOSS-TTS-Nano
MossTTSNanoModel serierer forespørsler og skaper friske CoreML tilstand for hver uttalelse. syntetisere og syntetisereStream konservering stereo; SpeechGenerationModel gir en mono downmix. Pass språk: nil. Strømmer slutter med en tom sluttmarkering.
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)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.
Gemma4UnifiedChat.generateResponse aksepterer en valgfri onGeneration tilbakekalling med Gemma4GenerationTrace. Tilbakekallingen kjører før verktøytolking, inkludert når den ferdigstillelsen blir avvist. Opptak endrer ikke prøvetaking eller akseptert verktøysyntaks.
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 utgivelser hver forespørsels KV cache. Response parsing fjerner kanalsifferanser fra returnert tekst. Orphanede verktøy-kall terminatorer avvises som feilaktige svar. 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.
VoxCPM2 støtter vektpresisjon: .float16 for et ukvantisert kontrollpunkt. Hovedparametrene bruker FP16; AudioVAE og noen beregninger forblir FP32. INT8 kontrollpunkter blir avvist for denne modusen.
Gemma4ConversationMessage, Gemma4Tool, og generer Response bevarer innfødte verktøyerklæringer, argumenter og resultathistorie. InferanseAnnulleringToken avbryter generasjonen samarbeidsmessig. Silero gjørUavhengigStream isolasjoner tilstand, og prosessChunkThrowing utbreder inferensfeil.
Whisper ASRModel.fraDirectory lasts iscenesatt full Large-v3 CoreML pakker. 32-lags dekoderen kan bygge sitt prefiks uten TextDecoderContextPrefill.mlmodelc og frigjør per trinn temporære. Standard Whisper CLI-modellen forblir Turbo.
Den opprinnelige tjenesten serialiserer chat, syntese og transkripsjon; lett VAD har separat stream-tilstand. Gemma forhåndsfyll bruker 256-token-partier, ber KV-tilstand frigis, og MLX cache er cache cache 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 8080POST /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, contentValgfritt 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.
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 kjører lokalt på Apple Silicon gjennom Voxtral TTS-modulen: 20 forhåndsinnstilte stemmer, ni språk 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)
}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.
import AudioCommon
let player = StreamingAudioPlayer()
player.skipInitialSilence = false