From 464edbc4fd658728f06d3a7d98340aa28ff3e3ec Mon Sep 17 00:00:00 2001 From: historia Date: Sat, 12 Sep 2026 15:25:06 -0400 Subject: feat: slop web gui --- README.md | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 190 insertions(+), 15 deletions(-) (limited to 'README.md') diff --git a/README.md b/README.md index 1d43285..348b7e3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ # Producer -Local speech cleanup and mastering for voice recordings. Noise removal uses `DeepFilterNet3`. Filtering, dynamics and loudness normalization are `FFmpeg`. +Local speech cleanup and mastering for voice recordings. Noise removal uses +ClearVoice or DeepFilterNet3; speech-aware pause silencing uses Silero VAD. +Filtering, dynamics and loudness normalization use FFmpeg. Audio stays local. `producer.sh` bootstraps its own managed Python environments and downloads dependencies and models automatically. ## Requirements -- glibc +- glibc >= 2.28 for AI denoising and speech detection - `uv` (or Python 3) - NVidia driver and toolkit (optional) @@ -15,7 +17,7 @@ dependencies and models automatically. ```bash git clone https://git.historia.vg/git/producer -./producer.sh setup +./producer.sh setup --denoiser clearvoice ./producer.sh recording.wav ``` @@ -47,12 +49,18 @@ LUFS with a -1.5 dBTP true-peak ceiling**. ./producer.sh recording.wav --denoiser fft ./producer.sh recording.wav --no-denoise -# Use the ClearVoice MossFormer2_SE_48K denoiser instead of DeepFilterNet3 -# (larger download; preserves word attacks noticeably better at high strength) +# Compare ClearVoice MossFormer2_SE_48K with DeepFilterNet3 +# (larger download; speech preservation depends on the recording) ./producer.sh recording.wav --denoiser clearvoice ./producer.sh setup --denoiser clearvoice --device cpu -# Shorten long gaps between takes (speech is never attenuated) +# Silence pauses without changing the timing (enabled in config.toml) +./producer.sh recording.wav --pause-silence --no-trim-silence + +# Bypass pause silencing for an A/B comparison +./producer.sh recording.wav --no-pause-silence --output-dir comparison + +# Optionally shorten long gaps between takes (a separate pacing edit) ./producer.sh recording.wav --trim-silence --max-gap-s 1.5 --gap-pad-s 0.6 # LibriVox-style delivery file: 44.1 kHz, 128 kbps CBR, -19 LUFS, mono @@ -63,6 +71,134 @@ LUFS with a -1.5 dBTP true-peak ceiling**. Edit default settings in `config.toml` +## Optional local browser GUI + +```bash +./producer.sh gui --root /path/to/recordings +# Optional alternate loopback port: +./producer.sh gui --root /path/to/recordings --port 8766 +``` + +The browser studio guides you through **Choose recording → Try a short passage +→ Compare sound → Export full recording**. Use a current desktop browser +(Chromium tested); JavaScript is required. No Node/npm build, CDN, telemetry, +or cloud audio service is used. The launcher installs the optional +FastAPI/uvicorn extra only when `gui` is requested. Existing CLI commands do +not need it. Direct package installs can use `producer[gui]` and need system +FFmpeg or the `bundled-ffmpeg` extra for processing. + +1. Browse folders beneath your chosen root and select a mono WAV. The overview + is a streaming scan reduced to 2,048 peak bins, not a full recording loaded + into the browser. You can enter times before scanning finishes. +2. Click or drag the waveform, or enter exact `HH:MM:SS.sss` start/end times + (seconds also work). Zoom enlarges the same coarse overview; exact times + are best for fine selection on multi-hour recordings. +3. Start with noise cleanup, quiet pauses, tone and even volume. Expand **All + settings & advanced controls** for every other setting and its units/help. + Disabled effects retain their knob values. Nothing renders per keystroke, + and no dependent effect is silently enabled. Click **Render sound comparison**. +4. Play/loop the passage and switch A/B without losing your place. Optional + matching attenuates the louder snippet for fair listening. File loudness + and peak readings are separate from monitoring gain, not quality scores + or full-export measurements. Changes pause playback and mark older renders; + late jobs never replace the visible comparison after you edit the selection. +5. Choose an existing output folder, review the frozen current settings and + confirm **Export full recording**. This processes the entire original even + if you selected only a few seconds. Completed local paths appear in the + export panel; find the files with your operating system's file manager. + +Open the printed `http://127.0.0.1:.../#token=...` URL on the same machine and +keep it private. The server binds only to loopback, rejects untrusted +Host/Origin headers, and requires the session credential for every API read +or mutation. Do not expose it through a proxy or port-forwarding service. +`--root` bounds browsing and output directories, including resolved symlinks; +its default is the current working directory. There are no recording uploads +or arbitrary host-file download endpoints. Stop the server with Ctrl-C. + +**Containers/remote shells:** loopback belongs to the machine/network namespace +running Producer. A browser on the host cannot normally reach a container's +`127.0.0.1`; publishing a container port does not change this loopback-only +binding. The simplest supported setup is to run `./producer.sh gui` directly +on the machine with your browser and recordings. This development container +has no GUI. Do not change the bind to `0.0.0.0`, disable the Host/Origin checks, +or expose the token through a proxy to work around access. No insecure +container-host access mode is provided. + +Settings use the same strict resolver and configuration precedence as the CLI. +The initial controls include your launch TOML and CLI overrides. **Restore +launch settings** resets edits. **Apply profile & launch defaults** resets +through that precedence too: explicit launch values still win. Changing only +the profile name keeps your other explicit knob values. TOML import instead +loads standalone settings (package defaults/profile plus the imported TOML). + +Save up to 20 named settings presets and 12 immutable comparison snapshots per +root in this browser. Snapshots retain the source identity, excerpt times and +requested settings, never audio. **Restore & render** explicitly recreates a +comparison; a changed source file must be re-selected. Download/import small +TOML presets to move settings between browsers. Local browser storage can be +cleared or disabled and is specific to the loopback address/port; use TOML for +backup. Session credentials are never saved in presets or comparison snapshots. + +Waveform scans and jobs run in the background, one at a time, with up to three +waiting. Activity shows per-stage progress, frozen snapshots and cancellation. +Cancellation is cooperative: a model download may take up to 60 seconds to +reach a safe callback, and files already published can remain. There is no +total recording-duration cap; typical 1–4 hour and longer recordings still need +sufficient processing time and temporary disk space. Inputs must be readable +mono WAVs; stereo needs an explicit downmix outside Producer first. + +First AI noise cleanup or pause silencing use downloads dependencies/models; +processing stays local afterwards. For a quick no-model trial, launch with +`./producer.sh gui --root /path/to/recordings --no-denoise --no-pause-silence`. +These explicit flags establish initial controls, not hidden permanent bypasses. +Reload retains the credential in the same tab and reconnects to recent jobs, +but does not automatically restore/play old audio. If Producer restarts, open +its newly printed private URL. If a connection drops during an export request, +check Activity before submitting another export; the first may have succeeded. + +Sound-comparison previews select up to 120 seconds anywhere in a recording, +process with up to 10 seconds of context on each side, then crop to the selected +interval. They are **approximate, not exact export previews**: chapter-level +normalization and inference context differ. Pacing edits are not previewed; +comparisons preserve timing even when export gap trimming is selected. +Normalization and other effects are never forced on for comparison. Optional +loudness matching is playback-only attenuation, not a change to export settings. + +Exports process the whole original with the requested settings into a new, +non-clobbering `producer-export-*` folder in the chosen output directory: +`master.wav`, optional `master.mp3`, and `logs/master.report.json`. The API +returns persistent local paths, **not browser blobs of multi-hour exports**. +The browser only fetches bounded preview snippets. TOML presets can be imported +as text or downloaded; no preset or source recording is rewritten by the API. +The server retains at most eight repeated-result cache entries and 128 MiB of +artifacts; expired previews must be rendered again. Job history is limited to +24 entries and is lost when the server stops, while completed output files +persist. Browser preview WAVs are bounded to about 11.6 MB per side (120 seconds +of mono PCM16 at 48 kHz). Full exports never become browser Blobs. These are +generic WAV/MP3 delivery files, not delivery-platform compliance certification. + +### GUI development checks (optional) + +The application itself needs no browser automation or Node dependencies. With +an external test environment containing `producer[gui,test]`, use: + +```bash +python -m pytest lib/project/tests -q +node --check lib/project/src/producer/web/app.js +node --test lib/project/tests/gui_state.test.mjs +# Optional real headless browser checks, no AI models: +python -m pip install playwright +python -m playwright install chromium +PRODUCER_BROWSER_TESTS=1 python -m pytest lib/project/tests/test_gui_browser*.py -q +``` + +Playwright may need OS-specific browser shared libraries in the test container; +these are not application runtime dependencies. Browser checks generate a +short test WAV, exercise real scan/preview/export and cancellation, and mock a +bounded four-hour overview. They do not claim a four-hour AI processing run. +Screenshots default to `/tmp/producer-browser-smoke`; set +`PRODUCER_BROWSER_ARTIFACTS` to keep them elsewhere. + ## Profiles | Profile | Sound | @@ -72,13 +208,51 @@ Edit default settings in `config.toml` | `radio` | Stronger compression, more warmth/presence, tighter range | | `cleanup-only` | Denoise + highpass only; no EQ, dynamics or normalization | -AI denoisers soften word attacks to some degree; `clearvoice` -(MossFormer2_SE_48K) was measured to leave onsets essentially untouched, -while `deepfilter` ducks them a couple of percent even at reduced strength. -Denoisers also never reach true digital silence: a noise floor remains in -blank sections. `--trim-silence` addresses both properly - long gaps are -shortened to `--gap-pad-s` of untouched room tone with a sample-exact cut, -so speech is never gated or attenuated. +## Speech starts and silent pauses + +Denoising and pause silencing are different jobs. Pushing a denoiser harder +can damage quiet consonants without eliminating all room tone. Compression +and normalization then raise the remaining noise. The shipped `config.toml` +uses ClearVoice at 0.85 strength, speech-aware pause silencing, and **no gap +trimming**. Bare package defaults leave pause silencing off (opt in with +`--pause-silence`). + +Pause silencing detects speech on the **pre-denoise** audio using pinned +Silero VAD v5.1 ONNX weights. First use downloads a separate CPU runtime and +~2.3 MB model; it needs no GPU or cloud service. After EQ/dynamics, gaps +outside protected speech fade to zero before loudness normalization. This +keeps the timeline unchanged unless you separately enable `--trim-silence`. +32-bit export uses no dither so silent cores can remain digital zero; +resampling/filter tails may extend slightly into their edges. MP3 need not +retain sample-exact silence near speech boundaries. + +Defaults protect 120 ms before and after detections, use 10 ms fades, and +require an additional 80 ms silent core. Shorter gaps are left alone rather +than risking chopped words. Controls: + +- `--pause-threshold 0.25`: lower = preserve more possible speech. +- `--pause-pre-ms 180`: protect more of quiet sentence starts. +- `--pause-post-ms 200`: keep longer word tails and decay. +- `--pause-min-ms 40`: allow shorter silent cores after margins and fades. +- `--no-pause-silence`: bypass this stage; no detector download. Combine with + `--no-denoise` to avoid all AI model/runtime downloads. + +The detector can miss whispers, breaths, or unusual speech. If it detects +**no speech**, cleanup fails open with a warning instead of muting the file. +Other detector failures stop processing, not silently switch to a level gate. +Reports in `logs/` include the attenuated intervals on the original, +pre-trim timeline for inspection. With VAD enabled, optional trimming only +shortens near-zero cores; without it, legacy `gap_threshold_db` trimming can +mistake quiet speech for silence. + +This stage does **not** restore consonants a denoiser has already removed. +Compare denoisers and try `--denoise-strength 0.65` if attacks remain soft; +a dry/wet blend trades some noise reduction for speech preservation. +A low, consistent room tone can sound more natural than dead silence. +Professional quality requires listening for artifacts, breaths, sibilance, +clipping and reverb, not just checking a meter. LUFS targets here are not +ACX RMS/noise-floor certification; no one-click chain guarantees every +recording meets a delivery specification. Test the difference on your own audio before committing: @@ -103,5 +277,6 @@ Test the difference on your own audio before committing: [0BSD](LICENSE). -Upstream components (DeepFilterNet, PyTorch, FFmpeg, uv) -carry their own licenses +Upstream components (ClearVoice, DeepFilterNet, Silero VAD, ONNX Runtime, +PyTorch, FFmpeg, uv) carry their own licenses. Silero VAD is MIT-licensed: +https://github.com/snakers4/silero-vad/tree/v5.1 -- cgit v1.2.3