Skip to content

Request TTS and Diarizer opt-out traits: ASR-only consumers ship 1.0 MB of unreachable LuxTTS resources and compile 3.1 MB of unused subsystems (cf. #880/#888) #990

Description

@NocturnalGrp

Summary

ASR-only consumers unconditionally ship the LuxTTS G2P resources, and compile the TTS
and Diarizer subsystems, with no code path able to reach any of it. Could TTS and
Diarizer get the same opt-out trait treatment NemoTextProcessing received in #880 /
#888?

(Refiling #989, which I closed — it covered TTS only.)

Measurements

FluidAudio 0.17.5, release build of an ASR-only macOS app: Parakeet / Phonon-2 on the
ANE via AsrManager + AsrModels only. No TtsManager, no Kokoro, no LuxTTS, no
DiarizerManager — grep across the app's sources returns zero references to any of them.

FluidAudio_FluidAudio.bundle is 1.0 MB, and every byte is TTS:

File Bytes
luxtts_en_us_lexicon.tsv.zz 982,385
luxtts_en_us_g2p_aux.json 37,000
Info.plist 1,134

That comes from the unconditional

resources: [.process("TTS/LuxTts/G2p/Resources")]

on the FluidAudio target.

Source footprint of the subsystems, for scale against the one actually in use:

Subsystem Size
Sources/FluidAudio/TTS 2.4 MB
Sources/FluidAudio/ASR 1.3 MB
Sources/FluidAudio/Diarizer 728 KB
Sources/FluidAudio/VAD 60 KB

TTS is the largest subsystem in the library — nearly double ASR. In a prior unstripped
build of the same app, TTS symbols were roughly 9% of the binary's symbol table.

So an ASR-only consumer pays ~1.0 MB of provably unreachable resources, plus the compile
time and binary weight of 3.1 MB of TTS and Diarizer source.

Why traits rather than separate products

Separate FluidAudioASR / FluidAudioTTS products would break every existing
import FluidAudio. The trait approach already taken for NemoTextProcessing avoids
that: default-on preserves current behaviour exactly, and consumers who want a smaller
build opt out. Mirroring the existing pattern in Package@swift-6.2.swift:

traits: [
    .trait(name: "TTS", ...),
    .trait(name: "Diarizer", ...),
    .default(enabledTraits: ["NemoTextProcessing", "TTS", "Diarizer"]),
]

with those sources, and the .process("TTS/LuxTts/G2p/Resources") resource rule,
conditioned on the matching trait.

I appreciate the resource rule is the harder half. Conditioning source files and
resources on a trait within a single target is more awkward than conditioning a
dependency on a binary target, which is what #880 needed. If the practical route is
splitting TTS and Diarizer into their own trait-conditioned targets, that is equally good
from a consumer's point of view.

Happy to test a branch against an ASR-only consumer and report the resulting bundle and
binary sizes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions