Commit Graph

75 Commits

Author SHA1 Message Date
2d5d5da777 feat(characters): short framing-first portrait prompt; the sheet follows what the finished portrait shows
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
Portrait backdrop measured 0/4 -> 4/4 plain on the failing character, no
change on the one that already passed. After the portrait passes, the vision
model describes hair, facial hair and eyes, and the turnaround and story
prompts are rebuilt with it -- a character with no hair in his sheet got a
different haircut on the sheet and failed the same-person check 3/3.
Costume cut and colours restored for armed characters. v1.41.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 20:09:45 +02:00
fb56f4a6d7 fix(characters): short framing-first turnaround prompt; drop passing moods, gestures and scars from images
Measured with the image check: full-body turnarounds 0/5 -> 10/10 (Karyla),
12/12 on Karyla, Darrag and Eolan after the face fixes. The 4-step model
loses the tail of a ~3000-char prompt. Scars are left out of image prompts:
any scar wording, even "fully healed", rendered as fresh gashes. v1.40.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 17:38:03 +02:00
981341de3f feat(characters): check every render, retry with a new seed, and take the sheet's face from the profile
The job checks the portrait crop, then the turnaround, story panel and
same-person against the sheet, re-renders on failure (up to 3 attempts) and
keeps the attempt with the fewest faults. ReActor transfers the profile's face
onto the turnaround and the largest face in the story panel. If the checker is
down, retries stop and the pair is marked unverified. The outcome is saved
with the pair and shown on the character page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 10:32:47 +02:00
ac8a6c7a24 feat(characters): automatic vision check for generated character images
The model only reports observations; expectations come from the sheet and the
comparison is in code. Fail-safe: an unreachable checker or unreadable answer
is a failure. Calibrated 14/14 on panels with known defects using the already
loaded LLM; Ling 3.0 Flash VL (free) scored 8/14 with 6 unreadable answers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 10:23:42 +02:00
16df95ec97 fix(characters): elf ears on humans, gender drift in the scene panel, bleeding scars, firearm sword grip
Each fix pins a defect seen in a real render. The species test read the raw
sheet field, so a hedged "Mensch (oder Halbelfe...)" matched the elf pattern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 09:47:28 +02:00
9edafe8f4a fix(characters): revert per-view turnaround renders to the single triptych
Drawing front/side/rear separately with the edit model reproduced the exact
failure the triptych was introduced to fix: three near-identical front views,
mixed styles between panels, cropped bodies, and the wireframe pose guide
rendered into the costume.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 09:33:23 +02:00
69b5e06f02 fix(characters): reword stored Renaissance book profiles to high-fantasy medieval in image prompts
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 22:11:02 +02:00
46967ade68 feat(engines): list LiteLLM router aliases in the model dropdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 16:23:25 +02:00
4b59d06479 fix(characters): map tricorn hats to a period helm in image prompts
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 16:13:50 +02:00
fb4cdbba0c feat(characters): turnaround drawn from the portrait, Dark Eye medieval setting, object-only prop tiles
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 06:19:56 +02:00
e19f2b524c fix(characters): period-safe, uninjured, more varied image prompts with taller adult proportions
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 05:34:31 +02:00
a9b4a493d8 fix(characters): retry empty character-sheet extraction with thinking disabled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 22:58:10 +02:00
37e2622d4e feat(audiobook): advisory verify and span-native recast for span casts
Verify / recast now run span-natively (no text re-emission): a second differently-windowed
pass marks lines agreed/disputed and records the other answer, without changing any speaker
(~9 min vs ~49 min). Measured on the real pipeline, overruling disputed lines with a reasoning
adjudication made them worse (66.5% -> 61.4%), so that step was removed; agreed lines were 83%
right vs 48.5% for disputed ones, which is the signal used for confidence and review.
Auto-repair no longer runs after a span cast; segments carry a spanId.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 20:17:38 +02:00
5877aa2edc fix(characters): persist base-appearance image pairs, deterministic prompts, form-aware review; add forms panel
- fix: base-appearance matched pair lost its concept image + metadata on reload; visual save
  wrote base concept art to the record root; one save path for base and forms now
