Commit Graph

180 Commits

Author SHA1 Message Date
31b13a4e16 feat: improve magazine review navigation
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 17:36:27 +02:00
c1d86ec13d fix: return All magazines to library
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 17:14:27 +02:00
272d4872bd fix: use native Unlimited-OCR layout regions
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 13:27:14 +02:00
b7aade39db Release v1.26.1
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-08 23:39:44 +02:00
85080f4b82 feat: add live ingest preview, region icons/ownership badges, manual region drawing to magazine review
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Ingestion now streams each page's image and recognised text into a
console-styled preview panel (Baidu Unlimited-OCR demo style) as pages
finish, instead of a bare progress bar -- raw text is written to a
per-job ingest_preview.json file since the background-job result field
strips text-like keys for data minimization.

Split-screen review boxes and their matching list rows now show a
centred icon for the region's kind and, when a region on a shared page
belongs to a different article, a badge naming that article, so a
claimed region is never mistaken for unclaimed text.

Added a "Draw it" mode: click-drag a box directly on the page image to
add a region the layout engine missed, as typed/OCRed text or as a new
figure (add_manual_region, POST /api/magazine/{doc_id}/pages/{page}/regions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 18:52:21 +02:00
5adba6b4c0 feat: split-screen article review with numbered regions, per-page/whole-magazine "OCR again", and a real column-interleaving fix it found
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Split-screen review: the rendered page (left) with a numbered box per
detected block, the extracted text (right) with matching numbers.
Clicking either side highlights the other. Checkboxes moved from a flat
list into this layout without changing their semantics (still gate
what gets narrated).

"OCR again": reocr_page() forces one page through the configured
vision engine again, replacing only that page's blocks -- deliberately
does NOT call build_articles(), so an already-approved article is not
silently re-grouped. A magazine-level option re-reads every page and
re-runs detection (with a confirmation, since that does reset article
status). extract_pages() gained force_vision_ocr to skip its quality
gate for this case.

Building the numbered-box review immediately did what it was built to
do -- surfaced a real bug on live production data (real magazine, real
scan, not a synthetic fixture): a photo caption at 49.9% of the page
width sat in the gutter between two genuinely separate columns and
merged them into one, so every block on the page came back column=0
and reading order fell back to pure top-to-bottom, interleaving the
two columns' sentences. Fixed two compounding causes: column boundary
detection now excludes blocks much wider than the page's median width,
and detect_columns' gutter threshold (3.5%) was itself narrower than
some real magazine gutters (~2.1% measured) -- lowered to 1.5%.

10 new/updated tests, including one built directly from the real
measured page-17 block coordinates that exposed the bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 14:00:34 +02:00
5b0c8e0bf5 feat: add drag-and-drop dropzone to the magazine upload form
Replaces the plain <input type="file"> with the same reader-dropzone
component the Book/Source screen already uses (reused CSS, no new
styles needed beyond grid/layout adjustments) -- drag a PDF onto the
zone or click "Choose file", both paths route through the same hidden
input magCreate() already reads via a DataTransfer handoff, so no other
logic needed to change. Shows the chosen/dropped filename in place of
the default hint text, and resets it after a successful add.

Verified live: click-to-choose and a simulated real 'drop' DragEvent
both populate the file input correctly, dragover highlighting toggles,
no console errors from the app itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 00:03:01 +02:00
813e06c914 feat: complete magazine P1 (images, play-all, karaoke, driving mode, sidebar exclusion) + OCR engines page + second OCR engine
Magazine P1:
- Images shown automatically during playback (assign_images_to_articles
  links each figure to the article whose column it falls in; the client
  shows the last image reached in reading order as playback advances).
- "Play all articles" queues every approved article and advances
  automatically at the end of each rather than stopping.
- Word-level highlighting, explicitly documented as an ESTIMATE (no
  forced-alignment/timestamp source exists): each word's share of the
  sentence's real measured audio duration is proportional to its
  character length. A checkbox turns it off; sentence highlighting
  (measured, not estimated) is unaffected.
- Driving mode: full-screen overlay, two oversized controls, reuses
  whatever is already playing/queued.
- Sidebars/pull-out boxes excluded from narration automatically
  (mark_sidebars: an anomalously narrow column vs. the page's regular
  grid). Fixed a real defect found while building this: a full-width
  headline was left in the column-width analysis and could bridge two
  genuinely separate columns into one, hiding a real sidebar column
  entirely -- caught by a failing test before the fix.

Second OCR engine + fallback ladder:
- KDL Frontier Parser nano wired in via vision_ocr_page_chain (ordered
  engine list, first usable result wins, tesseract last resort).
  Confirmed live: ~3x faster than Baidu (~12s vs ~40s/page) but returns
  plain text with NO coordinate markers, unlike Baidu's labeled regions.
  _whole_page_region treats the whole response as one ambiguous
  full-page block (gated by ocr_quality_score) rather than discarding
  usable text just because it lacks layout structure.

OCR engines page + a real UI bug:
- The OCR & Document Parsing page had no .s-engines-page[data-page="ocr"]
  markup at all -- renderLocalContainers already supported an OCR grid
  generically, but $('dc-grid-ocr') was always null, so the card grid
  silently never rendered. Added an Active OCR Engine panel mirroring
  Active Language Model exactly, plus the Local grid -- both configured
  engines now appear as ready-made cards, no "Add Custom" dialog needed.
- Fixed the audiobook pipeline's "Previous/Next" nav bar bleeding into
  every .section-head in the document (confirmed live on the Engines
  page: a "Cast Audiobook" button and "STEP 1/8" hint that made no sense
  there). Changed from a blocklist (naming each unrelated section as
  noticed) to an allowlist of the pipeline's three actual destinations.

Verified live end-to-end: play-all queue building and manual advance,
word-span markup, driving-mode toggle, OCR page showing both engines as
local cards, zero stray nav bars on the Engines page, no console errors.

20 new backend tests (156 total in the magazine module).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 23:39:34 +02:00
71a398b82f feat: add magazine reader frontend (P1)
Studio -> Magazines: library, contents tree grouped by section with
confidence/pages/listening-time/audio status, the Stage D review
screen (tick/untick layout blocks, correct title/author, approve or
reject), a reflowed article view with click-to-seek sentence
highlighting, a linked original-page view showing the source bounding
box, and a podcast panel (2-3 host pickers, script generation,
turn-by-turn playback).

Wired into the existing lazy-module system (module-manifest.json,
loader.js, nav.js) rather than a separate app. Reuses /api/tts-preview
for both narration and podcast turns -- no new audio pipeline.

Fixes found building this:
- The pane toggle used role="tab" without the full ARIA tabs pattern
  (aria-selected, roving tabindex, arrow-key nav) -- fails WCAG 2.2 AA
  and hid the buttons from role-based tooling. Replaced with a button
  group + aria-pressed, matching the plain-click interaction it
  actually has.
- Print layout cues ("(continued on page 8)") were being sent to TTS
  verbatim -- narration would have spoken the parenthetical aloud.
  Stripped from the narration copy only; layout.json keeps the
  original for the review screen.
- has_podcast now comes from the articles listing so opening an
  article without a generated script skips a doomed GET instead of a
  routine 404 on every open.

Verified against the real API contract with Playwright (library,
review pre-selection, approval, sentence highlighting + PDF-page
linking, podcast approval gate, zero console errors across the flow)
and manually end-to-end against a real ingested fixture, screenshots
included. Full suite: 94 Python tests, 33/34 desktop Playwright tests
(one unrelated pre-existing flaky DOM-count assertion).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-06 15:00:58 +02:00
4c8022e8aa refactor: extract audiobook stylesheet 2026-09-04 11:44:55 +02:00
065445a20a refactor: extract rehearser stylesheet 2026-09-04 11:42:43 +02:00
d43959728d refactor: split voice design styles 2026-09-04 11:16:05 +02:00
de099d30c5 refactor: split background job styles 2026-09-04 11:13:36 +02:00
8d9a172993 refactor: split resource diagnostics styles 2026-09-04 11:10:43 +02:00
c815b7941a feat: expand resource diagnostics 2026-09-04 10:42:08 +02:00
90e74149d9 feat: add constrained-device resource diagnostics 2026-09-04 09:51:49 +02:00
690673625d feat: persist background job result artifacts 2026-09-04 09:48:37 +02:00
b648bbdf0b feat: add safe background job history panel 2026-09-04 09:44:31 +02:00
a7a6bb1cdc feat: add visual pair review workflow 2026-09-04 09:20:27 +02:00
3456b5a3b0 feat: support character appearance forms 2026-09-04 08:51:33 +02:00
fe807d1682 Release v1.22.2 2026-09-03 16:12:02 +02:00
f7264a8c07 chore: release 1.21.0 - Consistent ComfyUI Character Renders and Audiobook Export
- Deterministic hash-based character portraits and reference sheets
- Implemented strict early Renaissance aesthetic controls and role-specific headwear rules
- Added audiobook batch export scripts and progress tooling
- Verified book profiles with a new 'confirmed' state tracking mechanism
- Updated Pillow dependency for robust image handling
- Configured .gitignore for audiobook and audio cache exports
2026-08-23 09:12:57 +02:00
fd8f545d16 Optimize offscreen character table rendering 2026-08-19 18:35:10 +02:00
aa15265021 Show generated voice file and preview in character profiles 2026-08-19 17:12:02 +02:00
388fd601ab Release v1.20.38 2026-08-19 16:36:26 +02:00
189ca51e47 Release v1.20.37 2026-08-19 16:04:30 +02:00
62274a17fc Improve Studio casting and character voice design (v1.20.36) 2026-08-15 13:20:38 +02:00
f837ba1a4f Toggle quotation marks with CSS instead of rewriting text (v1.20.31)
CSS cannot target a character inside a text node, so the marks are now wrapped
in their own .ab-q element at render time and hidden with a single class on
body. Toggling is instant regardless of segment count, and the stored text is
never modified.

Also fixes the toggle looking inert on a freshly cast book: it previously only
added missing marks and never hid the ones the book already carried. Button
moved bottom-right as a larger labelled pill, clear of the search controls.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 13:14:35 +02:00
55f634e626 Show quotation marks in the casting script, with a toggle (v1.20.29)
German prose never quotes narration, so displaying the guillemets makes a
mislabeled line obvious at a glance. Extraction strips them from ~80% of
segments, so they are rendered rather than stored: dialogue rows display
wrapped in » «, lines that kept their own marks are left as-is, and the saved
text is untouched so synthesis and exports are unaffected. A toolbar button
toggles visibility and the choice persists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 10:51:46 +02:00
30bac15b6e Open toolbar flyout menus downwards when there is room (v1.20.18)
The Identify/Cast flyouts were hard-anchored to open above their trigger,
which suited the casting panel's bottom footer but clipped them off the top of
the screen in Studio, where the same toolbar sits near the top — the first two
entries were unreachable. They now pick the side with space, prefer opening
downwards, stay clamped inside the viewport and scroll if taller than it.

Also reorders the Identify menu to the sequence the passes should run in, with
the one-click Auto-repair cast first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 08:47:17 +02:00
193cbb202d Fix Fish-Speech 0-voices bug, add inline emotion-tag reference to Try It Out (v1.20.8)
Fish-Speech clones from the app's own saved WAV library but was missing from
the set of backends populated with those voices, so the UI probed the Fish
server for a voice-listing endpoint it does not have, showed "Fetched 0
voices" and left the engine unusable despite being healthy. It now reports
the full library (218 voices).

Also adds a Fish-only panel listing all 49 documented emotion tags with
click-to-insert and a multi-emotion example, and corrects the backend's
advertised capabilities: it was flagged style_aware with "emotion markers are
honoured per request", but measurement shows a reference clip's in-context
prosody overwhelms inline tags (10x loudness spread across emotions without a
reference, 1.2x with one). It is now described by what it does well:
deterministic, byte-reproducible cloning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 00:08:36 +02:00
5fecbf06d4 Fix Fish-Speech emotion tags, wire book context into portraits, add emotion controls app-wide (v1.20.5)
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>
2026-08-11 18:02:41 +02:00
ea50267c30 Add unified Studio casting workflow and fix voice/casting pipeline bugs
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>
2026-07-26 02:03:56 +02:00
f6e5449eb6 Show source evidence in character sheets 2026-07-09 20:36:17 +02:00
588ba3fcb8 Refine character sheets and live output UI 2026-07-09 19:47:16 +02:00
8f3fcbae04 Release v1.14.19 2026-07-09 14:11:40 +02:00
606ae125a3 Add editable Prompt panel for Character sheets (v1.14.17)
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>
2026-07-09 12:21:26 +02:00
b5ffa655d8 Redesign Character sheets progress modal into a big split view (v1.14.16)
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>
2026-07-09 11:53:57 +02:00
3db3616830 Show character avatar images in casting pickers (v1.14.12)
The Characters Found sidebar, the "Assign to" popup's character list,
and the "merge with an already-found character" list now show each
character's saved portrait when one exists (same source as the profile
detail panel), falling back to the existing colour-keyed initial-letter
dot otherwise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 02:09:20 +02:00
f139367f74 Make casting live-view panels resizable, fix collapse chevron direction (v1.14.10)
Passage/Thinking boxes in the audiobook casting live view can now be
resized vertically. Also fixed the character-list collapse button's
chevron pointing opposite to the direction the panel edge actually moves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 01:50:36 +02:00
c969150095 Fix triple-duplicated passage in audiobook casting's live LLM view (v1.14.7)
The "LLM Reading…" split view showed the same passage text three times
(reader pane, Passage column, and a full-width block toggled by the
chevron that duplicated the Passage column). Removed the redundant
full-width block, repurposed the chevron to show/hide the two-column
view itself, and swapped the columns to Passage (left) / Thinking (right).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 23:00:16 +02:00
ed76af4976 Add collapsible thinking panel to Conversation Playground, regroup mic controls (v1.14.6)
Reasoning-model chain-of-thought is now separated from the spoken/displayed
reply on the server (handles both a dedicated reasoning_content field and
inline <think> blocks, including chat templates that inject the opening tag
as a prompt prefix so it never appears in the stream). The client shows it
in a panel collapsed behind a "Thinking" chevron instead of dumping raw
reasoning text into the chat or speaking it aloud via TTS.

