Commit Graph
5 Commits
Author SHA1 Message Date
Palash DebnathandClaude Fable 5 0ee62b2261 feat(gallery): save gallery voices as profiles, with validated audio references (#1542)
* feat(gallery): save gallery voices as profiles, with validated audio references

Work-in-progress lifted from the concurrent gallery session at the
owner's request (its uncommitted working tree, preserved verbatim from
base 92b1ee5d; safety snapshot remains at rescue/gallery-wip):

- gallery voices can be saved as local profiles: audio is copied into
  the profile store with content-addressed filenames, existing profiles
  are detected and refreshed only when the source clip changed
- backend/core/audio_validation.py: symlink-rejecting, root-contained
  resolution for persisted profile WAV references, with tests
- archetype/community routers and the Voice Gallery UI updated for the
  save-as-profile handoff (spec: docs/specs/longform/26-gallery-use-handoff.md)
- locale updates for the new gallery strings across all 21 files

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore: drop a stray local screenshot script that rode in with the tree copy

* fix(community): explain the tolerated Content-Length parse failure; drop an unused import

CodeQL on #1542: the empty except now says why it is safe (the streamed
byte counter enforces the same cap regardless), and the test file loses
an unused Path import.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(gallery): review findings — copy outside the write lock, no stale completions

CodeRabbit on #1542, all findings addressed:
- the profile-audio copy stages to a .part temp BEFORE BEGIN IMMEDIATE
  and publishes via atomic os.replace inside it — other backend writers
  no longer block for the duration of an audio copy; a mid-copy failure
  leaves no temp droppings and no profile row (both pinned by tests)
- VoiceGallery async ops carry per-operation generation tokens: a
  preview or save-as-profile that resolves after unmount (or after a
  newer operation) can no longer play audio, redirect into a workspace,
  or touch state — three fail-before regression tests
- VoiceGalleryActions imports the page at test runtime; the e2e locator
  uses a stable data-testid instead of a translated string; symlink
  tests skip cleanly where the OS can't create symlinks; the changelog
  line carries its PR ref

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: static ffmpeg fallback when the chocolatey feed is down

Third feed outage to break a PR run (2026-07-20, 2026-07-28, today —
three attempts, three 'installed 0/1'). Chocolatey is a distribution
channel, not the dependency: after the retry loop exhausts, fetch the
static gyan.dev build from its GitHub release mirror and put it on
PATH — same binary, no feed in the path. URL verified live (HTTP 200).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-13 22:48:05 +00:00
Palash Debnath 04410a458d Release VoiceStudio 5.0.0 (#1487)
Complete the VoiceStudio identity, release documentation, assets, version mirrors, and safe cross-platform development startup.
2026-08-11 04:05:45 +00:00
641e660677 fix(shell): LogsFooter becomes a real grid row — bottom buttons can't clip under it at small window sizes (#882)
Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:31:23 +05:30
5c9b7ca313 chore(format): adopt oxfmt for JS/TS/JSX + CI format gate (#774)
Adds oxfmt (Rust formatter, Prettier-conformant) — the repo had no formatter, so
this is a one-time normalization of the JS/TS/JSX code (257 files; purely
cosmetic — full suite stays 638/638).

Scope is deliberately narrowed in .oxfmtrc.json to JS/TS/JSX only:
- singleQuote:true + jsxSingleQuote:false — preserve the project's existing
  style (single-quoted JS, double-quoted JSX attrs), not oxfmt's double-quote
  default. (Flipping quotes globally also broke a source-string-parsing test;
  preserving them keeps featureCoverage green.)
- Excludes **/*.css (the CSS→Tailwind migration will rewrite those — formatting
  them now is wasted churn), **/*.json (avoids reformatting 20 i18n locale
  files + config), **/*.toml, and src-tauri/** (Rust/Tauri config — out of scope
  for a frontend JS formatter; oxfmt was reformatting Cargo.toml/tauri.conf.json).

Tooling:
- `bun run format` (write) / `bun run format:check` (verify).
- ci.yml: new "Frontend format check (oxfmt)" gate after the oxlint gate.

Verified: format:check clean; oxlint 0 errors; vite build; full suite 638/638;
bun install --frozen-lockfile in sync.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:18:01 +05:30
Palash DebnathandClaude Opus 4.8 c857be816a fix(gallery): OmniVoice Gallery rename, dark dropdowns, and noisy/stale archetype previews (#241)
* fix(gallery): rename to "OmniVoice Gallery" + fix dark-theme dropdown colors

The gallery heading now reads "OmniVoice Gallery" (gallery.title, all 21
locales — brand prefix on each localized word).

The facet filter <select>s (Gender/Age/Pitch/Accent/Language) rendered with
the OS-default light control surface on the dark theme: .facet-select set
background/border from --bg-tertiary / --border-color, which are defined
nowhere. An undefined var() reads as transparent on the sibling <div> filters
(fine over the dark page) but falls back to the native light background on a
form control. Switch to the defined dark-chrome tokens and add
color-scheme: dark + an explicit dark option list so the popup matches across
WebKit / WebView2 / WebKitGTK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gallery): archetype previews render a noise buzz instead of voice

The Hype Host, The Podcaster and The Vlogger previews played a loud tonal
buzz, not speech. The preview renderer pinned num_step=16 and seed=42; the
"social" sample script at that exact point lands on a degenerate diffusion
trajectory and collapses to a near-pure tone. The blank-audio guard missed it
because the buzz is loud (peaks near -2 dBFS), not silent — so the garbage was
cached and served. The cache key is (instruct, language) only, so it never
self-corrected.

- Bump preview num_step 16 -> 32: reliably converges to speech across the
  gallery's instruct/script space (one-time, cached render cost).
- Add a spectral-flatness floor (_is_unusable_audio) so a degenerate tonal
  render is rejected like a blank one, reusing the existing retry-on-new-seed
  path. Whisper/breathy voices are broadband (high flatness) so they're safe.

Verified: flatness Hype Host 0.001->0.050, Podcaster 0.0002->0.083,
Vlogger 0.004->0.039; whisper control (Calm Guide) 0.239, not flagged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(gallery): stop preview playback replaying stale cached audio

Preview audio is re-rendered server-side when an archetype is fixed, but the
URL is stable and the response carried no Cache-Control — so the WebView's
HTTP cache replayed the first clip it ever fetched (e.g. the old buzz)
indefinitely, even after the server file was corrected.

- Frontend: fetch previews with { cache: 'no-store' } so playback always
  pulls current bytes.
- Backend: send Cache-Control: no-cache on the preview response so any client
  revalidates against the ETag instead of serving a stale clip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(e2e): add Playwright UI smoke + gallery specs and preview-quality unit test

UI testing system to catch regressions like "Use design → Importing a module
script failed" (a dead Vite/module server) and the noisy-preview bug.

- Playwright (frontend/e2e): drives the system chromium (no browser download)
  against the Vite dev server. ui-smoke mounts all 12 routable views and fails
  on any code-split/import failure, uncaught exception, or ErrorBoundary
  fallback. gallery.spec asserts the "OmniVoice Gallery" heading, the dark
  facet dropdowns (computed bg = rgba(255,255,255,0.04), not the OS-default
  light surface), and that opening an archetype in the Designer mounts the
  lazy CloneDesignTab. `bun run e2e`.
- backend/tests/test_archetype_preview_quality.py: unit-tests the
  _spectral_flatness / _is_unusable_audio guard with synthetic signals
  (tone < threshold < speech < noise; loud tone + silence are unusable) and
  pins the render constants. CI-safe — no model/GPU.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:34:46 +05:30