ASTRALK commited on
Commit
15dcc39
·
verified ·
1 Parent(s): 044e70f

Upload comic/imaging.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. comic/imaging.py +72 -0
comic/imaging.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Assemble a FLUX image prompt for one panel, and a deterministic seed.
2
+
3
+ Character consistency is the hard part of a multi-panel comic: FLUX renders every
4
+ panel independently, so the only lever we have to keep a character looking the same
5
+ across 20 images is to feed its FIXED visual description (from the bible) verbatim
6
+ into every panel it appears in. So a panel prompt is, in order:
7
+
8
+ <art style>, comic book panel, <scene>, <appearance of each character present>,
9
+ <palette>, <text-free contract>
10
+
11
+ The art style + palette are constant across the whole comic (style consistency);
12
+ the per-character appearance is constant per character (character consistency);
13
+ only the scene varies panel to panel (story variety).
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import hashlib
19
+
20
+ from .schema import Panel, ComicBible
21
+
22
+ # FLUX bakes garbled letters if asked for signage; the distilled model ignores
23
+ # negative prompts, so the "no text" contract lives in the positive prompt. The UI
24
+ # renders captions separately, so we never want text inside the image.
25
+ TEXT_FREE = (
26
+ "no text, no speech bubbles, no captions, no lettering or words anywhere in the image"
27
+ )
28
+
29
+ # A sane default if the writer omitted a style/palette.
30
+ DEFAULT_STYLE = (
31
+ "modern western comic book art, bold confident black ink linework, dynamic "
32
+ "cel shading, clean dramatic composition"
33
+ )
34
+ DEFAULT_PALETTE = "rich saturated comic-book color palette"
35
+
36
+
37
+ def _appearance_clause(panel: Panel, bible: ComicBible) -> str:
38
+ """The verbatim fixed appearance text for each named character in this panel.
39
+
40
+ This is the consistency anchor — same words every time a character appears.
41
+ """
42
+ clauses = []
43
+ for name in panel.characters:
44
+ ch = bible.character(name)
45
+ if ch is not None and ch.appearance:
46
+ clauses.append(f"{ch.name}: {ch.appearance}")
47
+ return "; ".join(clauses)
48
+
49
+
50
+ def build_image_prompt(panel: Panel, bible: ComicBible) -> str:
51
+ """Full FLUX prompt for one panel (idempotent; also stored on panel.image_prompt)."""
52
+ style = bible.art_style or DEFAULT_STYLE
53
+ palette = bible.palette or DEFAULT_PALETTE
54
+ scene = (panel.scene or "").strip().rstrip(".")
55
+ chars = _appearance_clause(panel, bible)
56
+
57
+ parts = [style, "comic book panel", scene]
58
+ if chars:
59
+ parts.append(chars)
60
+ parts += [palette, TEXT_FREE]
61
+ return ", ".join(p for p in parts if p and p.strip())
62
+
63
+
64
+ def panel_seed(bible: ComicBible, panel: Panel) -> int:
65
+ """Deterministic per-panel seed (stable across reruns, distinct per panel).
66
+
67
+ Keyed on the title + panel index so the same comic re-renders identically and
68
+ no two panels collide on a seed.
69
+ """
70
+ key = f"{bible.title}|{panel.index}".encode("utf-8")
71
+ digest = hashlib.sha256(key).digest()
72
+ return int.from_bytes(digest[:4], "big") & 0x7FFFFFFF