Also moved the noise-gate slider out of its own row and next to the mic
button, grouping it with Auto-stop/Hands-free/Live agent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 22:54:20 +02:00
bfd1bfb939 Add routing voice-picker, restore voice filters, fix pedalboard (v1.14.3)
- App Routing's output-voice field gets the same searchable
  avatar-thumbnail dropdown used elsewhere, as a browse button
  alongside the existing free-text input (which must stay editable to
  target vd_ Voice Design presets not in the voice library).

- My Voices table: Gender and Rating filter dropdowns existed in the
  JS (populateLibraryFilters, libraryFilterMatch) but their <select>
  elements had been dropped from the visible layout after an earlier
  redesign, replaced with hidden dead placeholders just to keep the
  code from erroring - and since populateLibraryFilters() early-returns
  if any of the three elements are missing, this silently broke the
  already-visible Language/Type dropdowns too. Restored the real
  elements and removed the hidden scaffold; added new Tag and Group
  dropdowns wired to the same filter state the sidebar chips use.

- Audio effects failing with "pedalboard is not installed" despite
  requirements.txt listing it: the package WAS installed, but its
  native extension (pedalboard_native) links against libatomic.so.1,
  an OS-level shared library missing from the python:3.11-slim-bookworm
  base image. Added libatomic1 to the Dockerfile and rebuilt - verified
  `import pedalboard` now succeeds in the running container.

