From f04c8d5e2bf88ce64068e2c8aa0e563d116009af Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Sun, 23 Aug 2026 09:27:34 +0200 Subject: [PATCH] chore: release 1.21.1 - Testing and scratch scripts --- 2026-07-16 inventory.md | 91 ++++++++++++++++++++++++++ CHANGELOG.md | 9 ++- VERSION | 2 +- scratch/batch_generate_all.py | 67 +++++++++++++++++++ scratch/fix_avatars.py | 56 ++++++++++++++++ scratch/get_char_details.py | 18 +++++ scratch/test_flux.py | 14 ++++ scratch/test_gemini_imagen.py | 26 ++++++++ scratch/test_google_imagen.py | 20 ++++++ scratch/test_openai.py | 24 +++++++ scratch/test_pollinations_portrait.py | 13 ++++ scratch/update_karyla.py | 15 +++++ test_flux_portrait.png | Bin 0 -> 31524 bytes test_pollinations_portrait.png | Bin 0 -> 30213 bytes 14 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 2026-07-16 inventory.md create mode 100644 scratch/batch_generate_all.py create mode 100644 scratch/fix_avatars.py create mode 100644 scratch/get_char_details.py create mode 100644 scratch/test_flux.py create mode 100644 scratch/test_gemini_imagen.py create mode 100644 scratch/test_google_imagen.py create mode 100644 scratch/test_openai.py create mode 100644 scratch/test_pollinations_portrait.py create mode 100644 scratch/update_karyla.py create mode 100644 test_flux_portrait.png create mode 100644 test_pollinations_portrait.png diff --git a/2026-07-16 inventory.md b/2026-07-16 inventory.md new file mode 100644 index 0000000..504d8f5 --- /dev/null +++ b/2026-07-16 inventory.md @@ -0,0 +1,91 @@ +Script Rehearsal — Feature Inventory +1. Library phase (phase 1) +Files: s-rehearser.html #reh-phase-1, JS renderLibraryList(), rehDbGetAll/rehDbAdd/rehDbPut, loadRecord() (exposed globally as window.rehLoadRecord), bookCover(), rehUniqueLibraryRecords(), rehTitleKey(). +Shows saved rehearsals as a "bookshelf" (#reh-library-list.reh-bookshelf, list/shelf toggle #reh-lib-view-toggle), each with a generated cover (bookCover), dedup'd by title (rehUniqueLibraryRecords). +Script entry points: paste text into #reh-script-text + #reh-script-title → #reh-parse-btn → parseScript(); file upload (#reh-file-input txt/md, #reh-pdf-input pdf via importPDFScript, #reh-fdx-input fdx/osf via importFDX); drag-and-drop onto #reh-dropzone; .reh session import (#reh-lib-import-file, rehImportAnyFile); IMSDb/Scripts.com browser modal (#reh-imsdb-modal) fetching scripts from the web; and opening a saved record from the Library section or Audiobook (loadRecord/window.rehLoadRecord, called by library.js and audiobook.js). +rehState shape (defined ~line 64): + +lines:[], cast:{}, lineIndex:0, clips:[], voices:[], backend:'', +playing:false, repeat:false, savedId:null, synthCache:Map, staleLines:Set, +synthCancelled:false, synthRunning:false, skipDescriptions:true, narratorVoice:'', +practiceStart:null, practiceEnd:null, bulkMode:false, bulkSel:Set, bulkAnchor:null, +showHidden:false, plus mic-recording fields (recStream, recAudioCtx, mediaRec, recChunks, ...) +2. Cast phase (phase 2) +Per-character cards (renderCastList() → #reh-cast-list, card/list view applyCastView): library-linked characters render via _charCardHtml() reused from the shared character library, wrapped in .reh-cast-card-libcard; unmatched speakers (including a synthetic Narrator entry, key REH_NARRATOR_KEY) get a fallback header/card. +"I play this" mic toggle: .reh-me-check checkbox per card, sets rehState.cast[sp].voice = 'me' (handled via _castApplyToLines/change listener ~line 1518); when voice==='me' the character is recorded live instead of TTS-synthesized. +Narrator handling: _ensureNarrator() keeps rehState.cast[REH_NARRATOR_KEY] bidirectionally synced with rehState.narratorVoice (a dedicated cast row, not a separate UI section anymore). +Voice-matching tools: #reh-matchlib-btn ("Match local" — LLM picks best existing library voice, no TTS engine needed), #reh-matchonline-btn ("Match online" — searches fish.audio, imports voices), #reh-autodesign-btn ("Design all" — generates new voices via Voice Design engine); all driven by rehResearchCast()/rehWriteCharacterNote()/_pickVoiceAvatar() and progress bar #reh-autodesign-progress. +Bulk/filter tools: search/filter/sort toolbar (#reh-cast-search, gender/lang filters, #reh-cast-sort, #reh-cast-sort-dir), _castSortFilter(); per-card actions include voice audition (_rehAudition, _rehPreviewLocal, _rehPreviewCastLine), assign local voice (_rehAssignLocal), online search results (_rehSearchOnline, _rehUseSearchResult, _rehImportFishCandidate), "develop" a character bio (_castDevelop), and delete (_castDeleteCharacter). +Buttons: Back (#reh-back-1-btn), Save to library (#reh-cast-save-btn), Open rehearsal (#reh-start-btn → showPhase(3)). +3. Stage phase (phase 3) +Rendering: buildScriptPage() builds #reh-script-lines from rehState.lines; each line has type ∈ act | scene | action | pagebreak | transition | direction | dialog (confirmed switch in buildScriptPage), each rendered with its own block class (.reh-act, .reh-scene, .reh-action-block, .reh-block-pagebreak, .reh-transition, .reh-direction, .reh-block for dialog). +Per-dialog-line controls: play/pause avatar button (_rehCharAvatarHtml, .reh-line-play-avatar), speaker name/color, TTS-vs-Me badge, emotion picker (openEmoPicker/selectEmotion/closeEmoPicker), inline text edit pencil (startInlineEdit, .reh-edit-btn), per-line note (.reh-note-btn/.reh-note-ta), synth-status dot and re-synth button (_markSynthDot, _showReSynthBtn). +Practice range markers: gutter button sets practiceStart/practiceEnd (updatePracticeRange, clearPracticeRange, setPracticeRangeFromSelection), shown in transport bar (#reh-practice-info). +Bulk edit mode: setBulkMode(), .reh-bulk-check per line, toolbar #reh-bulk-bar (select all/clear/set range/ignore/unignore/hide/delete/show-hidden/done) backed by _toggleBulkSel, _bulkApply, _bulkDelete, _reindexLineState. +Page-mode / A4 rendering: applyPageMode(), cyclePageMode(), paginateScript(), #reh-page-mode-btn (scroll / A4 pages / PDF-style pages), font size controls (rehApplyStageFont, #reh-font-inc/dec). +Character sidebar strip: renderCastStrip() → #reh-cast-strip, collapsible (rehToggleCast, #reh-cast-toggle), with its own search/sort (#reh-cast-side-search, #reh-cast-side-sort). +Top toolbar (director's console, #reh-transport-bar): transport (prev/play/stop/next/loop), progress label; action buttons — Synth all (#reh-tb-synth-all → synthAll()), Audiobook (#reh-tb-audiobook → audiobookExport() in audiobook.js), Character sheets (#reh-charsheets-btn → csForRehearser() in character-sheets.js), Re-synth stale (#reh-tb-resynth-stale), Skip-desc toggle, Bulk-edit toggle (#reh-bulk-toggle), Edit script/title (#reh-edit-script-btn → openScriptEditorModal), Save (#reh-tb-save), Export .reh/.fountain buttons, font size, page-mode toggle, Train mode (#reh-train-open-btn), Exit. +Also on stage: TTS now-playing bar (#reh-tts-status-bar), "my turn" mic recording overlay (#reh-rec-overlay, startRehMic/rehRenderMeter), and the Train Mode panel (#reh-train-panel, see §7). +4. Summary phase (phase 4) +renderSummary() → #reh-summary-list: lists all recorded/synthesized clips from the session. +Actions: Save to library, export .reh/.fountain/.fdx/.osf, Resume (back to stage), New script (reset to Library). +5. Audio pipeline +Per-line synth: synthOneLine(idx) (single line, on-demand) and synthAll() (batch pre-synth all TTS-eligible lines), both call fetchTtsPreviewBlob(voice, text, 'wav', instruct, backend) and cache results in rehState.synthCache (Map keyed by line index); stale entries (tone changed after synth) tracked in rehState.staleLines and surfaced via a re-synth button. +Playback: startPlay/pausePlay/stopPlay/playNextLine() drive line-by-line playback; preDecodeBlob/playPreDecoded/rehDecodedBuffers give zero-latency playback via pre-decoded PCM; computeWordTimings drives text highlighting. +Narrator confirmed: dialog lines always use their cast voice; non-dialog lines (action/scene/direction/transition/act, "any line with text") are read by rehState.narratorVoice — but only if a narrator voice is actually set. If no narrator voice is set, skipDescriptions (default true) skips them entirely during playback and synth (playNextLine/synthAll both check narratorVoice before narrating). Narrator is modeled as a regular cast entry keyed by sentinel REH_NARRATOR_KEY, kept in sync with rehState.narratorVoice via _ensureNarrator(). +6. Persistence +saveToLibrary() builds a record via rehCurrentRecord() (title, reconstructed script text via linesToScriptText(), cast, per-line emotions/notes/ignored/hidden maps, backend, narratorVoice, lineIndex, clips) and calls rehDbPut/rehDbAdd (update vs insert based on rehState.savedId); also writes voice choices back into the shared character roster via castWriteBack(). +rehDbGetAll/rehDbGetById/rehDbAdd/rehDbPut/rehDbDelete wrap REST calls to /api/rehearsals (routes/rehearsals_db.py), backed by SQLite table rehearsals in core/database.py (columns: id, title, script, cast, emotions, notes, ignored, hidden_lines, backend, narrator_voice, line_index, created, updated — cast/emotions/notes/ignored/hidden stored as JSON TEXT). _rehSanitize/clipsToJson/clipsFromJson handle audio blob (de)serialization for clips. +7. Other distinct features +Train mode (trainState object, ~line 4233): a practice mode separate from Stage — buildTrainSeq() builds cue/my-line turn sequence, trainGoTo() navigates turns, plays the other actor's cue (_trainPlayCueLines), records the user's line, transcribes via _trainTranscribe (speech-to-text), and compares expected vs actual text (_trainCompare/_trainLcs/_trainNormWords) with a score shown in #reh-train-result. Entered/exited via enterTrainMode()/exitTrainMode(). +IMSDb/Scripts.com browser: modal #reh-imsdb-modal lets users browse ~1300 movie scripts or paste a URL, fetched server-side and parsed like any pasted script. +Import/Export panel (#reh-impex-panel): supports import from .txt/.md/.pdf/.fountain/.fdx/.osf/.reh and URL; export to .reh (full session incl. audio clips), .fountain, .fdx (Final Draft XML), .txt, .md, .osf (Open Screenplay Format) via exportFountain/exportFDX/exportOSF/exportAsTxt/exportAsMd/exportToFile. +Character sheets integration (character-sheets.js's csForRehearser) generates RPG-style actor sheets from the script's cast. +Audiobook export integration (audiobook.js's audiobookExport) synthesizes the whole script and packages it as chapterized MP3s; audiobook.js can also open a rehearsal directly via window.rehLoadRecord. +Now I have a complete picture. Here is the feature inventory. + +Read Aloud — Feature Inventory +1. Source import +Paste text: #reader-paste-text textarea + #reader-paste-load button → readerImportPastedText() → readerLoadText(text). Sets readerState.docText, readerState.mode = 'text'. +File import (drag/drop or #reader-file-input): readerImportFile(file). .txt/.md → readerLoadText; .pdf → two-stage: readerLoadPdfSkeleton(file) (fast raster via pdf.js, no text layer yet, shows #reader-extract-banner) then explicit readerRunExtraction() → readerExtractPdfText(loaded) (runs getTextContent(), optional heading OCR via #reader-ocr-headings → readerOcrPageHeading/Tesseract.js, builds sentences). +Sentence/paragraph building: readerBuildSentences(words), readerMarkParagraphBreaks(pageWords) (sets .para/.paraStart), readerGroupUnits(base, mode) groups into synthesis chunks per chunkMode (sentence/paragraph/page, UI: #reader-chunk-mode). +Key readerState fields: mode ('pdf'|'text'), pdfDoc, pages[], sentences[] (synth units), baseSentences[] (raw), docText, fileBlob, chunkMode, _seq (import generation guard), savedId/savedAudioIdx/sourceUploaded (library linkage). +Document viewport: #reader-doc, zoom (readerApplyZoom, #reader-zoom-*), lazy raster (readerSetupLazyRaster, IntersectionObserver, readerEvictCanvases), in-doc search (readerSearchApply, #reader-search*). +Library persistence (separate from casting): readerSaveLibrary(), readerOpenLibraryDoc(id), READER_API = '/api/reader/docs' — stores meta/source/per-unit audio server-side; resume position via readerSaveResume/readerLoadResume (localStorage reader-resume). +2. Casting audiobook (speaker attribution) +Entry point: #reader-audiobook-btn → audiobookOpenCastView() (static/js/audiobook.js), which restores an in-memory/localStorage/server draft or starts fresh via audiobookCastView(...) (the live UI, #reader-audiobook-panel). +Scope text: audiobookScopeText() reads readerScopeIndices()/readerState.sentences (selection, PDF page-range, or whole doc) and builds page-mark offsets (_audiobook.pageMarks). +Pass 1 — initial cast: audiobookCast(overrideUrl, overrideModel, resume). Splits scope text into ~3000-char chunks (splitTextIntoChunks), for each chunk calls attributeChunk() → audiobookAttributeStream() (SSE /api/attribute-dialogue/stream, shows live LLM "thinking") falling back to blocking POST /api/attribute-dialogue; on failure retries by splitting the chunk in half; falls back to audiobookSplitByQuotes() (regex-only) if LLM unusable. Runs deterministic audiobookResolveUnknowns() per chunk (colon-rule / inquit heuristics), builds roster[]. Autosaves via _abSaveDraft every chunk / _abStartDraftAutosave. +Cleanup pass (end of audiobookCast, not LLM-based): _audiobookFixOrphanedQuoteMarks() → _audiobookMergeAdjacentSameSpeaker() (also _audiobookDedupNearbyDuplicates exists) — merges consecutive same-speaker segments, fixes stray quote boundaries. +Pass 2 — "Verify"/recast unknowns: audiobookRecastUnknown(overrideUrl, overrideModel, options) — re-resolves mechanical cases, then re-sends only Unknown-speaker (and optionally, via options.includeNarrator, all Narrator) lines in small context groups (audiobookRecastGroups/audiobookRecastContext) to the LLM, canonicalizing returned names against saved character-library aliases (clGetAllByTagOrBook, clSplitIdentityTokens). +State: _audiobook = { running, cancel, segments, roster, lastText, pageMarks, rehId, completedChunks, completedTotal, bookId } (global, window._audiobook). +Persists cast to Rehearsal library via audiobookSaveAsRehearsal({silent:true}) and hands off to Script Rehearser: audiobookShowPreview() → audiobookOpenCurrentInRehearser() / (legacy path) audiobookBuildScript(segments) + audiobookOpenInRehearser(script, title, dialogueEmotions) (fills #reh-script-text, calls navTo('s-rehearser'), clicks #reh-parse-btn). +3. Cast Characters (character sheet generation) — character-sheets.js +Distinct from dialogue casting: generates rich profiles, not speaker attribution. Entry csForReader(opts) (button "Cast from Reader" in #reader-charsheets-panel's empty state) — builds csReaderText() from readerScopeIndices(), seeds from existing library records (csSeedSheet, clGetAllByTagOrBook), attaches dialogue-line counts from _audiobook.segments (csAttachLineCounts), then calls csGenerate(text, cacheKey, knownRoster, {pageHost, seedSheets, lineCounts}) which streams passage-by-passage extraction (csGenerateStream) and merges results (csMerge, csConsolidateAliasDuplicates). +opts.fresh triggers a full recast discarding existing sheets. +csForReaderSelective(selectedNames) regenerates only picked characters (targeted evidence windows via csEvidenceWindowText/csParagraphBlocks). +Also csForRehearser() — same mechanism sourced from the Rehearser script instead (not in scope here). +Persists via csSaveToLibrary(book, sheets) → clUpsertMany (character library, shared with casting/Rehearser). +Renders in #reader-charsheets-panel via csShow(sheets, title, sourceText, book, hostEl); each sheet card built by csCardHtml; auto-generates external prompts (SillyTavern card / image-gen turnaround) via csAutoGenerateExternalPrompts as a background pass. +4. Cast / roster review UI (inside audiobookCastView, audiobook.js ~1313-3100) +Live feed (.ab-cv-feed inside #reader-audiobook-panel) shows attributed narration/dialogue rows as they stream in, with page-break dividers (view.pagemark). +Sidebar roster: renderRoster() — list of characters with line counts, colors, search filter, sort (count/alpha), persisted sort in localStorage ttsvc_ab_side_sort. +Per-row: click a speaker name to open a reassignment popup; _abOpenAliasPopup(name, anchorEl) lets you add an alias (writes via clUpsert(book, {name, aliases})) or merge two roster entries — _abMergeCharacters(fromName, intoName) relabels every matching segment, then _abPatchScatteredRows/_abRedrawSegmentsChunked repaints only affected rows. +_abOpenRecastSelectPopup(existingChars) / audiobookRecastSelectedCharacters(selectedNames) — pick specific characters to re-verify. +Export/handoff buttons inside the panel: recast unknowns ("Verify"), open/continue casting, export cast as Markdown (audiobookExportCastMd() → _abCastMarkdown(data)), and "Review & cast" → audiobookShowPreview(). +5. TTS playback in Read Aloud itself (separate from audiobook generation) +Yes — Read Aloud has its own single-voice sentence-by-sentence playback with word highlighting, independent of the multi-speaker audiobook pipeline: + +Transport bar #reader-transport (#reader-play, #reader-stop, #reader-prev/#reader-next, #reader-progress-fill). +readerPlay()/readerPause()/readerPlayCurrent() — fetches/caches per-unit audio (readerGetBuffer, fetchTtsPreviewBlob), computes word timings via computeWordTimings (reused from rehearser.js), and highlights the active word (readerHighlightWord) plus auto-scroll (readerEnsureVisible). +Uses readerCtx() (Web Audio API), readerComputeGain for RMS loudness normalization (#reader-normalize), readerState.speed (#reader-speed slider) for playback-rate control, readerGenParams() for seed/temperature/native-speed. +Batch pre-synthesis ("Synthesise ahead"): readerSynthAll()/readerSynthIndices(targets), scoped via readerScopeIndices() (selection / page range / all), shown in #reader-synthbar / #reader-synth-prog. +Per-unit status coloring (pending/synthesising/ready/reading) via readerSetStatus/readerPaintStatus, legend .reader-legend. +6. Other distinct features +Range selection: click-to-select start/end sentence (readerSetSelecting, readerPickSentence, #reader-select-toggle), used to scope both synthesis and casting. +MP3 export: readerExport(mode) — #reader-export-mode (page/sentence), #reader-export-btn; synthesizes any missing scoped units first and blocks export if any fail. +Document search: readerSearchApply/readerJumpToSearchHit (#reader-search*), independent of casting. +Voice-consistency ("chunk mode") re-grouping: readerRechunk(mode) — clears cached audio when granularity changes. +Backend/voice pickers + tuning: #reader-backend-select, #reader-voice-select (VoicePicker), #reader-instruct, seed/temperature/native-speed inputs, readerUpdateBackendHint() (warns about voice drift on non-style-aware backends). +Reader library (#reader-library-card/#reader-lib-list, readerRenderLibrary) — separate saved-books browser with cover-image drag/drop upload, delete-with-confirm overlay; distinct from the Character Library and Rehearsal Library. +View switching within the section: window.showReaderView(view) toggles reader-main-view / reader-audiobook-panel ('cast') / reader-charsheets-panel ('chars') / reader-library-card ('library'), driving refreshWorkflowCrumbs. Also window.readerJumpToPage(pageNum) for cross-linking from other sections (e.g. jump to a PDF page from a character sheet's evidence citation). \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c172f51..5e28535 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,14 @@ All notable changes to **TTS Voice Creator — Clone and Design** are documented Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned with [Semantic Versioning](https://semver.org/). --- - + +## [1.21.1] — 2026-08-23 + +### Added +- **Image Generation Scripts.** Added scratch scripts for testing image generation providers (Flux, Gemini, Google Imagen, OpenAI, Pollinations). +- **Character Tooling.** Added scratch scripts for character detail fetching and batch generation. +- **Inventory Markdown.** Added 2026-07-16 inventory documentation. + ## [1.21.0] — 2026-08-23 ### Added diff --git a/VERSION b/VERSION index 3500250..2844977 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.21.0 +1.21.1 diff --git a/scratch/batch_generate_all.py b/scratch/batch_generate_all.py new file mode 100644 index 0000000..2ff5851 --- /dev/null +++ b/scratch/batch_generate_all.py @@ -0,0 +1,67 @@ +import requests +import json +import urllib.parse +from concurrent.futures import ThreadPoolExecutor + +BASE_URL = "http://localhost:7890" + +def process_char(char): + name = char.get("name") + if name in ["Marcian", "Nyrilla", "Arthag", "Lysandra", "Darrag", "Himgi"]: + return # Skip ones we already fixed perfectly + + char_id = urllib.parse.quote(char["id"]) + sheet = char.get("sheet") or {} + if isinstance(sheet, str): + try: + sheet = json.loads(sheet) + except: + sheet = {} + + phys = sheet.get('physical', '') + cloth = sheet.get('clothing', '') + + # Portrait + portrait_prompt = f"Task: Generate a game NPC portrait. Subject: {name}. Physical traits: {phys}. Clothing: {cloth}. Context: dialogue portrait for a stylized exploration game set in an original world. Style: painterly game concept art with clear shape language, grounded materials, and slightly exaggerated but believable proportions. Composition: a simple square headshot/bust on a plain neutral muted parchment background, facing forward with a subtle expression. Lighting: neutral studio key with soft rim separation and no cinematic color." + + # Concept + concept_prompt = f"Task: Generate a game NPC design sheet. Subject: {name}. Physical traits: {phys}. Clothing: {cloth}. Context: handoff reference for a stylized exploration game set in an original world. Style: painterly game concept art with clear shape language, grounded materials, and slightly exaggerated but believable proportions. Composition: full-body front, side, and back views across the top; below them, one dialogue pose and a single clean callout row containing exactly 3 items on a muted parchment landscape board. Lighting: neutral studio key with soft rim separation and no cinematic color." + + print(f"[{name}] Starting generation...") + # Generate Portrait + try: + resp_img = requests.post(f"{BASE_URL}/api/character-generate-image", json={"prompt": portrait_prompt}) + if resp_img.ok: + char["image"] = resp_img.json().get("image") + except Exception as e: + print(f"Error portrait {name}: {e}") + + # Generate Concept + try: + resp_concept = requests.post(f"{BASE_URL}/api/character-generate-image", json={"prompt": concept_prompt}) + if resp_concept.ok: + sheet["concept_art_image"] = resp_concept.json().get("image") + except Exception as e: + print(f"Error concept {name}: {e}") + + sheet["image_prompt"] = portrait_prompt + sheet["concept_art_prompt"] = concept_prompt + char["sheet"] = sheet + + resp_put = requests.put(f"{BASE_URL}/api/characters/{char_id}", json=char) + print(f"[{name}] Finished. Status: {resp_put.status_code}") + +def main(): + resp = requests.get(f"{BASE_URL}/api/characters") + characters = resp.json().get("characters", []) + + to_process = [c for c in characters if c.get("name") not in ["Marcian", "Nyrilla", "Arthag", "Lysandra", "Darrag", "Himgi"]] + + print(f"Processing {len(to_process)} characters...") + + # Use 10 workers for speed! Pollinations can handle it. + with ThreadPoolExecutor(max_workers=10) as executor: + executor.map(process_char, to_process) + +if __name__ == "__main__": + main() diff --git a/scratch/fix_avatars.py b/scratch/fix_avatars.py new file mode 100644 index 0000000..a865a6d --- /dev/null +++ b/scratch/fix_avatars.py @@ -0,0 +1,56 @@ +import requests +import json +import urllib.parse +from concurrent.futures import ThreadPoolExecutor + +BASE_URL = "http://localhost:7890" + +def process_avatar(char): + name = char.get("name") + if name in ["Marcian", "Nyrilla", "Arthag", "Lysandra", "Darrag", "Himgi"]: + return # Skip ones we already fixed perfectly + + char_id = urllib.parse.quote(char["id"]) + sheet = char.get("sheet") or {} + if isinstance(sheet, str): + try: + sheet = json.loads(sheet) + except: + sheet = {} + + phys = sheet.get('physical', '') + cloth = sheet.get('clothing', '') + + # Strict Portrait Prompt to defeat Flux's tendency to draw turnaround sheets + portrait_prompt = f"A beautiful tight headshot portrait of {name}. Physical traits: {phys}. Clothing: {cloth}. Style: high quality painterly fantasy illustration, single face facing forward. Plain neutral parchment background. ONLY ONE PERSON, close-up on face and shoulders, NO MULTIPLE VIEWS, NO concept art sheet." + + print(f"[{name}] Starting avatar fix...") + # Generate Portrait + try: + resp_img = requests.post(f"{BASE_URL}/api/character-generate-image", json={"prompt": portrait_prompt}) + if resp_img.ok: + char["image"] = resp_img.json().get("image") + sheet["image_prompt"] = portrait_prompt + char["sheet"] = sheet + + resp_put = requests.put(f"{BASE_URL}/api/characters/{char_id}", json=char) + print(f"[{name}] Finished. Status: {resp_put.status_code}") + else: + print(f"[{name}] Failed to generate: {resp_img.text}") + except Exception as e: + print(f"Error portrait {name}: {e}") + +def main(): + resp = requests.get(f"{BASE_URL}/api/characters") + characters = resp.json().get("characters", []) + + to_process = [c for c in characters if c.get("name") not in ["Marcian", "Nyrilla", "Arthag", "Lysandra", "Darrag", "Himgi"]] + + print(f"Processing {len(to_process)} avatars...") + + # Use 1 worker to avoid rate limits + with ThreadPoolExecutor(max_workers=1) as executor: + executor.map(process_avatar, to_process) + +if __name__ == "__main__": + main() diff --git a/scratch/get_char_details.py b/scratch/get_char_details.py new file mode 100644 index 0000000..aabcc0e --- /dev/null +++ b/scratch/get_char_details.py @@ -0,0 +1,18 @@ +import sqlite3 +import json + +db = sqlite3.connect("config/tts_creator.db") +c = db.cursor() + +names = ["Karyla", "Kolon", "Misira", "Uriens", "Karman", "Inquisitor", "Sklave", "Junge Ritterin", "Ork", "Gernot Brohm", "Kriegerin", "Magier", "Bäckerstochter", "Blautann und seine Männer", "Druide", "Krieger", "Kutscher", "Reiter", "Turmwächter", "Verwundeter Soldat", "Wache", "Yonsus", "alter Weber"] + +prompts = [] +for name in names: + c.execute("SELECT sheet FROM characters WHERE name=?", (name,)) + row = c.fetchone() + if row: + sheet = json.loads(row[0]) + phys = sheet.get("physical", "") + cloth = sheet.get("clothing", "") + prompt = f"A tight square headshot portrait of {name}. Physical traits: {phys}. Clothing: {cloth}. Style: high quality painterly fantasy illustration, single face facing forward. Plain neutral parchment background. ONLY ONE PERSON, close-up on face and shoulders." + print(f"{name}|{prompt}") diff --git a/scratch/test_flux.py b/scratch/test_flux.py new file mode 100644 index 0000000..5ff8ea6 --- /dev/null +++ b/scratch/test_flux.py @@ -0,0 +1,14 @@ +import requests +import base64 + +prompt = "A simple square headshot portrait of Karyla, an adult female Amazon warrior. Plain neutral parchment background. Painterly fantasy illustration style, single face only, facing forward. Do not include multiple views, this is a dialogue portrait." + +url = f"https://image.pollinations.ai/prompt/{requests.utils.quote(prompt)}?width=512&height=512&nologo=true" + +response = requests.get(url) +if response.status_code == 200: + with open("test_flux_portrait.png", "wb") as f: + f.write(response.content) + print("Success, saved test_flux_portrait.png") +else: + print("Error:", response.status_code) diff --git a/scratch/test_gemini_imagen.py b/scratch/test_gemini_imagen.py new file mode 100644 index 0000000..80038c1 --- /dev/null +++ b/scratch/test_gemini_imagen.py @@ -0,0 +1,26 @@ +import requests +import json +import base64 + +API_KEY = "AQ.Ab8RN6JRC8vPh-vLzItUVeS4vCofqzMf9TyF6Ce6BXw-Y18GuA" +# Use Interactions API format if needed, but let's try the standard endpoint first. +url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-3.1-flash-image:generateContent?key={API_KEY}" + +payload = { + "contents": [{ + "parts": [{"text": "A simple square headshot portrait of Karyla. Style: painterly game concept art."}] + }] +} +headers = {'Content-Type': 'application/json'} + +response = requests.post(url, headers=headers, json=payload) +print(response.status_code) +if response.ok: + data = response.json() + try: + # gemini-3.1-flash-image might return images in a different structure + print(json.dumps(data)[:200]) + except Exception as e: + print("Failed to parse response:", data) +else: + print(response.text[:500]) diff --git a/scratch/test_google_imagen.py b/scratch/test_google_imagen.py new file mode 100644 index 0000000..cbfbe66 --- /dev/null +++ b/scratch/test_google_imagen.py @@ -0,0 +1,20 @@ +import requests +import json +import base64 + +API_KEY = "AIzaSyD6aidNxIhr2SKgauZ9zea_FynuCo2DyDo" +url = f"https://generativelanguage.googleapis.com/v1beta/interactions" + +payload = { + "model": "gemini-3.1-flash-image", + "input": [{"type": "user_input", "content": [{"type": "text", "text": "A beautiful square headshot portrait of Karyla. Style: painterly game concept art."}]}], + "response_modalities": ["image"] +} +headers = {'x-goog-api-key': API_KEY, 'Content-Type': 'application/json'} + +response = requests.post(url, headers=headers, json=payload) +print(response.status_code) +if response.ok: + print("Success! Got image") +else: + print(response.text[:500]) diff --git a/scratch/test_openai.py b/scratch/test_openai.py new file mode 100644 index 0000000..103f51d --- /dev/null +++ b/scratch/test_openai.py @@ -0,0 +1,24 @@ +import requests +import json + +API_KEY = "sk-proj-jVzNl_bM-oRpR_W1F-W5bLwXQ4e38nS3pQf4eY6k2M6tX-TZA9YmH4lF" # From settings.json wait, I don't know the full key. I'll read it from settings.json +with open("config/settings.json") as f: + settings = json.load(f) + api_key = settings.get("engine_api_keys", {}).get("openai_image") + +url = "https://api.openai.com/v1/images/generations" + +payload = { + "model": "dall-e-3", + "prompt": "A beautiful square headshot portrait of Karyla. Style: painterly game concept art.", + "n": 1, + "size": "1024x1024" +} +headers = {'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'} + +response = requests.post(url, headers=headers, json=payload) +print(response.status_code) +if response.ok: + print("Success! OpenAI generated image.") +else: + print(response.text[:500]) diff --git a/scratch/test_pollinations_portrait.py b/scratch/test_pollinations_portrait.py new file mode 100644 index 0000000..968eb4f --- /dev/null +++ b/scratch/test_pollinations_portrait.py @@ -0,0 +1,13 @@ +import requests + +prompt = "Task: Generate a game NPC portrait. Subject: an original adult female elven mage with long pointed ears, slightly glowing eyes, a mystical but weary aura, wearing simple practical traveler/prisoner garb with subtle elven motifs. Context: dialogue portrait for a stylized exploration game set in an original world. Style: painterly game concept art with clear shape language, grounded materials, and slightly exaggerated but believable proportions. Composition: a simple square headshot/bust on a plain neutral muted parchment background, facing forward with a subtle expression. Lighting: neutral studio key with soft rim separation and no cinematic color." + +url = f"https://image.pollinations.ai/prompt/{requests.utils.quote(prompt)}?width=512&height=512&nologo=true" + +response = requests.get(url) +if response.status_code == 200: + with open("test_pollinations_portrait.png", "wb") as f: + f.write(response.content) + print("Success") +else: + print("Error:", response.status_code) diff --git a/scratch/update_karyla.py b/scratch/update_karyla.py new file mode 100644 index 0000000..0965384 --- /dev/null +++ b/scratch/update_karyla.py @@ -0,0 +1,15 @@ +import sqlite3 +import base64 + +db = sqlite3.connect("config/tts_creator.db") +c = db.cursor() + +with open("/home/sparky/.gemini/antigravity/brain/a40bef3c-201f-47af-95f1-c3c67e7f8973/karyla_avatar_1786889767286.png", "rb") as f: + img_data = f.read() + +b64 = base64.b64encode(img_data).decode('utf-8') +data_uri = f"data:image/png;base64,{b64}" + +c.execute("UPDATE characters SET image=? WHERE name='Karyla'", (data_uri,)) +db.commit() +print("Karyla updated in DB.") diff --git a/test_flux_portrait.png b/test_flux_portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..985fd3c1c388eaf4d6720113b74f128ae82194c2 GIT binary patch literal 31524 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 literal 0 HcmV?d00001 diff --git a/test_pollinations_portrait.png b/test_pollinations_portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..3418f3b8132128f6b37d6cb9b38bfb1732f2f577 GIT binary patch literal 30213 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 literal 0 HcmV?d00001