Commit Graph
26 Commits
Author SHA1 Message Date
Palash DebnathandClaude Opus 4.7 90ef02b2e4 chore: unique ports (3900/3901) + broader CI caches (#20)
Two unrelated tweaks grouped into one PR to keep churn low.

## Ports

Backend 8000 → 3900, Vite dev 5173 → 3901, 3902 reserved for future
IPC. Port 8000 conflicts with Django/Rails/Jupyter/Airflow on most
dev machines; the uncommon 3900 range dodges that. Touched:

- frontend/src-tauri/src/lib.rs (BACKEND_PORT)
- frontend/src-tauri/tauri.conf.json (devUrl)
- frontend/vite.config.js (server.port)
- frontend/src/api/client.ts (hardcoded API base)
- frontend/src/App.jsx (PREVIEW_API fallback)
- backend/main.py (CORS allowlist + uvicorn.run default)

Rust sidecar launcher and FastAPI uvicorn port stay in sync via the
`BACKEND_PORT` constant + explicit port=3900.

## CI caches

Build time shaves across ci.yml and release.yml:

- `astral-sh/setup-uv@v3` → `enable-cache: true` keyed on uv.lock
  (~45 s saved per run after uv.lock stabilises)
- `awalsh128/cache-apt-pkgs-action` for ffmpeg (~25 s saved)
- `actions/cache@v4` on `~/.bun/install/cache` keyed on bun.lock
  (~15 s saved; applied to both test gate and build matrix)

Expected warm test job: ~45-60 s (was ~2-3 min).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 06:52:30 +05:30
Palash DebnathandClaude Opus 4.7 e57448f704 fix(settings): delete model button — encode HF repo_id per segment (#19)
`encodeURIComponent("voxcpm2/voxcpm2-2B-EC")` turns the slash into
`%2F`, which some ASGI layers reject or fail to roundtrip through the
`:path` converter. Frontend was sending `/models/voxcpm2%2Fvoxcpm2-2B-EC`
and getting a silent no-op (or 404 swallowed by the busy-state wrapper).

Encode each path segment instead so special chars in the repo name
still escape but the slash survives as a literal `/` in the URL.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 06:38:38 +05:30
debpalashandClaude Opus 4.7 93d8cd70d5 feat: pre-flight system check + actionable error surfacing
## /setup/preflight endpoint (backend/api/routers/setup.py)
New one-shot health check the setup wizard calls before model install.
Probes every runtime requirement so GPU driver mismatches, missing
ffprobe, low RAM, stale AMD ROCm setups, and unreachable HF no longer
manifest as silent CPU fallbacks or opaque runtime errors.

Checks returned as {id, label, status, detail, fix?}:
  - Operating system + arch
  - Python runtime
  - System RAM (fail <8 GB, warn <12 GB)
  - Disk free on HF cache partition (fail <10 GB)
  - HuggingFace cache writable
  - FFmpeg (required)
  - FFprobe (warn — some endpoints degrade without it)
  - GPU acceleration — vendor-aware detection:
      * Apple Silicon  → MPS available?
      * NVIDIA         → nvidia-smi parse; fail if driver < R555
                         (cu128 wheels we ship need ≥ 555)
      * AMD            → rocm-smi detect; warn if torch not built w/ ROCm
      * none/unknown   → warn, CPU-only note
  - Network reachability to huggingface.co:443

Aggregate: {ok, has_warnings, checks, device}. Wizard blocks forward-
nav on any fail; passes warnings through with a labelled Continue.

## SetupWizard 4-step flow (frontend/src/pages/SetupWizard.jsx)
Insert "System check" as step 1 between Welcome and Install models.
Renders preflight report with pass/warn/fail icons, inline fix
instructions, and a Re-check button for users who resolve a blocker
without restarting the app. Continue button labels shift based on
status ("All good — continue" / "Continue (with warnings)" /
"Resolve blockers to continue").

## Transcribe-stream error clarity
dub_core.py: move ASR / missing-audio preflight out of HTTP-status
error paths into in-stream `error` events, since EventSource on the
client can't read non-2xx bodies and previously surfaced 503s as
opaque "network error" strings. Users now see the actionable message
(e.g. "ASR isn't loaded yet — check Settings → Models") inline.

App.jsx: on transcribe-stream drop before any final segment, force-
close + reject with a pointed message instead of waiting for
EventSource auto-reconnect to thrash against a broken endpoint.

## API client (frontend/src/api/setup.ts)
Add PreflightReport / PreflightCheck / PreflightDevice types + preflight()
call matching the new endpoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:19:16 +05:30
debpalashandClaude Opus 4.7 e1966bdcd9 feat(ui): chrome theme + retina typography + launchpad charisma + export drawer + setup wizard + projects + logs footer
## Typography system
- Add Fontsource variable fonts: Inter, IBM Plex Mono, Source Serif 4
- Unify via --font-sans / --font-mono / --font-serif / --font-display
  tokens in ui/tokens.css
- Enable OpenType features globally: cv11 (single-story a), ss01, ss03,
  zero, tabular-nums slashed-zero; font-optical-sizing: auto;
  font-synthesis: none
- Alias legacy --chrome-font-mono to var(--font-mono); purge Google Fonts
  @import and hardcoded "ui-monospace, Menlo" refs across 43+ rules

## Chrome design tokens
- Migrate every panel/button/input to --chrome-* tokens with
  color-mix(in srgb, … N%, transparent) tone tints
- Flat-chromed .glass-panel, .studio-panel, .main-content, .launchpad,
  sidebar, segments, clone/design textarea, settings subsurfaces,
  export drawer, footer, modals
- Kill radial gradients, paper-grain noise, 30s mesh animation
- Rewrite Badge.css, Button.css, Tabs.css, Table.css to chrome tokens

## Launchpad charisma
- Aurora backdrop: three drifting blurred blobs (pink 22s, green 28s,
  amber 32s) behind everything at z=0
- Hero halo + animated sweep line under H1
- Wave bars with per-bar --bar-delay / --bar-dur for breathing stagger
- Action cards: single --card-hue drives bg/border/glow/spotlight
- Cursor-tracked spotlight via onMouseMove → --mx/--my custom props
  → radial-gradient paint (no JS re-renders)
- Eternal breath ring via .lp-glow-layer::after, staggered across
  three cards via :nth-child animation-delays
- All animations gated by @media (prefers-reduced-motion: reduce)

## Export drawer (new)
- ExportModal.jsx/css: 4-tab bottom drawer (Video / Audio / Subtitles
  / Package) rendered via createPortal
- Presets (YouTube, Archive, Web, Podcast, Study), per-track checklist
  with All/None/Dubs-only, MP3 bitrate 128/192/256/320
- Non-blocking: pointer-events: none on outer, auto on sheet; ESC + click
  outside to close
- DubTab: FooterBtn → React.forwardRef; export trigger opens drawer

## Dubbing ETA
- Show elapsed time during generation; genElapsed state + fmtDur helper
  renders .dub-gen-overlay__stats block

## Setup wizard (new)
- SetupWizard.jsx/css: first-run flow for engine probing, model downloads
- Projects.jsx/css: dedicated projects browser page
- LogsFooter.jsx/css: slide-up logs panel
- api/setup.ts: client for setup router endpoints
- App.jsx, NavRail, Header, store wired to new pages

## Version
- frontend/package.json 0.2.0; refresh bun.lock

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:49:44 +05:30
debpalash 52d68d05dc refactor: update backend architecture, expand frontend state management, and synchronize voice-pro research modules. 2026-04-21 18:32:25 +05:30
debpalash 6f124fb175 feat: implement frontend UI components and expand research documentation for voice processing and translation workflows. 2026-04-21 04:31:08 +05:30
debpalash 2c3e12d8de feat: implement responsive layout adjustments for small screens and add cached status visualization to dubbing workflow 2026-04-20 11:33:30 +05:30
debpalash 6e89db0f77 feat: add YouTube/URL ingestion support using yt-dlp and update UI with granular preparation progress tracking 2026-04-19 17:54:07 +05:30
debpalashandClaude Opus 4.7 ee0f8ce64c feat: error boundaries, sidebar search, keyboard cheatsheet, cross-platform tauri configs
- ErrorBoundary wraps each lazy route (Launchpad/Clone-Design/Dub/Settings).
  Crash in one tab → friendly fallback card; rest of app stays functional.
  Errors surface to Settings > Logs > Frontend via console.error ring buffer.
- Sidebar search input (pill shape at top of scroll area) filters projects,
  profiles, gen history, dub history, exports by name/text/seed/path.
- KeyboardCheatsheet: press '?' to open, grid of shortcut kbd pills
  (Navigation / Segment editor / Audio trimmer / Dub). Mac+Windows key labels.
- Dub thumbnail: Launchpad DubProjects cards now load /dub/thumb/{id} via
  DubThumb component with graceful fallback to film icon.
- Tauri cross-platform:
  * tauri.conf.json keeps Overlay+hiddenTitle (macOS-only, ignored elsewhere)
    so mac traffic lights float inside our Header instead of two-bar stack.
  * tauri.macos.conf.json: transparent + minimumSystemVersion 12.0.
  * tauri.windows.conf.json: NSIS + MSI bundles, webview bootstrapper.
  * tauri.linux.conf.json: AppImage + deb + rpm, deb depends on ffmpeg
    and libwebkit2gtk-4.1-0.
- Dub tab idle: right ghost panel hidden until upload; drop zone spans full
  width. Converted 8 glass-panel wrappers to studio-panel.
- Sidebar dub history: filter out empty/und/Auto language tokens (no more '()').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 05:50:22 +05:30
debpalashandClaude Opus 4.7 810e09bd0e ui: fix dub history '()' artifact + full-width idle drop zone
- Sidebar dub history subtitle: filter out empty/"und"/"Auto" language tokens
  instead of rendering "English (und)" → "()" style literals.
- DubTab idle state: when no video loaded, hide right ghost panel and
  let left drop-zone panel span both columns. Prevents looking "broken"
  before upload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 05:08:33 +05:30
debpalashandClaude Opus 4.7 15ef65a686 refactor: extract App.jsx into pages/components/api, add studio design pass + NavRail
Frontend:
- Split App.jsx (2850 -> ~1300 lines) into pages/{Launchpad,CloneDesignTab,DubTab,Settings}.jsx
  and components/{Header,Sidebar,NavRail,CompareModal,DubSegmentTable,DubSegmentRow}.jsx.
- Centralize every fetch through api/{client,dub,generate,profiles,projects,system,exports}.js
  with consistent ApiError + JSON error detail extraction.
- Extract utils: constants (TAGS/CATEGORIES/PRESETS/POPULAR_*), languages (LANG_CODES),
  format (formatTime/probeAudioDuration), consoleBuffer (ring for Settings > Logs > Frontend).
- Lazy-load AudioTrimmer, DubSegmentTable, Launchpad, CloneDesignTab, DubTab, Sidebar, CompareModal, Settings.
  Initial bundle 438KB -> 220KB (-50%).
- Virtualize segment table (react-window) + React.memo row; dynamic row height when
  original text row shown. Fix {proj.is_locked && ...} rendering literal "0" on falsy.
- Segment UX: multi-select + bulk voice/lang/delete, Ctrl+D split-at-cursor,
  Ctrl+M merge-with-next, search/filter/speaker filter, char-budget warn
  when translated text >1.3x source, preserve text_original across translations,
  always stream segments via EventSource /dub/transcribe-stream.
- AudioTrimmer: pro-grade zoom/pan/scrub, rAF-throttled drag, peak precompute
  + async refine (keeps UI responsive on 1700s mp3), keyboard shortcuts,
  click-drag = fresh selection, loop preview, Enter/Esc/Space/Home/End bindings.
  Tests: 22 cases in tests/frontend/audioTrim.test.mjs cover encodeWav header,
  peak min/max invariants, drag modes (start/end/region/pan/new), zoom math,
  slice-to-mono, tick interval picker.
- NavRail: left/right vertical icon rail (VS Code style), side persisted to
  localStorage. Removes tab group from Header.
- View-specific sidebar: hidden on Launchpad/Settings; dub gets 3 tabs; clone/design 2.
  app-container grid updated with sidebar-hidden / rail-right variants.

Design pass (hand-drawn "cute" identity):
- Fraunces italic serif for headlines, Nunito rounded sans for body.
- Wobbly non-uniform border-radius on cards/buttons/inputs.
- Warm peach/rose/lime palette across Launchpad, Settings, Header, panels,
  sidebar items, segment table.
- Header HQ: view breadcrumb (pulsing dot + kicker + accent-colored view label
  + active project), live mini-waveform reacting to model status.
- Settings: tabbed Models / Logs / About / Privacy with accent-colored pills;
  Logs sub-tabbed Backend / Frontend / Tauri.
- Clone/Design: two columns, each split into two studio-panels (prompt vs lang/steps;
  voice source vs overrides+synth). Rectangular corners + launchpad-warm gradient.
- Dub tab: migrate panels to studio-panel look.
- Sidebar item overhaul: kind pill + ago timestamp + hover-reveal pill actions,
  accent left-edge bar on hover, click-whole-card = primary action.

Backend:
- Per-segment translate retry + auto-src fallback; surfaces errors per-segment
  with logged type. Tests: 9 cases in tests/test_dub_translate.py (code coverage,
  source-lang resolution, retry/auto fallback, empty text handling).
- Thumbnail extraction during dub upload (ffmpeg @ ~10% offset, scale 320px wide)
  served via GET /dub/thumb/{job_id}.
- Preserve text_original during transcription so cross-language retranslations
  re-run from pristine source, not compounding on prior translation.
- Settings endpoints: GET /system/info, GET /system/logs?tail=N,
  GET /system/logs/tauri, POST /system/logs/clear. FK-safe profile_id NULL on
  history insert to avoid "FOREIGN KEY constraint failed" on stale/preset ids.
- /dub/transcribe-stream SSE: chunked mlx_whisper / pytorch pipeline per 30s
  window, diarization final pass, honors job.aborted.

Tests: 22 frontend trim + 9 backend translate all pass. Production build 220KB
gzipped (from 127KB main-only pre-split, which hid unshipped modules in main).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 04:52:54 +05:30
debpalash 508d4ba116 feat: add audio trimming for reference clips, implement streaming transcription, and refactor ffmpeg utility handling 2026-04-18 22:37:20 +05:30
debpalashandClaude Opus 4.7 67328d04fe refactor: split backend into api/core/services/schemas, harden security + fd pressure, add searchable language picker, fix segment fragmentation
Backend:
- Split monolithic main.py into backend/{api/routers,core,schemas,services}
- core/db.py: allowlist-gated migrations, db_conn context manager (kills SQL injection on ALTER)
- core/tasks.py: lock-guarded listener add/remove/push, snapshot-before-iterate
- services/ffmpeg_utils.py: run_ffmpeg helper with concurrency semaphore, EAGAIN retry, guaranteed reap
- services/segmentation.py: Bengali/CJK/Arabic punctuation, ultra-short tier, stitch_adjacent_shorts,
  bounded-loop merge; public clean_up_segments API
- services/model_manager.py: robust lock.locked() handling
- api/routers/dub_core.py: job_id traversal guard, thread-safe _active_procs, timeouts on ffmpeg/demucs,
  POST /dub/cleanup-segments endpoint
- api/routers/dub_export.py: guarded SSE listener remove, ffmpeg timeouts via run_ffmpeg
- api/routers/exports.py: destination_path validation, safe source resolver, subprocess list-form
- api/routers/generation.py: contextlib.suppress on tempfile cleanup, db_conn usage, safe output-path helper
- api/routers/system.py: try/finally tmp cleanup, subprocess timeouts
- schemas/requests.py: TranslateSegment.id int->str to match hex segment IDs
- main.py: threading.Lock around crash log writes

Frontend:
- components/SearchableSelect.jsx: popover combobox with search, keyboard nav, popular+recent pins, 200-item cap
- App.jsx: wire SearchableSelect for dub language / ISO code / voice-gen language; Clean Up segments button;
  fix blob URL leak (object-shaped prev in setter, unmount cleanup via ref)
- components/WaveformTimeline.jsx: explicit <video> detach instead of innerHTML='' to release decoder
- index.css: ss-* combobox styles matching Gruvbox theme

Tests:
- tests/test_segmentation.py (26 cases), test_dub_transcribe.py, test_dub_export_unique.py, conftest.py

Chore:
- .gitignore: exclude omnivoice.zip, /research/ reference clones
- Remove tracked stray root test scripts + crash_log.txt

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:20:19 +05:30
debpalash d2cab558c3 refactor: enable window state persistence, refine UI layout, and fix voice generation logic to prevent reference audio leakage and attribute errors 2026-04-15 05:10:16 +05:30
debpalash f0ec88c66d refactor: redesign sidebar navigation buttons and add a JSX tag validation script 2026-04-14 20:32:07 +05:30
debpalash cd8cbe6243 feat: implement file export history, native folder reveal, and robust FFmpeg/torchcodec environment management. 2026-04-14 19:40:26 +05:30
debpalash d79b6f6d04 feat: rebrand to OmniVoice Studio, add cross-platform icon assets, and implement backend audio preview proxy for WebKit compatibility 2026-04-14 16:15:27 +05:30
debpalash 788f808db9 feat: initialize Tauri desktop application with window management and custom styling 2026-04-14 05:39:29 +05:30
debpalash 5668aff528 feat: add Docker support for containerized deployment and serve static frontend from backend 2026-04-14 04:35:04 +05:30
debpalash 3a8adf5dd4 feat: implement streaming TTS, A/B voice comparison, and background task processing with SSE updates 2026-04-14 04:00:38 +05:30
debpalash f31c44040b feat: implement v1.2.0 production features including undo/redo, per-segment gain control, model telemetry, and UI polish. 2026-04-14 02:14:12 +05:30
debpalash eba72517fe feat: add voice previewing, keyboard shortcuts, and enhanced dubbing export options 2026-04-14 02:06:11 +05:30
debpalash bf5e1cb532 feat: implement waveform timeline component and refine UI with a compact, high-density design system. 2026-04-13 18:24:14 +05:30
debpalash 5c4674d709 refactor: simplify README documentation and update API and frontend to support voice design features 2026-04-10 03:51:40 +05:30
debpalash 053e3c8463 feat: add system monitoring dashboard, react-hot-toast notifications, and expanded language support 2026-04-10 03:36:07 +05:30
debpalash eb2e9988f6 chore: flatten project by moving all contents from submodule to root 2026-04-10 02:53:23 +05:30