- Relabeled "edit ID"/"copy ID" to "rename filename"/"copy filename"
  in the voice inspector - the feature already renamed the underlying
  .wav/.meta.json/.reference.txt/picture files via the existing
  /api/voice/rename endpoint, it just wasn't obvious "ID" meant
  "filename."

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 21:05:45 +02:00
960389ef5b Add live-streaming output to Character Sheets generation (v1.14.0)
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>
2026-07-06 15:28:26 +02:00
f2bdd98a4f Fix invisible icon on the Cast as audiobook button (v1.13.10)
A leftover rule colored the icon accent-blue from when this button
was still .btn-secondary (accent icon on a white background). After
making it the primary blue button in the last release, that same blue
rendered blue-on-blue against the button's own background - invisible.
Confirmed via computed style before/after (blue -> white) rather than
guessing from the screenshot alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 15:16:25 +02:00
07eadeff1e Fix Recast-selected running on the full roster, improve dropdown positioning (v1.13.7)
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>
2026-07-06 14:35:27 +02:00
95a4c95b90 Fix wasted empty space in Read Aloud tuning panel layout (v1.13.6)
The backend hint box sat beside the 4 tuning rows via grid-row: 1 /
span 4, forcing it to stretch to their combined height no matter how
short its own text was - usually leaving a large empty gap below a
1-3 line hint. Moved it full-width below the rows instead, sized to
its own content, and dropped the now-redundant two-column grid and
mobile-breakpoint overrides that existed only to manage it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 12:16:10 +02:00
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
628bd75a82 Fix table-view layout bug, add per-prompt Generate buttons, sort dropdown (v1.13.2)
Table view was rendering as stacked blocks instead of columns: rows
reused .lib-char-card for its event wiring, but that class's
display:flex;flex-direction:column turned every <tr> into a flex
column. Reset to display:table-row and stripped the leaked-in card
chrome.

