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
+72 -37
View File
@@ -66,7 +66,12 @@
function checkSimd() {
try {
return WebAssembly.validate(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11]))
return WebAssembly.validate(
new Uint8Array([
0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0,
253, 15, 253, 98, 11,
]),
)
? Promise.resolve(true)
: Promise.resolve(false);
} catch (e) {
@@ -79,19 +84,22 @@
var p = PROCESSORS[modelId];
if (!p || !p.wasm) return Promise.resolve(null);
wasmPromises[modelId] = (modelId === 'rnnoise' ? checkSimd() : Promise.resolve(false)).then(function (simd) {
var file = (simd && p.simdWasm) ? p.simdWasm : p.wasm;
return fetch(ASSET_BASE + file).then(function (r) {
if (!r.ok) {
if (simd && p.simdWasm) return fetch(ASSET_BASE + p.wasm).then(function(r2) {
if (!r2.ok) throw new Error(modelId + ' wasm failed');
return r2.arrayBuffer();
});
throw new Error(modelId + ' wasm failed');
}
return r.arrayBuffer();
});
});
wasmPromises[modelId] = (modelId === 'rnnoise' ? checkSimd() : Promise.resolve(false)).then(
function (simd) {
var file = simd && p.simdWasm ? p.simdWasm : p.wasm;
return fetch(ASSET_BASE + file).then(function (r) {
if (!r.ok) {
if (simd && p.simdWasm)
return fetch(ASSET_BASE + p.wasm).then(function (r2) {
if (!r2.ok) throw new Error(modelId + ' wasm failed');
return r2.arrayBuffer();
});
throw new Error(modelId + ' wasm failed');
}
return r.arrayBuffer();
});
},
);
return wasmPromises[modelId];
}
@@ -100,20 +108,30 @@
ctxPromise = (function () {
var ctx = new AudioContext({ sampleRate: SAMPLE_RATE });
if (ctx.sampleRate !== SAMPLE_RATE) {
try { ctx.close(); } catch (e) {}
try {
ctx.close();
} catch (e) {}
return Promise.reject(new Error('SampleRate mismatch: ' + ctx.sampleRate));
}
// Load required modules
var scripts = [PROCESSORS[MODEL].script];
if (USE_GATE) scripts.push(PROCESSORS.gate.script);
return Promise.all(scripts.map(function(s) {
return ctx.audioWorklet.addModule(ASSET_BASE + s);
})).then(function () {
return ctx.state === 'suspended' ? ctx.resume().then(function () { return ctx; }) : ctx;
return Promise.all(
scripts.map(function (s) {
return ctx.audioWorklet.addModule(ASSET_BASE + s);
}),
).then(function () {
return ctx.state === 'suspended'
? ctx.resume().then(function () {
return ctx;
})
: ctx;
});
})();
ctxPromise.catch(function () { ctxPromise = null; });
ctxPromise.catch(function () {
ctxPromise = null;
});
}
return ctxPromise;
}
@@ -140,8 +158,8 @@
openThreshold: GATE_THRESHOLD,
closeThreshold: GATE_THRESHOLD - 5,
holdMs: 150,
maxChannels: 1
}
maxChannels: 1,
},
});
head.connect(gateNode);
head = gateNode;
@@ -166,32 +184,49 @@
function cleanup() {
if (torndown) return;
torndown = true;
try { mlNode.port.postMessage('destroy'); } catch (e) {}
try { source.disconnect(); mlNode.disconnect(); } catch (e) {}
try { origTrack.stop(); } catch (e) {}
try {
mlNode.port.postMessage('destroy');
} catch (e) {}
try {
source.disconnect();
mlNode.disconnect();
} catch (e) {}
try {
origTrack.stop();
} catch (e) {}
}
var rawStop = processedTrack.stop.bind(processedTrack);
processedTrack.stop = function () { cleanup(); rawStop(); };
processedTrack.stop = function () {
cleanup();
rawStop();
};
origTrack.addEventListener('ended', function () {
try { rawStop(); } catch (e) {}
try {
rawStop();
} catch (e) {}
cleanup();
});
if (!hasNotifiedActive) {
hasNotifiedActive = true;
window.parent.postMessage({
type: 'lotus-denoise-status',
active: true,
model: MODEL,
nativeNS: USE_NATIVE_NS,
gate: USE_GATE
}, '*');
window.parent.postMessage(
{
type: 'lotus-denoise-status',
active: true,
model: MODEL,
nativeNS: USE_NATIVE_NS,
gate: USE_GATE,
},
'*',
);
}
var out = new MediaStream();
out.addTrack(processedTrack);
stream.getVideoTracks().forEach(function (t) { out.addTrack(t); });
stream.getVideoTracks().forEach(function (t) {
out.addTrack(t);
});
return out;
})
.catch(function (e) {
@@ -206,7 +241,8 @@
var wantsAudio = !!(constraints && constraints.audio);
var effective = constraints;
if (wantsAudio) {
var audioC = typeof constraints.audio === 'object' ? Object.assign({}, constraints.audio) : {};
var audioC =
typeof constraints.audio === 'object' ? Object.assign({}, constraints.audio) : {};
audioC.noiseSuppression = USE_NATIVE_NS;
audioC.channelCount = 1;
if (audioC.echoCancellation === undefined) audioC.echoCancellation = true;
@@ -218,4 +254,3 @@
});
};
})();