Spaces:
Sleeping
Sleeping
Commit History
-
Add "Load from Backblaze" pickers for turns/captions and text input
Two independent browsers: one for the turns.json + captions pair, one for the general text/subtitle source — mirroring the two existing Drive-link entry points. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>7eb9f97
-
Fail closed on API auth, and compare tokens in constant time
Found in the 2026-08-11 security review of the DO droplet. _check_api_token was `if expected and x_api_token != expected` — it skipped the check entirely whenever the token env var was unset or empty. That is fail-open, and it matters here specifically because Caddy exempts /api/* from the Google OAuth gate (Miscellaneous/droplet-infra/Caddyfile in the monorepo), making this check the *entire* perimeter for those routes. One typo'd env file, or a container recreated without --env-file, would have published the whole API to the internet with no error anywhere — and a missing env var on a redeploy is not hypothetical, it already happened once to TranslationUI's HF_TOKEN. It now returns 503 when unconfigured, matching what _check_hf_token next to it already did; the inconsistency between the two is what gave the bug away. Also switched both token comparisons to hmac.compare_digest so they don't leak length/prefix information through timing. The test fixtures relied on the fail-open pat…f54c348
-
Fix path-traversal via project_id in the new job API
Unlike the UI, which only ever generates project_id itself (slugify + uuid hex, always safe), the new POST /api/jobs and GET /api/projects/{id} endpoints accept it directly from an external caller so an existing project can be targeted. tts/core/project_store.py's local (TTS_DATA_DIR) backend builds a real filesystem path directly from it — _project_path(project_id) = "projects/{project_id}/project.json", joined onto the data root — with no sanitization. An authenticated caller (holding a valid X-API-Token) could pass e.g. project_id=../../../../tmp/pwned for arbitrary file write/read inside the container, which runs as root (no USER directive in this repo's Dockerfile). project_id is now validated against the same safe-slug shape new_project_id() already produces before it reaches the store, on both the job submission and project-read endpoints. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>021451f -
Add async REST job API alongside the existing Gradio UI
Mirrors HuggingFaceSpaces/ArchiveAI-STT's server/api_jobs.py pattern: POST /api/jobs, GET /api/jobs/{id}, GET /api/jobs, GET /api/status, POST /api/drain, GET /api/ping, plus GET /api/projects and GET /api/projects/{id} for an external caller to poll for edits made through the UI (project updated_at changes on every UI edit). Prerequisite refactor: extracted the actual ElevenLabs call (_synthesize_turn_and_store) out of app.py into tts/core/turn_audio.py (synthesize_turn) and tts/core/turns.py (build_project_payload), so both the Gradio UI and the new API can call the same pure functions without either module importing from the other. app.py's version is now a thin wrapper that adds its Gradio-state-specific segment mutation on top. Existing tests patching the old app.synthesize_turn_audio location were updated to patch tts.core.turn_audio.synthesize_turn_audio instead; all 443 pre-existing tests still pass unchanged in behavior. A submitted job runs the same pipeline Turn Review's U…ab0a768
-
Add DO deploy path with local-file project storage backend
project_store.py now supports two backends, auto-selected by environment: local files on a mounted volume (TTS_DATA_DIR set, e.g. DO) or the original HF dataset (HF_TOKEN set, no TTS_DATA_DIR, e.g. the HF Space). Necessary because both deploy targets build from the same main branch — a local-only rewrite would have broken persistence on the still-live HF Space on its next deploy. Local files rather than a database, since most of what's stored here is generated audio, which fits a filesystem more naturally than DB rows. Function signatures are unchanged, so app.py needs no changes. glossary.py is untouched — its existing /data-if-present cache plus best-effort HF sync already does the right thing once a volume is mounted at /data, and the shared glossary dataset is intentionally kept shared between HF and DO (see deploy-do.yml). deploy-do.yml is additive, doesn't touch deploy.yml, and deploys to a droplet shared with TranslationUI: same Caddy instance and oauth2-proxy auth gate (cooki…07e532f
-
Fix turn-audio splice drift; harden Turn Review; add Quick Synthesize tab
Splice/pause (tts/core/pause_synthesis.py): insert_pauses and splice_sentence_audio now shift/space timestamps by the crossfade-adjusted audio length, not the nominal pause/clip length, so regenerated selections splice at the right position instead of drifting later through a turn. Multi-word selections keep internal comma/period pauses (synthesize_clip internal_only). Sentence pauses now fire on ? and ! and before closing quotes (."), not only bare periods; decimals still excluded. Turn Review robustness (app.py, project_store.py): reload with a changed glossary drops the offset map instead of splicing the wrong region; a failed audio download on load no longer lets autosave orphan stored audio+alignment; the sweeper refreshes mtime on render so live-session audio isn't reclaimed, and Download All/Accept guard against a missing file; Create Turns no longer mints a duplicate project (reload on upload/clear, not programmatic .change); per-turn Generate resets the stale regenerate banne…c198355 -
Add per-slot regen settings, enlarge Regenerate Selection button, full test coverage
Each turn's regen box now has its own Model/Speed/Stability/Similarity/Style controls (above the "Regenerate: <selection>" banner, advanced ones tucked into an accordion) instead of sharing the Turn Review tab's global sliders — so adjusting speed for one regeneration no longer silently affects Generate/Generate All. Regenerate Selection is now a full-size ("lg") button instead of "sm", to be easier to see and hit. Verified the rendered layout and event wiring by launching the app and driving it with Playwright, and added a Blocks-config-introspection test (test_app_regen_settings_wiring.py, following the existing test_app_tabs_isolation.py pattern) asserting each slot's regen/retry click events read that slot's own controls, not the shared globals. Also added tests/test_tts_voices.py — validate_speed() (added earlier this session) had no direct unit tests, only indirect coverage through its call sites. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>2172eca -
Reject out-of-range speed before calling ElevenLabs, and clamp speed sliders
ElevenLabs rejects voice_settings.speed outside 0.7-1.2 with a bare 400 — validate it up front (in generate_with_timestamps and _call_el, the two call sites used by turn generation, selection regeneration, and Quick Synthesize) and raise a clear error instead. Also narrow the Speed/Prose Speed/Mantra Speed sliders to that same range so the invalid value can't be picked in the UI in the first place. Also commit tts/utils/net.py and its tests — call_with_retries has been imported and relied on by pause_synthesis.py already, but the file itself was never actually committed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>c1429dc -
Stop preview from disappearing when Play is clicked
Any successful selection event unconditionally hid the open preview group, including a redundant re-fire of the exact same span — which happens when clicking Play on the preview player (the browser appears to re-report the textbox's unchanged selection at that point). Treat a re-fire of the same span with a preview already open as a no-op instead of collapsing the preview back to just the banner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>ee39309 -
Add project nickname + explicit Save button; fix shallow-push deploy failure
Turn Review now mirrors TranslationUI's project management: a Project Name field (renames + autosaves on submit) and a Save button (flushes the current page's text edits and autosaves) alongside the existing autosave-on-blur/generate behavior. Also fix the deploy workflow: actions/checkout@v4 defaults to a shallow clone, which Hugging Face's git server rejects when pushed ("shallow update not allowed") — add fetch-depth: 0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>93c910b -
Fix selection-regeneration blocked by text edits and preview disappearing on play
Allow regenerating a highlighted selection after a small text edit by locating the edit via common prefix/suffix and remapping it into the old word map, instead of requiring an exact match to the last-synthesized text. Also stop an empty/collapsed text selection (which also fires when clicking Play collapses a highlight) from hiding an open preview player. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>9aad88b -
Add Gemini-powered "Create Turns" for VTT/SRT uploads without turns.json
Turn Review previously required both turns.json and translated captions. Now, uploading just captions (VTT or SRT) surfaces a "Create Turns" button that generates turns.json via Gemini, mirroring the July Launch pipeline's speaker_turns.py/gemini_client.py model chain and validation, then saves and loads it through the existing project-persistence path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>1a24191
-
Add Turn Review project persistence with autosave, Generate All, and SRT captions
Every turns.json + translated-captions upload now becomes a saved project on the private GarchenArchive/tts-turn-projects dataset, mirroring TranslationUI's project_store pattern: raw source files, settings, and per-turn text/alignment/audio are autosaved as the user works (on generate/regenerate/accept, textbox blur, and page navigation), so nothing is lost on a closed browser tab and a project can be reopened later from any computer via the new project picker. Also adds a sequential "Generate All" batch action, and SRT support for the translated-captions upload (previously VTT-only in Turn Review). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>a69c6ab
-
Add word-level highlight-to-regenerate for Turn Review audio
Highlighting any text in a turn's textbox (down to part of a single word) snaps to the whole word(s) touched and offers to regenerate just that span via ElevenLabs, previewing the take before splicing it into the turn's existing audio at the exact time offset from its original character-time alignment, with a crossfade at each cut and downstream timestamps shifted to stay correct for further edits. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>bd5fe5b -
Merge remote-tracking branch 'hf-tts/main'
c43ffcc -
Add sample SRT/text fixtures for manual TTS testing
Kept as reference examples for exercising the synthesis pipeline by hand. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>6ac04bc
-
Make ElevenLabs pause/audio tags model-safe, add turn-audio temp file cleanup
Protect <break .../> (v2) and [pause]-style (v3) tags from mantra-detection, glossary substitution, and the Turn Review pause-splicing so they always reach the API unmangled, and document the v2 break-tag syntax in the app description. Turn Review's generated mp3s now live in a dedicated temp dir with a background sweep plus per-regenerate cleanup, so they no longer accumulate indefinitely. Also verified (with a regression-guard test against the real Gradio event graph) that Glossary-tab actions and tab switching never touch Turn Review's audio or state. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>7e54bd7
-
Add advanced voice setting controls (stability, similarity boost, style)
Surfaced in a collapsed accordion with a note that the production-validated defaults shouldn't normally be changed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>794b80f -
Add Turn Review tab for editor approval of AI-drafted interpreter turns
Loads a chunk's turns.json + translated VTT, windows captions per turn (mirroring the July Launch pipeline's step 8), and lets an editor adjust text and generate/listen/download interpreter audio per turn with real pause insertion (room-tone splicing after commas/periods via ElevenLabs' with-timestamps endpoint, ported from tts_insert_pauses.py) instead of plain single-shot synthesis. Moves the pronunciation dictionary to a HuggingFace dataset-backed glossary (tts-glossary) so entries persist across Space rebuilds and are shared, seeded with the pipeline's validated digraph respellings. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>be2032d
-
feat: segment editor with timestamps, editable text, pagination
- Parsers now return {timestamp, text} dicts instead of plain strings - Segment editor shows one slot per subtitle block with timestamp chip and editable textbox; slots paginate in groups of 20 - Fixed persistent "processing" overlay caused by gr.Column visibility toggle in Gradio 6: editor column is now always rendered, slots control their own visibility - Upgraded Gradio requirement to >=6.9.0; launch with ssr_mode=False - Updated parser tests for new dict return format Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>5adf3e7
-
Replace Kokoro TTS with ElevenLabs API
Removes the local Kokoro ML model (~1.5GB Docker image) in favour of the ElevenLabs REST API. Key changes: - tts/core/synthesis.py: rewritten around _call_el() using pcm_24000 output format; two synthesis paths toggled by mantra_mode flag - tts/core/voices.py: new module for EL client construction, voice listing, and instant voice cloning - tts/core/pipeline.py: deleted (Kokoro KPipeline, g2p, IPA lexicon) - tts/lexicon/phoneme_lexicon.py: deleted (IPA corrections dropped) - app.py: API key accordion, dynamic voice dropdown, mantra mode toggle, Voices tab with Available Voices + Clone a Voice sub-tabs - voices/: new directory for pre-placed voice sample files - Dockerfile: stripped to plain pip install (~200MB vs ~1.5GB) - requirements.txt: torch/kokoro/misaki replaced by elevenlabs>=1.0.0 - tests: 90 tests passing; synthesis tests rewritten for EL mocks The user pronunciation dictionary (plain-English text substitutions) is unchanged — it is applied at the text level before an…7b3dc39 -
Initial commit — ArchiveAI TTS Gradio app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>f9cbb13