Split /api/character-generate-prompts into four independent per-field
LLM calls (from two paired calls) and added a `fields` filter, so the
UI can offer one Generate button per prompt box instead of a single
button that always regenerated all four - cheaper, and further
shrinks each response to reduce truncation risk.

Added a Sort dropdown (Role/Alphabet/Lines/Gender/Voice assigned) to
the Characters/Cast list, persisted like the Cards/Table toggle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:20:23 +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
04531b25f8 Turn Script Rehearser's Stage character strip into a sidebar (v1.13.0)
Replaces the horizontal avatar strip above the transport bar with a
sidebar next to the script page, reusing Read Aloud's Casting sidebar
classes (.ab-cv-side/.ab-char-item) directly instead of a separate
look. Same collapse-to-avatars control, now shows each character's
line count, and clicking a character scrolls the script to their
first line. Removed the CSS/HTML this replaces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 00:58:04 +02:00
5fd1660c09 Add character table view, bulk voice-assign, source links, fix prompt truncation (v1.12.98)
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>
2026-07-05 23:09:59 +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
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
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
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
bc6c4842b5 Optimize startup and persist engine keys 2026-06-30 14:52:17 +02:00
586dc3dc3f release: v1.12.52 2026-06-30 13:53:08 +02:00
ef5321cb18 feat: lang/gender in batch benchmark list+results; sortable results table (v1.12.15)
Voice selection list now shows flag + gender symbol on each row.
Batch results table adds Lang and Gender columns. All columns are
sortable by clicking the header (↑↓ indicator); defaults to Factor
descending. Sort logic handles strings (locale) and numbers uniformly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 00:15:23 +02:00
5db93d55d1 feat: voices table shows only Factor+WPM; Benchmark gets full detail (v1.12.14)
Voices table: removed Length, Duration, Time — only Factor and WPM remain
from benchmark data. Setup → Benchmark batch results now shows Duration,
Factor (sorted fastest-first, colour-coded), Time, and WPM. Factor replaces
Avg RTF with the same data flipped to a more intuitive direction (higher=better).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 23:32:13 +02:00
90a481f8d8 feat: split Speed into Factor + Time columns, add colour coding (v1.12.13)
The old combined `21.8s · 1.30x` Speed cell is replaced by two separate
sortable columns:
- Factor (x.xx): audio÷render multiplier, green/amber/red colour-coded
- Time (Xs): total render time

