Commit Graph

32 Commits

Author SHA1 Message Date
ebd18bcc14 Fix merge-freeze with chunked redraw, add sidebar search/sort (v1.13.5)
Merging two characters could block the main thread long enough to
trigger the browser's own "Page Unresponsive" dialog - the merge
itself is a fast array loop, but redrawing the whole feed afterward
(thousands of DOM rows, each running highlightText's regex pass) was
one long synchronous chunk. A plain spinner overlay can't fix that,
since it freezes right along with everything else in the same JS
turn. Split _abMergeCharacters into a fast relabel step plus a new
_abRedrawSegmentsChunked that rebuilds the feed across animation
frames, driving a real progress bar in the busy overlay instead of a
static "please wait".

Also added search + sort (line count / alphabetical) to the Casting
sidebar's character list, matching the Library's character list
controls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 12:12:36 +02:00
139cb6b85b Fix table-view column misalignment for real, add character-merge via alias popup (v1.13.4)
The earlier table-view fix (display:table-row on <tr>) wasn't the
whole story: display:flex directly on a <td> (Stimme, Tags columns)
also broke its table-cell participation in Chromium, rendering that
cell stacked at the PREVIOUS column's x-position regardless of
table-layout mode - confirmed via direct DOM/rect inspection, not
guesswork. Moved flex layout to inner wrapper divs and switched to
table-layout:fixed with an explicit colgroup so column widths are
never re-negotiated by content again.

Also added actual character merging to the "also known as" alias
popup: picking an existing roster entry (e.g. "Schmied" from Darag's
popup, when the LLM split one person into two roster names) reassigns
every one of its segments to the character you opened the popup from,
with undo support - not just a linked library alias that left the
live cast still showing both as separate people.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:58:42 +02:00
cb76a2f237 Fix short quoted-line drag opening Assign popup instead of Split (v1.13.3)
Any selection under 40 chars was treated as "assign this as a
character name," including short quoted lines like "»Henker«." that
the user clearly meant to split into their own Unknown-speaker
segment - guillemets/quotes are never part of a name. Selections
starting with a quote mark now skip the assign-popup hijack and fall
through to the already-visible "Split text to Unknown Speaker" button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:32:06 +02:00
204bc3a6c6 Add View Characters + recast-all/selected once a book is already cast (v1.13.1)
"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>
2026-07-06 01:03:30 +02:00
3fd4f7d052 Fix UTF-8 mojibake, thinking-pane duplication, stale popup closures (v1.12.97)
The streaming attribution endpoint decoded the LLM's SSE response with
requests' guessed encoding (Latin-1 fallback when no charset is declared),
mangling every German umlaut. Forced UTF-8 explicitly.

The "LLM Thinking" pane duplicated the passage text for models that
ignore the <think> instruction and stream straight into JSON - it now
only shows real reasoning when present, and otherwise labels raw output
honestly instead of passing it off as thinking.

Also fixed three UI bugs found while testing a live multi-hour cast:
- A-/A+ font buttons had no effect (a hardcoded font-size on .ab-cv-row
  always overrode the CSS variable they set).
- Typing a name + Enter in the "Assign to" popup (and drag-to-assign,
  which reuses it) silently did nothing after the first cast/recast run
  in a session - the popup is a page-lifetime singleton but its input
  handlers closed over the first run's now-stale assignName/closePopup.
  Every popup open now repoints them at the current run.
- "Split text to Unknown Speaker" split at the wrong spot when the
  selected phrase repeated earlier in the same paragraph (indexOf found
  the first occurrence, not the dragged one). Now uses the exact DOM
  range offset instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:18:41 +02:00
6bc98e2b62 Fix ASGI middleware crash and stream/blocking lock race (v1.12.96)
The static-asset caching middleware used BaseHTTPMiddleware, which has a
known Starlette bug: a client disconnecting mid-StreamingResponse (the new
live-attribution SSE stream hitting its idle timeout) raced its internal
task group and raised "RuntimeError: No response returned", crashing that
request. Rewritten as plain ASGI middleware that only touches headers via
the raw send callable, removing the race.

Also found the real cause of the casting timeouts/405s: the streaming
attribution endpoint had its own lock instead of sharing the one the
blocking endpoint already used to serialize on the LLM's single slot -
letting a stream call and its own blocking fallback fire concurrently,
exactly the ghost-request pile-up that lock was built to prevent. Unified
onto one lock and added server-side logging for stream failures.

The "LLM Thinking" pane now shows the model's actual <think> reasoning
instead of the in-progress JSON answer echoed back at the user.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 18:08:54 +02:00
3503f5bda6 Live LLM-thinking stream, fix resolver garbage names, safer rules (v1.12.95)
The LLM Reading card splits into thinking-stream (left) and passage
(right), fed by a new SSE endpoint that shares prompt-building and
parsing with the blocking one and falls back to it on any stream
failure (inactivity timeout, not overall). The deterministic resolver
no longer invents speakers from scenery nouns (PLATZ/GESICHTER/
KLEINIGKEIT) — person-noun whitelist plus a clause-subject pattern —
and gains the impersonal post-quote formula and strict two-person
alternation with colon/page/window guards. All reported failure cases
verified against the exact book sentences.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 10:50:34 +02:00
d1969b7609 Fix quality-run roster display, blank API errors, resolver-first (v1.12.94)
The recast/quality view's sidebar rebuilt its roster from only the
lines being checked, appearing to wipe every named character (the cast
itself was safe: named lines are never recast targets and increases in
Unknowns already roll back). The sidebar now seeds from the full cast
and refreshes during the run. Error notes fall back to the HTTP status
(statusText is empty on HTTP/2). The deterministic grammar resolver
runs before any LLM call in quality runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 23:17:59 +02:00
42a45c43b6 Resolve Unknown speakers deterministically after each passage (v1.12.93)
The LLM left ~44% of dialogue Unknown even with all deduction rules in
its prompt, so the mechanical ones now run in code per passage: colon
rule (with a non-agent-noun stoplist), post-quote inquit, and the "who
had spoken" pattern. Fills only Unknowns, never overrides the LLM.
Tested against the exact reported failure cases.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 22:40:14 +02:00
3c3c209d3a Guarantee attribution rules server-side, fix highlight corruption (v1.12.92)
The saved casting prompt was the 2nd-quality verification prompt, so
first-pass attribution ran with the wrong job description and none of
the deduction rules — and the client-side prompt migration had no
anchor to upgrade. The server now appends the rules to any prompt
lacking them, and the saved prompt was reset to the default (backed up
to config/audiobook_prompt.backup.txt). Also: single-pass combined name
regex (a shorter alias could match inside a longer name's data-name
attribute and leak raw style="..." into the feed), stopword filter so a
comma-split alias like "Die, die den Vampir verließ" can't underline
every article, heading-like narration renders bold/centered, and A-/A+
font controls in the casting toolbar sharing the Rehearser Stage scale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 18:19:01 +02:00
e02ca4d703 Fix casting-feed freeze, zip cast export, character generation prompts (v1.12.90)
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>
2026-07-04 12:48:00 +02:00
637aeb3a2c Sharpen speaker attribution rules and auto-detect book language (v1.12.86)
The casting prompt now teaches the deduction patterns behind most false
Unknown/Narrator assignments: colon-introduced quotes, post-quote inquit
attribution, pronoun resolution to the last-named matching-gender
character, addressee rule, strict two-person ping-pong, and role names
(Ork, Nachbar) as valid speakers. Saved prompts upgrade in place; the
2nd Quality Run prompt gets the same toolkit. The attribution language
hint falls back to detecting the book's language from its text instead
of relying on a usually-empty dropdown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 02:36:28 +02:00
cfe15a72f5 Optimize and clean up the pipeline merge (v1.12.85)
Speed: OCR renders only the heading band (was full page at 2.5x),
Tesseract worker freed after extraction, name-underline index cached
instead of rebuilt per segment, constant regexes hoisted, old drafts
migrate segment page numbers once at load (single-path feed renderer).

Quality: global [hidden]{display:none!important} ends the empty-box bug
class; racy deferred cast-restore + _readerSuppressCastRestore flag
replaced by a synchronous, caller-wins restore; card collapse defaults
move to data-collapse-default markup; duplicated join/colour/alias/LLM-
target helpers now delegate to their canonical implementations; dead
reader state removed; stepper hide-guard fixed for the merged Source key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 21:52:33 +02:00
9d80ec27e7 Merge Reader/Casting/Rehearser pipeline into one guided workflow (v1.12.84)
- 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>
2026-07-03 17:45:38 +02:00
34e4bb99e1 Keep audiobook casting moving on slow LLMs 2026-06-30 22:06:39 +02:00
32a3c838fe Fix audiobook stop casting state 2026-06-30 21:04:53 +02:00
586dc3dc3f release: v1.12.52 2026-06-30 13:53:08 +02:00
04dee87710 feat: auto-save audiobook to Rehearser IndexedDB + Edit in Rehearser (v1.12.6)
- Casting completion auto-saves to Rehearser IndexedDB (same format
  as script rehearsals). Manual speaker corrections in the cast view
  debounce-save after 1.5s.
- rehId tracked across session (stored in localStorage draft) so
  updates go to the same record instead of creating duplicates.
- Voice assignments made in Script Rehearser survive an auto-update:
  only script text and emotions are overwritten; voice/instruct/soul
  are merged from the existing record.
- "Edit in Rehearser" button in the completed cast footer opens the
  saved record directly in Script Rehearser, ready for voice casting.
- Expose rehDbGetById + rehLoadRecord globally from rehearser.js.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 20:21:21 +02:00
9c975a651c feat: autosave casting progress to localStorage (v1.12.5)
Saves accumulated segments after every chunk. On page refresh or crash,
reopening Cast as Audiobook for the same document restores the session
automatically — shows a banner with completion % and save age.

Manual speaker reassignments in the cast view are also autosaved so
review corrections survive a refresh. Draft clears when the script is
saved to Script Rehearsals or a fresh Recast All is triggered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 20:13:36 +02:00
87cac1f5f5 feat: expandable ⋯ dividers in Recast Unknown (v1.12.4)
Click any gap divider to reveal the hidden segments between two Unknown
passages inline — shows speaker + text so context is clear before
making an assignment. Displays line count ("42 lines hidden — click
to expand") so users know what they are opening.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:49:04 +02:00
7a75d1ecf4 feat: casting badge, navigate-away/back, live character count (v1.12.3)
- Pulsing blue dot on the Read Aloud nav item while casting is active
- Navigating away and returning restores the cast panel automatically
- Reassigning a segment's speaker decrements the old count so the
  Characters Found panel stays in sync; speakers at 0 disappear

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 19:45:41 +02:00
4f795e820c feat: noise gate, PDF search, sidebar active highlight, stats collapse, tooltip + dialogue fixes
- Conversation: adjustable noise gate slider (RMS threshold + 300 ms
  minimum burst duration) prevents short noise spikes from triggering
  STT; level meter shows gate position as a blue marker
- Conversation stats panel now collapsible (chevron button) to free
  chat width; floating expand button restores it; state persists
- Read Aloud: text search input in PDF toolbar (Enter = next hit,
  Shift+Enter = previous, Esc = clear)
- Sidebar: tooltip now works for all item types including sub-items
  that had no .nav-label span (text extracted by stripping icon/badge)
- Sidebar active section indicator added (.nav-tree-item.active was
  previously unstyled — active section now has bg + right accent bar)
- Casting audiobook: prompt instructs LLM to handle ?« / !« endings
  and unclosed » at passage end as dialogue; deterministic fallback
  also handles unclosed opening quote

Bumps to v1.12.2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 16:48:48 +02:00
a4128788d6 feat: slim icon-rail sidebar, collapsible panels, Read Aloud fit-height (v1.12.0)
- Sidebar collapses to a 56px icon rail; hovering flies the full menu out as
  an overlay (icons + titles/nested items). Language picker moved to Settings.
- Unify settings collapsibles to the app's standard card-collapse style:
  Conversation, Read Aloud (drag-&-drop now inside), Try It Out, Casting panel.
- Read Aloud: reordered (settings → toolbar → document → transport/synth) and
  the document fits the viewport height so controls below stay visible; remove
  the redundant My Books card (lives in Library → Books).
- Conversation: stacked full-width config, fills viewport height; fix
  intermittent webm decode in hands-free mode (recorder restarts cleanly,
  in-browser WAV encode); barge-in via Live agent.
- Fix casting feed overflow that pushed the sidebar off-screen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 15:47:52 +02:00
6b52a346d5 fix: stop casting feed from hijacking scroll and deleting visible rows
- Auto-scroll to bottom is now gated on the user being within 80px of
  the bottom. Scrolling up to review or edit a line freezes the feed
  in place — new rows are still added, but the viewport doesn't move.
- Row-trimming is likewise suppressed while the user is scrolled up,
  so old lines stay visible as long as they're being read/edited.
  Trim limit raised from 80 → 600 rows so almost nothing is evicted.
- A floating "↓ Live" pill button appears at the bottom of the feed
  whenever the user has scrolled up. Clicking it returns to the live
  bottom and re-enables auto-scroll.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:47:25 +02:00
a978e39e49 feat: expandable LLM panel + page markers in casting feed; fix page numbering
Casting view improvements:
- "LLM Reading…" row now shows a preview of the passage being processed.
  A chevron button expands it to a full scrollable view of the passage
  text (up to 260px), so you can follow what the LLM is reading live.
- Page-break dividers ("Page N") appear in the casting feed whenever the
  source PDF page changes, giving a real-time view of page boundaries.

Bug fix:
- Page numbers in the Rehearser script were 0-indexed (PDF-internal) so
  the first page break showed "Page 1" for what was PDF page 2, etc.
  Now always emits 1-indexed page numbers (\f${page+1}).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:23:19 +02:00
868ce6a7bd feat: show page numbers on page-break markers in Script Rehearser
When a PDF audiobook is cast and saved to the Rehearser, page breaks now
carry the source PDF page number. In the Stage view each divider renders
as "— Page N —" instead of the generic "— Page break —".

Implementation:
- audiobook.js: `audiobookBuildScript()` encodes the page number in the
  form-feed line (\fN instead of bare \f) at each page boundary.
- rehearser-parse.js: `parseScript()` now matches `line.startsWith('\f')`
  and extracts the trailing page number into `line.page`.
- rehearser.js: `buildScriptPage()` renders "— Page N —" when `line.page`
  is set; `toScript()` round-trips the number back (\fN) so it survives
  save/reload; `importPDFScript()` also encodes page numbers (\f<pageIdx+1>)
  when importing screenplay PDFs directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:09:32 +02:00
65e2784d2d Preserve audiobook pagination when saving to Rehearser (v1.9.2)
audiobookScopeText now records PDF page boundaries as character offsets in the
scope text; audiobookBuildScript realigns each segment against the source and
emits \f page-break markers at the nearest boundary. Saved/opened cast scripts
keep the book's pagination instead of collapsing to one flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 21:49:51 +02:00
e62abbcd1d Fix character-sheet LLM URL + audiobook preview; Stage font controls (v1.9.1)
- 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>
2026-06-26 21:44:30 +02:00
495550bf6a Release v1.9.0 — Character Library + richer character sheets
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>
2026-06-26 21:22:40 +02:00
18b4c1959c Release v1.8.1 2026-06-25 18:48:42 +02:00
3908f365e5 fix: Abort fetch when cancelling audiobook casting and close UI immediately 2026-06-22 17:36:05 +02:00
36437478a6 feat: Read Aloud reader, multi-voice audiobook casting, character sheets (v1.7.0)
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>
2026-06-21 15:08:46 +02:00