fix(calls): make ML denoise build-honest + gate desktop trigger on CI
CI / Build & Quality Checks (push) Successful in 10m41s
CI / Trigger Desktop Build (push) Successful in 6s

Audit/repair of the multi-model denoise work so it actually builds and only
exposes working, self-hosted models.

- Complete the DTLN/DFN3 revert: uninstall @workadventure/noise-suppression
  and deepfilternet3-noise-filter (package.json + lockfile), drop the unused
  DTLN asset-copy block from vite.config.js (was shipping ~2MB of unused
  tflite/wasm), and narrow DenoiseModelId to the bundled models (rnnoise,
  speex). Coerce any retired persisted model value back to the default.
- Fix General.tsx CI typecheck failures introduced by the denoise UI: restore
  three imports the rewrite deleted (useDateFormatItems, SequenceCardStyle,
  useTauriUpdater), add the missing denoise/sound imports, and correct
  hallucinated Folds props (Text has no variant/bold; Box uses
  alignItems/justifyContent). tsc now passes with 0 errors.
- Harden the vite denoise plugin: required RNNoise/Speex/gate assets and the
  shim now fail the build loudly if missing (instead of a silent warn that
  shipped a broken ML feature), and the index.html shim injection is verified.
- CI: move the cinny-desktop submodule bump into ci.yml as a `trigger-desktop`
  job gated on `needs: build`, and delete the standalone trigger-desktop.yml.
  A failing push no longer kicks off the slow Tauri builds in parallel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 01:40:37 -04:00
parent b65e82a475
commit 6634b2b8a2
12 changed files with 200 additions and 196 deletions
+26 -34
View File
@@ -80,6 +80,10 @@ function lotusDenoise() {
fs.mkdirSync(denoiseDir, { recursive: true });
const sapphi = path.resolve('node_modules/@sapphi-red/web-noise-suppressor/dist');
// All bundled denoise assets are REQUIRED: every entry backs a model the
// UI can select (RNNoise, Speex) or the optional noise gate. A missing
// source means a partial/changed install would otherwise silently ship a
// broken ML feature (worklet 404 -> raw mic), so we fail the build instead.
const assets = [
[
path.join(sapphi, 'rnnoise/workletProcessor.js'),
@@ -87,49 +91,31 @@ function lotusDenoise() {
],
[path.join(sapphi, 'rnnoise.wasm'), path.join(denoiseDir, 'rnnoise.wasm')],
[path.join(sapphi, 'rnnoise_simd.wasm'), path.join(denoiseDir, 'rnnoise_simd.wasm')],
[
path.join(sapphi, 'speex/workletProcessor.js'),
path.join(denoiseDir, 'speexWorklet.js'),
],
[path.join(sapphi, 'speex/workletProcessor.js'), path.join(denoiseDir, 'speexWorklet.js')],
[path.join(sapphi, 'speex.wasm'), path.join(denoiseDir, 'speex.wasm')],
[
path.join(sapphi, 'noiseGate/workletProcessor.js'),
path.join(denoiseDir, 'noiseGateWorklet.js'),
],
// DTLN (WorkAdventure v0.0.4)
[
path.resolve('node_modules/@workadventure/noise-suppression/dist/audio-worklet.js'),
path.join(denoiseDir, 'dtlnWorklet.js'),
],
[
path.resolve('node_modules/@workadventure/noise-suppression/dist/assets/audio-worklet-processor.js'),
path.join(denoiseDir, 'dtlnProcessor.js'),
],
[
path.resolve('node_modules/@workadventure/noise-suppression/dist/vendor/litert/litert_wasm_internal.wasm'),
path.join(denoiseDir, 'litert_wasm_internal.wasm'),
],
[
path.resolve('node_modules/@workadventure/noise-suppression/dist/assets/model_quant_1.tflite'),
path.join(denoiseDir, 'model_1.tflite'),
],
[
path.resolve('node_modules/@workadventure/noise-suppression/dist/assets/model_quant_2.tflite'),
path.join(denoiseDir, 'model_2.tflite'),
],
];
assets.forEach(([s, d]) => {
if (fs.existsSync(s)) {
fs.copyFileSync(s, d);
} else {
// eslint-disable-next-line no-console
console.warn(`[lotus-denoise] Asset missing, will be populated by CI: ${s}`);
}
});
const missing = assets.filter(([s]) => !fs.existsSync(s)).map(([s]) => s);
if (missing.length > 0) {
throw new Error(
`[lotus-denoise] Required denoise asset(s) missing — build aborted to avoid shipping a broken ML feature:\n ${missing.join('\n ')}`,
);
}
assets.forEach(([s, d]) => fs.copyFileSync(s, d));
const shimSrc = path.resolve('build/lotus-denoise.js');
if (fs.existsSync(shimSrc)) fs.copyFileSync(shimSrc, path.join(ecDir, 'lotus-denoise.js'));
if (!fs.existsSync(shimSrc)) {
throw new Error(`[lotus-denoise] Missing shim source ${shimSrc} — build aborted.`);
}
fs.copyFileSync(shimSrc, path.join(ecDir, 'lotus-denoise.js'));
// Inject the shim <script> into Element Call's index.html so it runs
// before EC captures the mic. Verify the injection actually landed —
// if EC's bundle ever drops its deferred module entry the replace would
// no-op and ML would silently never engage, so fail loudly.
const indexPath = path.join(ecDir, 'index.html');
if (fs.existsSync(indexPath)) {
let html = fs.readFileSync(indexPath, 'utf8');
@@ -139,6 +125,12 @@ function lotusDenoise() {
/<script type="module"/,
'<script src="./lotus-denoise.js"></script><script type="module"',
);
if (!html.includes('lotus-denoise.js')) {
throw new Error(
'[lotus-denoise] Failed to inject shim into Element Call index.html ' +
'(no `<script type="module">` entry found) — build aborted.',
);
}
fs.writeFileSync(indexPath, html);
}
}