Column order: Length · Duration · Factor · Time · WPM · Seed · dBFS · ...

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 23:19:33 +02:00
0606db101a feat: reorder columns, add Duration column, benchmark sentence presets (v1.12.12)
Column order now: Img·Play·Name·Lang·Gender·Length·Duration·WPM·Speed·
Seed·dBFS·Type·Source·Rating·Tags·Note·Active.
Duration shows synthesised audio length (b.audio_sec), sortable.
Preset dropdown offers 4 benchmark sentences (DE/EN narrative + DE/EN
tongue-twister) and a reset option.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 22:54:54 +02:00
c5181b499a feat: add WPM column + info tooltips to voice table (v1.12.10)
WPM (words per minute) is derived from the benchmark audio duration and
sentence word count, revealing how fast a voice speaks — independent of
GPU speed. 130–180 wpm is comfortable for audiobooks. Column is sortable.
Info (ⓘ) icons on Speed and WPM headers explain both metrics on hover.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 22:41:01 +02:00
0bc3acc2ee feat: editable Source field + fish-audio fallback + bulk set source (v1.12.7)
- Add Source input to voice inspector panel (saves to origin in meta.json)
- Auto-detect fish-audio voices via tag — SOURCE column now shows
  "fish-audio" for tagged voices even without an explicit origin field
