From b02ce8e2f31f59c6803b6b83040ca6577a38ad45 Mon Sep 17 00:00:00 2001 From: James Pine Date: Tue, 17 Mar 2026 02:16:33 -0700 Subject: [PATCH] replace descript-audio-codec with lightweight DAC shim The real descript-audio-codec package pulls in descript-audiotools, which transitively requires onnx, tensorboard, protobuf, matplotlib, pystoi, and other heavy dependencies. onnx fails to build from source on macOS due to CMake version incompatibility. TADA only uses Snake1d (a 7-line PyTorch module) from DAC. This commit adds a shim in backend/utils/dac_shim.py that registers fake dac.* modules in sys.modules with just the Snake1d class, completely eliminating the DAC/audiotools dependency chain. --- backend/backends/hume_backend.py | 7 +++ backend/build_binary.py | 16 ++---- backend/requirements.txt | 6 ++- backend/utils/dac_shim.py | 93 ++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 backend/utils/dac_shim.py diff --git a/backend/backends/hume_backend.py b/backend/backends/hume_backend.py index 1d4a4600..b3beab25 100644 --- a/backend/backends/hume_backend.py +++ b/backend/backends/hume_backend.py @@ -100,6 +100,13 @@ class HumeTadaBackend: repo = TADA_MODEL_REPOS.get(model_size, TADA_1B_REPO) with model_load_progress(model_name, is_cached): + # Install DAC shim before importing tada — tada's encoder/decoder + # import dac.nn.layers.Snake1d which requires the descript-audio-codec + # package. The real package pulls in onnx/tensorboard/matplotlib via + # descript-audiotools, so we use a lightweight shim instead. + from ..utils.dac_shim import install_dac_shim + install_dac_shim() + import torch from huggingface_hub import snapshot_download diff --git a/backend/build_binary.py b/backend/build_binary.py index 0c6dfebd..0574894f 100644 --- a/backend/build_binary.py +++ b/backend/build_binary.py @@ -213,19 +213,11 @@ def build_server(cuda=False): "tada.utils.gray_code", "--hidden-import", "tada.utils.text", - # descript-audio-codec (DAC) — used by TADA for Snake1d layers + # DAC shim — provides dac.nn.layers.Snake1d without the real + # descript-audio-codec package (which pulls onnx/tensorboard via + # descript-audiotools). The shim is in backend/utils/dac_shim.py. "--hidden-import", - "dac", - "--hidden-import", - "dac.nn", - "--hidden-import", - "dac.nn.layers", - "--hidden-import", - "dac.model", - "--hidden-import", - "dac.model.dac", - "--collect-all", - "dac", + "backend.utils.dac_shim", "--hidden-import", "torchaudio", "--collect-submodules", diff --git a/backend/requirements.txt b/backend/requirements.txt index 2bba9d70..d77f97be 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -34,8 +34,10 @@ spacy-pkuseg pyloudnorm # HumeAI TADA sub-dependencies (hume-tada itself is installed -# --no-deps in the setup script because it pins torch>=2.7,<2.8) -descript-audio-codec>=1.0.0 +# --no-deps in the setup script because it pins torch>=2.7,<2.8. +# descript-audio-codec is NOT installed — it pulls onnx/tensorboard +# via descript-audiotools. A lightweight shim in utils/dac_shim.py +# provides the only class TADA uses: Snake1d.) torchaudio # Audio processing diff --git a/backend/utils/dac_shim.py b/backend/utils/dac_shim.py new file mode 100644 index 00000000..ea1294fc --- /dev/null +++ b/backend/utils/dac_shim.py @@ -0,0 +1,93 @@ +""" +Minimal shim for descript-audio-codec (DAC). + +TADA only imports Snake1d from dac.nn.layers and dac.model.dac. +The real DAC package pulls in descript-audiotools which depends on +onnx, tensorboard, protobuf, matplotlib, pystoi, etc. — none of +which are needed for TADA's runtime use of Snake1d. + +This shim provides the exact Snake1d implementation (MIT-licensed, +from https://github.com/descriptinc/descript-audio-codec) so we can +avoid the entire audiotools dependency chain. + +If the real DAC package is installed, this module is never used — +Python's import system will find the site-packages version first. +Install this shim only when descript-audio-codec is NOT installed. +""" + +import sys +import types + +import torch +import torch.nn as nn + + +# ── Snake activation (from dac/nn/layers.py) ──────────────────────── + +@torch.jit.script +def snake(x: torch.Tensor, alpha: torch.Tensor) -> torch.Tensor: + shape = x.shape + x = x.reshape(shape[0], shape[1], -1) + x = x + (alpha + 1e-9).reciprocal() * torch.sin(alpha * x).pow(2) + x = x.reshape(shape) + return x + + +class Snake1d(nn.Module): + def __init__(self, channels: int): + super().__init__() + self.alpha = nn.Parameter(torch.ones(1, channels, 1)) + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return snake(x, self.alpha) + + +# ── Register as dac.nn.layers and dac.model.dac ───────────────────── + +def install_dac_shim() -> None: + """Register fake dac package modules in sys.modules. + + Only installs the shim if 'dac' is not already importable + (i.e. the real descript-audio-codec is not installed). + """ + try: + import dac # noqa: F401 — real package exists, do nothing + return + except ImportError: + pass + + # Create the module tree: dac -> dac.nn -> dac.nn.layers + # -> dac.model -> dac.model.dac + dac_pkg = types.ModuleType("dac") + dac_pkg.__path__ = [] # make it a package + dac_pkg.__package__ = "dac" + + dac_nn = types.ModuleType("dac.nn") + dac_nn.__path__ = [] + dac_nn.__package__ = "dac.nn" + + dac_nn_layers = types.ModuleType("dac.nn.layers") + dac_nn_layers.__package__ = "dac.nn" + dac_nn_layers.Snake1d = Snake1d + dac_nn_layers.snake = snake + + dac_model = types.ModuleType("dac.model") + dac_model.__path__ = [] + dac_model.__package__ = "dac.model" + + dac_model_dac = types.ModuleType("dac.model.dac") + dac_model_dac.__package__ = "dac.model" + dac_model_dac.Snake1d = Snake1d + + # Wire up submodules + dac_pkg.nn = dac_nn + dac_pkg.model = dac_model + dac_nn.layers = dac_nn_layers + dac_model.dac = dac_model_dac + + # Register in sys.modules + sys.modules["dac"] = dac_pkg + sys.modules["dac.nn"] = dac_nn + sys.modules["dac.nn.layers"] = dac_nn_layers + sys.modules["dac.model"] = dac_model + sys.modules["dac.model.dac"] = dac_model_dac