- fix: extraction no longer lets the LLM author image_prompt (source of avatar/concept drift);
  avatar-only generation uses the deterministic prompt and flags an existing pair
- fix: prompt writes and Physical/Clothing edits go to the active form; review endpoint checks
  each form's own pair; fingerprint parity with the browser incl. visual_* overrides
- feat: appearance forms panel (add/rename/delete/show, per-form stale flag, generate one/all)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 15:27:21 +02:00
e7cb92c572 feat(audiobook): span-mode casting - deterministic quote spans, LLM only names speakers
Split the book into narration/dialogue spans from its own quotation marks and ask
the LLM only who speaks each dialogue span (POST /api/attribute-spans), so text can
no longer be fused, dropped or duplicated and a novel takes ~10 min instead of ~4 h.
Book 1 vs the hand-corrected reference: every-word-right 87.0% -> 92.3%, type
agreement 93.6% -> 97.4%; Books 2/3 (not tuned on) 90.8% / 89.9%.

- static/js/audiobook-spans.js (pure, unit-tested) + audiobook-cast-spans.js
- core/attribution_spans.py, route, tests; scripts/score_attribution.py
- default on; localStorage ab-span-mode=0 restores the classic engine
- architecture/audiobook-attribution.md, Manual, CHANGELOG 1.32.0, TODO

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 08:30:26 +02:00
ff827a74bd fix: recover character sheet requests from gateway 405
Some checks are pending
Test and SonarQube / quality (push) Waiting to run
2026-09-09 06:49:52 +02:00
b6f4a9518b test: lock visual identity prompts 2026-09-04 15:30:39 +02:00
c4a5689a1d fix: prevent narrator phantom speakers in book2 2026-09-04 10:04:20 +02:00
aa8a96c48f feat: add safe retries for background jobs 2026-09-04 09:58:45 +02:00
6ca044ef64 feat: validate canonical image asset digests 2026-09-04 09:53:50 +02:00
9b15dae205 fix: preserve live image job results 2026-09-04 09:52:40 +02:00
690673625d feat: persist background job result artifacts 2026-09-04 09:48:37 +02:00
5219bc4588 feat: unify transient provider retries 2026-09-04 09:36:48 +02:00
e234a6e9a3 feat: persist background job metadata 2026-09-04 09:23:17 +02:00
4300d22cd9 feat: add background casting jobs 2026-09-04 09:17:56 +02:00
3456b5a3b0 feat: support character appearance forms 2026-09-04 08:51:33 +02:00
4ffe6e9012 feat: add consistent image job cancellation 2026-09-04 08:34:35 +02:00
3c6245a5f8 fix: repair split guillemet dialogue 2026-09-04 08:26:27 +02:00
fc0361bc71 feat: deduplicate casting requests 2026-09-04 08:10:55 +02:00
d21a6f28e8 feat: record protected generation history 2026-09-04 08:07:42 +02:00
8235b36afd security: validate upload filenames and archive paths 2026-09-04 08:04:26 +02:00
9517cca00c feat: detect stale character image identity 2026-09-04 07:59:17 +02:00
94f09c110d feat: version character visual identity 2026-09-04 07:58:16 +02:00
885fa9b065 perf: bound concurrent image generation 2026-09-04 07:52:17 +02:00
ebf7b8baa1 feat: deduplicate image generation jobs 2026-09-04 07:51:31 +02:00
a8f8779736 Release v1.22.3 2026-09-04 07:28:26 +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
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
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
a62dd0bac1 Fix voice stability, audio effects, and character/voice pipeline bugs
Voice consistency:
- Read back each voice's pinned seed (Seed Finder / Batch Seeds) on every
  generation. The seed was saved to voice metadata but only ever read by the
  Seed Finder's own benchmark path, so all per-voice seed pinning was inert.
- Stop coercing the "voice_design_playback" stability profile back to
  "voice_clone". The pseudo-backend key isn't a real routing target, so the
  backend-name normalizer silently rewrote it — reintroducing the hardcoded
  seed:0 that profile exists to avoid, overriding every per-voice pin.
