Fish-Speech emotion tags were silently ignored on non-English books: per-line
emotions are LLM-generated in the book's own language, but Fish-Speech only
recognizes English [tag] markers, and a double-tagging bug was stacking a
broken server-derived tag on top of the client's own. Added a DE->EN
translation table and removed the double-tagging. Also wires the existing
book-profile context and race_species field into character portrait prompts
(previously only used for voice design), adds a recast-until-threshold loop
for casting, and adds backend-aware emotion quick-picks to Read Aloud, Try a
Voice, and Conversation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Introduces the new Studio section (Source -> Characters -> Voices ->
Perform & Export) that reuses the existing Read Aloud/Library/Script
Rehearsal code via DOM reparenting instead of duplicating it, and rolls up
a long tail of bugs found while producing a real audiobook through it:
umlaut-eating name sanitizers, a voice picker that mispositioned itself and
capped results at 60, PDF pagination silently breaking on trimmed \f
markers, a race letting stale audio keep playing after a new line was
clicked, an alias-overlap bug that could silently redirect a voice/image
save onto the wrong character, voice design failing outright during brief
TTS backend restarts instead of retrying, sparse cast entries defaulting to
English/wrong gender, and a reassigned voice never reaching an already-open
Stage session or invalidating its cached audio. Also adds a persistent
per-line audio cache, audiobook export browsing/download, and an inline
voice-design prompt editor. Full details in CHANGELOG.md.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same pattern as the Casting audiobook Prompt button: a collapsible
textarea with the full extraction prompt (fields + sources/citation
schema), named-preset save/load/delete, and live persistence so edits
apply from the next passage onward. Server-side, _charsheets_prepare()
now accepts a character_sheets_prompt override (shared by the blocking
and streaming endpoints), following the same pattern already used for
the audiobook attribution prompt override.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Was a small 420px dialog with a collapsible one-line JSON preview and a
cramped 2-column chip grid. Now a big panel matching the audiobook
casting live view's shape: passage text (left) and live JSON output
(right) side by side, with a character sidebar on the right edge whose
just-updated entries are highlighted — so the user can watch each sheet
actually being built from its source passage instead of a tiny opaque
progress bar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Character Sheets generation only ever showed a progress bar - no
visible reading/thinking/filling-out, unlike the casting flow which
already streams the LLM's output live. Refactored
/api/character-sheets into shared _charsheets_prepare/_charsheets_parse
helpers (same split used for attribution) and added
/api/character-sheets/stream, proxying the LLM's SSE stream through
the same shared lock used by the other attribution endpoints.
Client: new csGenerateStream (mirrors audiobookAttributeStream) tries
the streaming endpoint first per passage, updating a new "Live output"
panel in the progress dialog with the raw JSON answer as it's written
- itself the "watch it fill out the sheet" experience, since there's
no separate reasoning channel worth hiding it behind here. Falls back
to the blocking endpoint on any stream failure.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Recasting one character out of a 149-passage book was reading the
entire text every time, exactly as flagged: "you only need to read a
couple of paragraphs before and after his name." csForReaderSelective
now matches the picked character's name + known aliases against the
book's chunks, keeps one chunk of context on either side for
pronoun/"he" resolution, and only extracts from those - falling back
to the full book only if nothing matched at all (e.g. a name typo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
csForReaderSelective passed the ENTIRE roster to csGenerate as the
target list, so the "N cast characters queued" progress dialog showed
every character regardless of what was actually checked in the picker
- only the final save step was correctly filtered, making the whole
run look like it ignored the selection. Now only the picked name(s)
go in as the target roster.
Also fixed the "Recast options" dropdown opening off-screen: its
anchor sits in the bottom action bar, so opening downward (the
default) routinely pushed it past the viewport edge. Opens upward
when there isn't enough room below, with more prominent styling.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
"Cast Characters" always blindly regenerated the whole cast from
scratch, even for a book already fully cast - no way to just look at
what's there or touch up a handful of characters without redoing
everyone. Once clGetAllByTagOrBook finds existing characters for this
book, the button becomes a split control: View Characters (jump to the
Library overview) plus a dropdown for Recast all or Recast selected...
(checkbox picker that re-scans the book but only saves updates for the
characters checked).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Table view: one row per character (avatar, name, sex, line count, voice
language, alignment, voice, tags, prompt-availability checks), toggled
next to the card grid and persisted.
Bulk voice auto-assign: checkbox per character + "Auto-assign selected"
per production, sequential so later picks see what earlier ones just
took (avoids duplicate voice assignments).
Character tags (auto-set to the book of origin) are now visible on
cards - the field always existed, cards just never rendered it, so a
character recurring across books had no visible link between records.
Detail fields (Backstory, Motivation, etc.) now show small numbered
links to their exact source citation when the sheet has one, instead
of making the reader search the full "Quellen im Text" list.
Added gender as an actual extracted character-sheet field - the UI
already had a gender icon but the LLM was never asked for the value.
Fixed SillyTavern/Concept Art prompts still coming back empty despite
the earlier token-budget increase: they're the last two fields in one
JSON object, so truncation always cost the same two regardless of the
ceiling. Split into two independent, concurrent LLM calls instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The per-word <span> wrapping behind "click any word to assign" created
~100k DOM nodes at book scale and froze the tab on every feed redraw;
replaced with native caretRangeFromPoint word detection plus a single
reused hover overlay — same UX, zero extra DOM. Export button gained a
2s re-entry guard (queued clicks during a freeze fired as a download
burst) and now delivers one zip: the cast script in Markdown plus a
sheet per character. Character detail view gains a Generation Prompts
section — four fold-out copy boxes (Voice Design, Character Image,
SillyTavern card, Concept Art sheet) filled by one LLM call over the
full profile via the new /api/character-generate-prompts endpoint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add a 6-stage pipeline stepper (Source -> Cast Audiobook -> Cast Characters
-> Script Rehearser -> Generate MP3s -> Audiobook) with direct, non-destructive
jumps between stages and a prominent guided-tour look
- Split PDF import into an explicit "load" then "Extract Text" step, with
in-browser OCR (Tesseract.js, vendored) to recover chapter headlines baked
into a PDF as images instead of real text
- Fix casting feed silently merging pages after leaving/returning: segments
now carry their own page number instead of re-guessing it from text
- Fix excessive "Unknown" speaker attribution: restore the attribution LLM's
output token budget, which had been cut roughly in half and was truncating
dialogue-dense passages
- Fix Theater Play library cards failing to open (dead pre-migration
IndexedDB API calls, missing section navigation)
- Fix bulk "Set tag" wiping a voice's existing tags instead of adding to them
- Start merging Casting's feed with Script Rehearser's Stage UI: collapsible
character sidebar, shared "paper" page styling, inline text editing
- Fix a performance regression from that merge (per-row listeners on every
redraw) by moving to event delegation
- Various layout/clutter fixes: hide reader chrome until a document is
loaded, collapse secondary settings by default, fix overlapping toolbar
icons, fix duplicate "opening" notifications
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Character sheets: stop sending the dead localhost:11434 default; fall back to
the server's configured llm_url so extraction uses the same working LLM.
- Audiobook casting: hoist highlightText to module scope so the "Review & cast"
manual-correction preview renders its segment rows again.
- Stage: unify narrator/dialog font size, add A-/A+ play text-size control
(scales A4 + paginated views), and make the cast chip list collapsible.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a persistent, book-scoped Character Library (new Characters section,
IndexedDB) that auto-fills from Character-sheet analysis with editable cards.
Enrich extraction with six narrative fields (backstory, relationships,
motivation, fears, mannerisms, voice/speech) plus the greyscale Good↔Evil
alignment bar, arc arrow, and 5-area Deep Analysis. Add ⋯ separators between
non-contiguous passages in Recast unknown, and harden dialogue attribution
against hallucination with same-language emotion tags.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read Aloud (new "Vorlesen" tab):
- PDF (real page render + overlay highlight) / TXT reader with live word
highlighting, voice + speed, per-sentence synthesis-state colours, zoom
(fit-width/height, two-page, ±), resume, and a server-side book library
(syncs across devices; per-unit MP3 audio fetched on demand).
Book -> multi-speaker audiobook:
- "Cast as audiobook" attributes dialogue to characters via the LLM
(guillemet/quote-style aware, turn-taking, recent-context), with a
deterministic speech-tag fallback. Editable preview, non-blocking live
casting panel, then auto-saved as a reopenable Script Rehearser play.
- Audiobook export: synthesise every cast line -> one MP3 per chapter.
Character sheets:
- LLM-extracted, self-filling RPG-style sheets (with page+quote sources)
in both Read Aloud and the Rehearser.
Also: MP3 storage + per-page/sentence export, voice-library "Precompute
embeddings" pre-warm, German "Vorlesen" i18n + flag language toggle,
large-PDF performance (lazy raster, buffer/canvas eviction, yielded parse),
and the Seed Finder changelog entry.
New: routes/reader.py, POST /api/attribute-dialogue, POST /api/character-sheets,
static/js/{reader,audiobook,character-sheets}.js, static/sections/s-reader.html.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>