fix(calls): make ML denoise build-honest + gate desktop trigger on CI
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:
@@ -45,6 +45,7 @@ import {
|
||||
ChatBackground,
|
||||
ComposerToolbarSettings,
|
||||
DateFormat,
|
||||
DenoiseModelId,
|
||||
MessageLayout,
|
||||
MessageSpacing,
|
||||
NoiseSuppressionMode,
|
||||
@@ -70,6 +71,10 @@ import { BG_OPTIONS, getChatBg } from '../../lotus/chatBackground';
|
||||
import { resetBootSequence, runLotusBootSequence } from '../../../../lotus-boot';
|
||||
import { useMessageLayoutItems } from '../../../hooks/useMessageLayout';
|
||||
import { useMessageSpacingItems } from '../../../hooks/useMessageSpacing';
|
||||
import { SequenceCardStyle } from '../styles.css';
|
||||
import { useTauriUpdater } from '../../../hooks/useTauriUpdater';
|
||||
import { useDateFormatItems } from '../../../hooks/useDateFormat';
|
||||
import { playCallJoinSound } from '../../../utils/callSounds';
|
||||
|
||||
type ThemeSelectorProps = {
|
||||
themeNames: Record<string, string>;
|
||||
@@ -1247,7 +1252,7 @@ function MicMeter() {
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="100" style={{ padding: '8px 0' }}>
|
||||
<Box direction="Row" gap="200" align="Center">
|
||||
<Box direction="Row" gap="200" alignItems="Center">
|
||||
<Button size="300" variant="Secondary" outlined onClick={active ? stop : start}>
|
||||
<Text size="T300">{active ? 'Stop Test' : 'Test Microphone'}</Text>
|
||||
</Button>
|
||||
@@ -1276,7 +1281,7 @@ function MicMeter() {
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
<Text size="S300" variant="Secondary">
|
||||
<Text size="T200" priority="300">
|
||||
The green bar shows your live volume. Use this to tune the Gate Threshold.
|
||||
</Text>
|
||||
</Box>
|
||||
@@ -1336,8 +1341,8 @@ function Calls() {
|
||||
description={
|
||||
<Box direction="Column" gap="200">
|
||||
<Text>
|
||||
Filter background noise from your mic during calls. Browser-native uses the
|
||||
built-in WebRTC suppressor (Google NSNet2).
|
||||
Filter background noise from your mic during calls. Browser-native uses the built-in
|
||||
WebRTC suppressor (Google NSNet2).
|
||||
</Text>
|
||||
|
||||
<Box direction="Column" gap="100" style={{ overflowX: 'auto' }}>
|
||||
@@ -1347,39 +1352,31 @@ function Calls() {
|
||||
style={{ borderBottom: '1px solid var(--lt-border-color)', paddingBottom: '4px' }}
|
||||
>
|
||||
<Box style={{ width: '120px' }}>
|
||||
<Text size="S300" bold>
|
||||
Model
|
||||
</Text>
|
||||
<Text size="T200">Model</Text>
|
||||
</Box>
|
||||
<Box style={{ width: '80px' }}>
|
||||
<Text size="S300" bold>
|
||||
CPU
|
||||
</Text>
|
||||
<Text size="T200">CPU</Text>
|
||||
</Box>
|
||||
<Box style={{ width: '80px' }}>
|
||||
<Text size="S300" bold>
|
||||
Quality
|
||||
</Text>
|
||||
<Text size="T200">Quality</Text>
|
||||
</Box>
|
||||
<Box grow="Yes">
|
||||
<Text size="S300" bold>
|
||||
Transients
|
||||
</Text>
|
||||
<Text size="T200">Transients</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
{DENOISE_MODELS.map((model) => (
|
||||
<Box key={model.id} direction="Row" gap="100">
|
||||
<Box style={{ width: '120px' }}>
|
||||
<Text size="S300">{model.name}</Text>
|
||||
<Text size="T200">{model.name}</Text>
|
||||
</Box>
|
||||
<Box style={{ width: '80px' }}>
|
||||
<Text size="S300">{model.cpuUsage}</Text>
|
||||
<Text size="T200">{model.cpuUsage}</Text>
|
||||
</Box>
|
||||
<Box style={{ width: '80px' }}>
|
||||
<Text size="S300">{model.voiceQuality}</Text>
|
||||
<Text size="T200">{model.voiceQuality}</Text>
|
||||
</Box>
|
||||
<Box grow="Yes">
|
||||
<Text size="S300">{model.transients}</Text>
|
||||
<Text size="T200">{model.transients}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
))}
|
||||
@@ -1387,12 +1384,12 @@ function Calls() {
|
||||
|
||||
{!mlSupported && (
|
||||
<Box direction="Column" gap="100">
|
||||
<Text variant="Warning" size="S300">
|
||||
<Text size="T200" priority="400">
|
||||
ML options are not supported in this browser.
|
||||
</Text>
|
||||
<Box as="ul" style={{ paddingLeft: '20px', margin: 0 }}>
|
||||
{ML_DENOISE_REQUIREMENTS.map((req) => (
|
||||
<Text as="li" key={req} size="S300">
|
||||
<Text as="li" key={req} size="T200">
|
||||
{req}
|
||||
</Text>
|
||||
))}
|
||||
@@ -1400,7 +1397,7 @@ function Calls() {
|
||||
</Box>
|
||||
)}
|
||||
{callNoiseSuppression === 'ml' && (
|
||||
<Text variant="Warning" size="S300">
|
||||
<Text size="T200" priority="400">
|
||||
Note: Applying changes requires rejoining the call.
|
||||
</Text>
|
||||
)}
|
||||
@@ -1471,11 +1468,9 @@ function Calls() {
|
||||
|
||||
{callDenoiseGate && (
|
||||
<Box direction="Column" gap="100">
|
||||
<Box direction="Row" justify="SpaceBetween">
|
||||
<Text size="S300">Gate Threshold</Text>
|
||||
<Text size="S300" bold>
|
||||
{callDenoiseGateThreshold} dB
|
||||
</Text>
|
||||
<Box direction="Row" justifyContent="SpaceBetween">
|
||||
<Text size="T200">Gate Threshold</Text>
|
||||
<Text size="T200">{callDenoiseGateThreshold} dB</Text>
|
||||
</Box>
|
||||
<input
|
||||
type="range"
|
||||
|
||||
@@ -14,7 +14,10 @@ export type MessageSpacing = '0' | '100' | '200' | '300' | '400' | '500';
|
||||
// - 'browser' : WebRTC built-in suppression (Element Call noiseSuppression param)
|
||||
// - 'ml' : client-side RNNoise ML suppression (Lotus denoise shim)
|
||||
export type NoiseSuppressionMode = 'off' | 'browser' | 'ml';
|
||||
export type DenoiseModelId = 'rnnoise' | 'speex' | 'dtln' | 'deepfilternet';
|
||||
// Only self-hostable, build-bundled models are exposed. DTLN/DeepFilterNet were
|
||||
// evaluated but rely on remote-style asset loading incompatible with our
|
||||
// self-hosted/Tauri-CSP strategy (see LOTUS_DENOISE_ENGINEERING_REVIEW.md).
|
||||
export type DenoiseModelId = 'rnnoise' | 'speex';
|
||||
export type ChatBackground =
|
||||
| 'none'
|
||||
| 'blueprint'
|
||||
@@ -257,6 +260,12 @@ export const getSettings = (): Settings => {
|
||||
? 'browser'
|
||||
: 'off'
|
||||
: (saved.callNoiseSuppression ?? defaultSettings.callNoiseSuppression),
|
||||
// Coerce any retired/unknown persisted model (e.g. 'dtln', 'deepfilternet'
|
||||
// from earlier beta builds) back to the default working model.
|
||||
callDenoiseModel:
|
||||
saved.callDenoiseModel === 'rnnoise' || saved.callDenoiseModel === 'speex'
|
||||
? saved.callDenoiseModel
|
||||
: defaultSettings.callDenoiseModel,
|
||||
composerToolbarButtons: {
|
||||
...DEFAULT_COMPOSER_TOOLBAR,
|
||||
...(saved.composerToolbarButtons ?? {}),
|
||||
|
||||
@@ -15,30 +15,21 @@ export type DenoiseModel = {
|
||||
export const DENOISE_MODELS: DenoiseModel[] = [
|
||||
{
|
||||
id: 'rnnoise',
|
||||
name: 'RNNoise (Mozilla)',
|
||||
name: 'RNNoise',
|
||||
description: 'Lightweight hybrid model. Best for consistent noise like fans.',
|
||||
cpuUsage: '< 5%',
|
||||
binarySize: '< 1 MB',
|
||||
transients: 'Poor',
|
||||
voiceQuality: 'Moderate',
|
||||
},
|
||||
{
|
||||
id: 'dtln',
|
||||
name: 'DTLN (Balanced)',
|
||||
description: 'Deep learning model with a good balance of quality and CPU.',
|
||||
cpuUsage: '10-20%',
|
||||
binarySize: '3-4 MB',
|
||||
transients: 'Good',
|
||||
voiceQuality: 'High',
|
||||
},
|
||||
{
|
||||
id: 'deepfilternet',
|
||||
name: 'DeepFilterNet 3 (Pro)',
|
||||
description: 'State-of-the-art studio quality. Removes all background noise.',
|
||||
cpuUsage: '25-50%+',
|
||||
binarySize: '15-20 MB',
|
||||
transients: 'Excellent',
|
||||
voiceQuality: 'Very High',
|
||||
id: 'speex',
|
||||
name: 'Speex (Legacy)',
|
||||
description: 'Classic DSP noise suppressor. Minimal CPU, gentler on voice.',
|
||||
cpuUsage: '< 2%',
|
||||
binarySize: '< 1 MB',
|
||||
transients: 'Poor',
|
||||
voiceQuality: 'Moderate',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -65,4 +56,3 @@ export const ML_DENOISE_REQUIREMENTS = [
|
||||
'Microphone access',
|
||||
'48kHz AudioContext capability',
|
||||
];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user