- Apply the accent clause on every line, not just at voice-creation time,
  and reorder the instruct so emotion leads and accent trails (Qwen3-TTS
  doesn't reliably follow multiple conflicting instructions).
- Pass an explicit language to Voice Design instead of leaving it on "Auto".

Audio effects:
- Add a limiter after compressor makeup gain. Makeup gain pushed peaks to
  ~1.9, and the final hard clip turned that into broadband distortion that
  swamped the rest of the chain.
- Cascade highpass/lowpass 3 stages each (~18 dB/octave). Single-pole
  filters were too gentle to band-limit speech audibly.
- Add a Bandpass control and wire it into the Telephone/Radio presets —
  compression alone never sounded like a phone; band-limiting is the
  defining trait.

Persona / Try It Out:
- Disable "Apply character persona" with an explanatory tooltip when the
  voice has no persona saved, and error clearly server-side instead of
  silently no-op'ing. Persona is typed manually per voice, never auto-filled.
- Stop dropping applyPersona in the chunked generation path (>200 chars).
- Populate the Voice Design dropdown from the user's own library rather than
  filtering the engine's discovery list, which never contains custom voices.

Navigation and library:
- Use pushState instead of replaceState so browser Back/Forward step through
  in-app navigation instead of leaving the app entirely.
- Show real dialogue line counts in the character sidebar instead of the
  capped reference-quote count (which showed a misleading uniform "12").

Also fixes a crash in /api/transcribe-bytes that referenced an undefined
source_id in its cleanup path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 15:33:24 +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
588ba3fcb8 Refine character sheets and live output UI 2026-07-09 19:47:16 +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
b96968ac5d Add mid-quote-dash and voice-announcement rules to casting attribution prompt (v1.14.15)
Two gaps observed in real casting output:
1. A mid-quote " - " (em-dash pause) was being read as the end of the
   quotation, handing the rest of the line to a wrong/new speaker.
2. Narration naming whose voice is about to speak (e.g. "Marcians
   Stimme wirkte nicht mehr so fest") wasn't being used to resolve the
   following unattributed line away from 'Unknown'.

Added as rules 11/12 to the client-side AB_DEFAULT_PROMPT (the prompt
actually sent to the LLM) and to normalizeCastingPrompt()'s migration
so already-saved custom prompts pick them up automatically, same
mechanism as the earlier Doppelpunkt-Regel upgrade. Also added
equivalent rules to the server-side fallback prompt in
routes/conversation.py for completeness, though the client-sent prompt
is what's actually used in normal operation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 02:51:46 +02:00
328e612eb7 Fix empty thinking panels for vLLM builds using a bare "reasoning" key (v1.14.9)
Confirmed by directly probing a streaming response from vllm-0.23.1rc1:
its delta objects carry reasoning text under "reasoning", not the more
common "reasoning_content" key every reasoning-display code path was
checking for. Added a shared _reasoning_text() helper that checks both,
used by the Conversation Playground, audiobook casting's live view, and
character sheets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 01:42:24 +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
ce3ae79132 Fix streams permanently stuck holding the shared LLM lock (v1.14.2)
Confirmed in production: a streaming attribution/character-sheets
request held _attribution_llm_lock for 11+ minutes, well past its
configured timeout, silently rejecting every subsequent passage as
"Attribution engine busy" and falling back to the non-streaming view -
looking exactly like live-thinking had stopped working, when actually
one earlier request never finished.

Root cause: requests' timeout= on a stream=True call only covers the
connect + first byte, not gaps between later body reads. If the LLM
backend goes silent mid-stream (connection left open, no more chunks),
the blocked socket recv() inside iter_lines() can hang indefinitely.
Since that's a native blocking call, not a Python-level yield point,
neither an in-loop wall-clock check nor GeneratorExit from a
disconnected client can interrupt it - both only take effect at the
next bytecode boundary, which never arrives while blocked in the C
extension.

Added _watchdog_close: a daemon thread that force-closes the upstream
connection if the wrapped block hasn't finished within the configured
timeout. Closing the socket from another thread makes the blocked
recv() raise, unblocking the generator so its normal except/finally
cleanup (including releasing the lock) actually runs. Verified against
the live LLM backend post-restart: stream completes normally with
real token-by-token deltas, and the lock is confirmed free immediately
after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:57:49 +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