- Bulk "Set source" action in the multi-select toolbar
- Source cell in table reflects the live-displayed value and updates
  immediately when changed via the inspector

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 20:28:35 +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
41f747a7b0 fix: icon-rail sidebar now shows per-item label tooltips instead of full flyout
Hovering the collapsed 56 px rail no longer expands the whole sidebar,
which was pushing the main content left and right. Each nav item now
shows a small floating tooltip (JS-positioned fixed div) next to its
icon on hover — layout stays completely stable.

Bumps to v1.12.1.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-27 16:00:56 +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
fb7dcb52f8 feat: stacked Conversation config + browser WAV decode; changelog (v1.10.1)
- Conversation Playground: STT/LLM/TTS/System prompt now full-width stacked.
- Fix conversation mic upload on ARM64: decode recording in-browser to
  16 kHz mono WAV, bypassing server ffmpeg webm/EBML parser (with fallback).
- Document v1.10.0 (unified Library + character tags) and v1.10.1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:35:57 +02:00
73c27944ac feat: collapsible nested sidebar groups
Group headers (Voice Actions, Speak, Setup) are now collapsible parents;
Tags nests under Library; Integrations + Settings nest under Setup.
Navigating a section auto-opens its whole ancestor tree chain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 14:30:14 +02:00
52994df70b feat: unified Library + character tags + shared cast (v1.10.0)
Restructure the sidebar into Voices / Speak / Setup groups and fuse the
Read Aloud and Script Rehearser features into one workspace:

- New combined Library section (Books · Theater Plays · Characters/Cast)
  with cross-links (Rehearse a book, Read Aloud a play).
- Character tags like voice tags: one record, many productions, reusable
  across books/scripts; seeded with origin book, editable in the editor.
- Shared cast resolution: opening a production fills empty cast slots from
  the character roster (matched by book OR tag); voice choices written back
  on save. Productions joined by normalized title (prodKey).
