Commit Graph

211 Commits

Author SHA1 Message Date
e52a73c868 fix(tts): custom engine availability follows health, not the library voice list
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 05:18:52 +02:00
0551b6651f feat(voices): redesigned My Voices list, working copy, engine-aware TTS availability
My Voices
- Top bar with search, filter toggle (active-count badge), synth-source drawer, group and table buttons;
  filters/sort in a collapsible labelled panel; one-line sort header with select-all/none checkbox
- Groups chip list is a collapsed accordion; bottom bar is Refresh/Sync/Import plus one Actions (N) menu
  (Edit / Audio / Share / Danger), disabled until voices are checked; touch targets stay 44px
- Copy selected works again (copyText was no longer exported), shows "N voice names copied to clipboard"
  and falls back to a copy dialog when the async clipboard is unavailable

TTS / engines
- Health probe works for /v1 card URLs and, behind a LiteLLM gateway, checks the selected model's own
  upstream so stopped containers are not reported as available
- Unhiding a voice publishes a missing entry to the engine's voices.json (no more silent default-voice fallback)
- Status-bar TTS picker also drives the My Voices and STT-test selectors; Use as TTS refreshes the status bar

Includes the engine connect/disconnect, custom TTS, STT footer and magazine auth work that was already
in the working tree, with their tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-11 04:44:27 +02:00
sparky
402fd52f40 fix(sonar): drop redundant optional group in audio-link regex (python:S5842)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 11:31:20 +02:00
b60586a559 fix(sonar): compare speed with math.isclose instead of float equality (python:S1244)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 03:51:32 +02:00
1d65a4df7c fix(sonar): remove unused variables and commented-out code
Removes 43 small Sonar findings (unused locals, dead helpers, a misread comment); behaviour unchanged. CHANGELOG entry was already swept into 9f78a15.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 03:42:44 +02:00
e7a25d80ff feat(conversation): metrics view with TTFB charts and token usage
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 00:48:32 +02:00
2479617964 fix: run blocking requests/sleep in async routes via to_thread
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 00:40:34 +02:00
8ce8e791b2 feat(conversation): thinking on/off switch
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-06 00:21:11 +02:00
668681dd24 fix(security): private temp dir for docker installer, https for OMDb, md5 non-security flag
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 18:57:34 +02:00
4f30ee5c0d fix: keep references to background asyncio tasks
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 18:57:20 +02:00
2a06d0a488 fix(export): ship untagged file when provenance tagging fails
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 18:38:42 +02:00
fece9122d1 feat(voices): archetype catalog and API
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 18:10:35 +02:00
c0a5d54763 fix(voices): robust LibriVox search and expose export_provenance_default
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 18:07:22 +02:00
772c43d7f0 feat(voices): LibriVox and Wikimedia Commons voice sources
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 17:42:36 +02:00
9b169037a4 feat(tts): inline tags in generate, audiobook and magazine paths
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 17:35:18 +02:00
5a7c73ea42 feat(export): provenance tags and optional disclosure for exported audio
ID3 provenance tags (synthetic speech, generator, version, date, opt-in
voice name) on magazine MP3/ZIP/EPUB exports via a stream-copied temp copy;
verify endpoint and CLI; AudioSeal tier is a documented stub.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 17:02:41 +02:00
8b51487a64 feat(tts): inline pause, spell and speed tags
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:52:23 +02:00
91843e95e6 feat(voices): optional vocal isolation for URL imports
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:50:14 +02:00
e0daafd4e1 feat(voices): export and import voice bundles
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:42:28 +02:00
781bf6e7f2 feat(voices): consent and provenance field per voice
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:39:32 +02:00
b36423457b feat(design): auto-pick the best seed by scored candidates
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:37:58 +02:00
a0cd7b867f feat(voices): show audio problems in the voice library
Single-voice health endpoint (GET /api/voices/{id}/health), problems stored in
meta on import, shown in the Try-out voice panel; architecture note and docs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:35:10 +02:00
19283a53a4 feat(voices): timestamped audio problem flags in voice health
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-04 16:10:56 +02:00
48af2b3ccb feat(magazine): detect continuation pages and suggest titles for untitled articles
"Page N" entries come from review stand-ins created after Approve saved only
the visible page's regions. New core/magazine_untitled.py classifies untitled
entries (continuation, article head, advert, picture page, contents, junk),
proposes merges into the previous article with confidence and evidence
(optional LLM check in the ambiguous band), and suggests titles
(deterministic, optional validated and cached LLM titles). Exposed through
derived GET /articles fields, GET /untitled, quality report, undoable
merge-into-previous / accept-title routes, POST /titles/suggest and
scripts/magazine_untitled.py (dry run by default, --apply backs up first).
Merges mark audio_stale; no audio is deleted; real titles are never
overwritten.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:36:29 +02:00
7eabdf0e43 feat(characters): distinct deterministic face profiles per character
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 14:25:56 +02:00
1f812d2faf fix(characters): merge profiles only on real names, keep other cast names, reasoning and foreign quotes out of a character
Real-library audit (270 records) traced the data damage to:
- identity matching on ANY shared token ("Zwerg", "der Zwerg", "Mann") with
  "longer text wins" merging (Arthag b02 = Kolon's species/relationships), and
- csRosterCanonicalName renaming a sheet to the first cast name among its
  aliases, which saved 16 whole-sheet copies (Zwerg/Kolon = Arthag b03,
  Fremder = Mann, Alchimist = Promos ...).

Fixes:
- static/js/character-identity.js + core/character_records.py: generic labels
  are never identity evidence; csFindMergeKey, csConsolidateAliasDuplicates,
  csRosterCanonicalName, clSameIdentity use it; own name always wins; clUpsert
  writes to the exact-name record before any alias scan; no seed rename onto a
  name that has its own record.
- _charsheets_parse: in cast-target mode drop other cast members' names from
  aliases / first / last name (Kolon: "Sharraz Garthai"), strip reasoning
  leakage ("Warte:", "Der Text sagt ...") from every text field.
- _character_scene_evidence: only a quote naming the character is used,
  otherwise its own mannerisms (16 panels showed another character's scene).
- _character_age_category: Junge/Mädchen/boy/girl, number words, Sommer/
  Winter ages, evidence clause, age-tagged quotes; "15 Jahre älter" is no age.
- scripts/audit_character_records.py (read-only) and
  scripts/clean_character_records.py (dry run by default, --apply backs up).

Tests: tests/test_character_record_hygiene.py, tests/character-identity.test.mjs.
Docs: architecture/character-extraction.md, Manual, CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:09:53 +02:00
04f791e1f5 feat(characters): translate character info to English before image prompts
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 12:01:42 +02:00
4fd21b1d1c fix(characters): base dwarf body lock and species text on the character's own species assertion
Extraction notes in race_species that mention another character's species
("Mensch (oder Zwerg, ...)", "... 'Der Zwerg' wird separat erwähnt ...")
switched on the dwarf body lock (short legs, full beard) for human characters
and carried a sentence about another character into the Subject clause.
Confirmed on the real library: Marrad, Kolon and Arthag (book 02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 11:09:19 +02:00
9e5ea609ce feat(magazine): word-level timing via forced-aligner sidecar with player word highlight
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 00:37:40 +02:00
788f186b9c fix(magazine): use sentence timings of interview renders for player and EPUB
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-03 00:09:45 +02:00
084a99af2c fix(characters): isolate image generation per character
Bind the consistent-image Idempotency-Key to the character request so a reused
key cannot return another character's job; add back-to-back and concurrent
two-character regression tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 22:34:07 +02:00
63034b07eb fix(magazine): record where speech starts in each sentence so the highlight is not early
The TTS pads every sentence with 0.4-0.9 s of silence; boundaries are exact but the
highlight lit up that long before the words. Record per-sentence speech onsets at render
time, measure them from the decoded MP3 for older audio, and expose them as 'speech' in
/timings.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 14:57:30 +02:00
904d6a432c fix(characters): accessory pictures show only props, no body parts
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 12:33:33 +02:00
270b8d56ca fix(magazine): driving-mode text and picture follow the recorded sentence times
Adds GET .../articles/{id}/timings (exact per-sentence times via plan_sentences); the player uses them, falls back to the length estimate, and gives captions no time slot.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 11:51:58 +02:00
d4099e45c6 fix(characters): remove the gutters between the concept sheet panels
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 08:12:15 +02:00
1a527c3b41 fix(characters): ground the concept sheet's lower pictures in the character and the book's world
The story moment was a ~5,400-character prompt whose period rules sat at
the end, out of reach of the 4-step model; it opened with "ears clearly
visible" and asked for studio photography by a photographer with a real
actor, and drew a modern man with headphones and a camera in a garden,
captioned with pseudo-text. The prop tile was a stock catalog photo. The
negative prompts were inert because those samplers run at cfg 1.0.

Story moment and signature-item prompts are now short, world-first and
positive-only: The Dark Eye, 900-1300 AD and the book profile's setting
(never the title), the same identity, appearance and costume as the
turnaround, the book moment, a period background and a hand-made,
unmarked world; the item is the character's own, in the craftsmanship
and colours of their costume, on a table in a medieval room. Text and
modern objects are added to the scene and prop negatives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 08:00:53 +02:00
6d1c6c1b88 fix(characters): remove divider lines from the concept sheet
The sheet composer drew light lines between the three poses and between
the top and bottom rows, cutting through capes and swords.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-02 07:49:19 +02:00
80ec22b752 fix(magazine): deleting a picture removes both of its records; say clearly while a turn is being read
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 18:35:20 +02:00
884bbf33aa fix(magazine): a turned page shows at once (versioned picture URLs), turns are visible and undoable, one turn at a time
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 13:35:25 +02:00
130fd273c6 fix(magazine): read a turned page through a ladder (turned, original with carried boxes, tesseract)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 12:31:44 +02:00
6fdf9fbc38 feat(magazine): turn a page scanned sideways or upside down and read it again
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 12:13:13 +02:00
9ad881ada8 feat(magazine): manage OPDS catalogues in the app, env-based login, result paging
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 11:03:03 +02:00
268ed391a3 feat(magazine): EPUB 3 Media Overlay export with measured sentence timings; tolerate missing mutagen
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 10:33:08 +02:00
4a20a12f66 feat(magazine): show sidebars in the reading view as labelled, never-narrated asides
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 10:26:27 +02:00
0005ae0ebd feat(magazine): import a magazine from PNG/JPEG page images
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 10:19:14 +02:00
3f4dfb70a4 fix(characters): harder gender/period locks in scene prompts, no unchecked sheet overwrites a validated one, weapon wording only for armed characters, poll survives 5xx blips
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 21:20:56 +02:00
c3c5c55f17 feat(magazine): find and import issues from the Internet Archive and OPDS catalogues
Also reuses the existing magFmtClock for the contents list (the duplicate
tripped the frontend collision gate).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-29 17:35:08 +02:00
f0b5d5aa68 feat(magazine): run the whole-issue Auto-fix pass automatically after import
A fresh import used to stop once laid out, leaving missed text, unverified
OCR and provable misspellings for a separate manual click. _ingest_sync now
runs _quality_run_sync itself, under the same job, so the ingest progress
bar carries through it and the reviewer opens an already-worked magazine.
An Auto-fix failure is reported as an ingest failure without losing the
ingest's own result.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 09:37:28 +02:00
ac1153b782 fix(magazine): re-check for duplicate boxes after box-fitting/seam-mending grows them
The duplicate detector only ran once, before geometry fixes could merge or
grow a box into one that now duplicates another's text -- narrating it
twice. Now re-run after the geometry loop at ingest and after
recover_missing_text in the whole-issue quality run. Confirmed live: 13
such duplicates in a fresh import, 6 in the already-reviewed magazine.

TODO: F decided unnecessary per user; G updated with both universal fixes
from this pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 08:50:13 +02:00
d06f990379 feat(magazine): fast LLM calls for spelling agent, run-together word repair, magazine comparison tool
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 20:09:42 +02:00