- Tags nav group for voices (distinct tags + counts, Cloned/Designed/Fav).
- Fold standalone Characters into Library; Read Aloud now a single entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 12:12:22 +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
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
ca599be5c3 style: reduce gap between stars in compact rating display 2026-06-23 10:40:48 +02:00
7e4c80d784 feat: simplify compact list meta row and update gender badges 2026-06-23 10:34:20 +02:00
307922b90c feat: Add row highlighting during batch voice benchmark 2026-06-23 09:13:41 +02:00
c26dabe296 feat: Implement dark theme variables and add save button to general settings 2026-06-22 21:35:16 +02:00
af49bb4d6f fix: Correct CSS grid order for inline name input 2026-06-22 15:22:04 +02:00
cada45fb15 feat: Add Inline Table Edit Mode 2026-06-22 15:15:13 +02:00
3f1e82ef81 fix: Add drag-over visual feedback CSS for inspector avatar 2026-06-22 14:49:31 +02:00
a325f53e62 feat: Implement sortable Table View and Inspector drag-and-drop support
- Added a new 'Table View' button to the library sort bar.
- Implemented a CSS grid layout to display voice properties in a high-density table.
- Added sortable column headers (Name, Lang, Gender, Speed, dBFS, Length, Rating, Source, Seed, Note, Tags, Active).
- Aligned CSS grid to account for the bulk edit checkbox injection.
- Added drag-and-drop profile image support to the Inspector's large avatar.
- Ensured picture updates instantly synchronize across the List, Table, and Inspector views.
2026-06-22 14:40:39 +02:00
88c74ab826 feat: persistent seed pinning and batch seeds 2026-06-22 10:43:56 +02:00
fff6e7e096 feat: add Seed Finder panel to voice inspector
Adds a collapsible "🎲 Seed Finder" panel to the voice inspector pane.
Select a voice, expand the panel, set a seed range (default 1–15), and
click Run to generate audio samples with different seeds.

Each result row has Play and "Use this seed" buttons. "Use this seed"
saves the chosen seed to the faster-qwen3-tts voices.json via the new
/api/tts-voice-seed proxy endpoint (which calls /voice-seed on the TTS
server). The saved row gets a ✓ marker.

Test sentence auto-selects DE/EN mixed or EN-only based on voice name.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-21 14:53:51 +02:00
c3b1cab75b Enhance benchmark history metadata 2026-06-07 15:41:04 +02:00
52d3dcd135 Make settings guidance more intuitive 2026-06-06 00:02:47 +02:00
1f4784653c Improve benchmark voice selection and device reporting 2026-06-05 20:14:02 +02:00
7b855394a5 Add searchable benchmark voice pickers 2026-06-05 15:44:13 +02:00
f469d428e2 Persist section reloads and reuse voice samples 2026-06-05 15:07:09 +02:00
2547619998 Refine benchmark tabs and model pickers 2026-06-05 14:44:30 +02:00
10a11132c0 Add benchmark mode tabs 2026-06-05 14:16:35 +02:00
9c2e507ccf Improve voice workflows and add user manual 2026-06-04 08:23:18 +02:00
40e42590cc Release v1.6.0: a11y (WCAG AA), i18n (DE), PWA, perf, tests, Cast UX
Cast: card/list views, sort & filter, online voice picker, "Hear a line"
sample button, AI character notes, import auto-save.

Platform: WCAG 2.1 AA accessibility pass; German UI translation + language
picker; installable PWA with offline shell; GZip + content-visibility
virtualization + lazy images + Rehearser PCM memory cap (mobile stability);
Playwright suite (desktop + iPhone); opt-in minified bundle build.

Fixes: screenplay parser false characters; Fish-Speech inline-tag tones;
narrator/voice pickers list full library; clone GUI rework; fish.audio
import dedup; voice-ID rename; bulk-delete modal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 14:23:35 +02:00
b64baf2d0b Script Rehearser: library with save / load / import / export
Storage: IndexedDB ('reh-library' DB, 'rehearsals' store).
Blobs (recorded mic audio) stored natively; no base64 overhead.

Library panel (Phase 1):
- List of saved rehearsals sorted by last update
- Each row: character-colour avatars, title, progress bar,
  line count, recorded-clip count, date
- Active record highlighted in accent colour
- Open / Export .reh / Delete per-row buttons
- Import .reh button at the top

Transport bar (Phase 3):
- Save button (updates existing record if savedId set, else creates new)
- Export button (downloads current state as .reh JSON file)

Phase 4 (session complete):
- Save to library and Export .reh buttons

Data format (.reh file):
- JSON with version=1, title, script text, cast map, backend, lineIndex
- clips serialized with audio as base64 strings (mime + b64 fields)
- clipsFromJson restores Blob objects on import

Behaviour:
- Parsing a brand-new script resets savedId → safe to save as new record
- loadRecord() restores script, cast, lineIndex, clips and jumps to Phase 2
- renderLibraryList() called on init, after save, after delete, after import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 20:32:24 +02:00