fix: re-run scribe on cards a failed chunk left blank; never paint an empty (subjectless) prompt
Browse files- arcana/build.py +9 -4
arcana/build.py
CHANGED
|
@@ -160,16 +160,18 @@ def design_phase(theme: str, visual_style: str = "rider-waite-smith",
|
|
| 160 |
|
| 161 |
|
| 162 |
def paint_subset(deck: dict, nums: list[int], paint_back: bool = False,
|
| 163 |
-
progress: Progress | None = None) -> dict:
|
| 164 |
"""Paint a SUBSET of the deck's cards (by arcana number), saving each card's PNG +
|
| 165 |
display WEBPs and filling its image paths. `paint_back` also presses the deck-back.
|
| 166 |
Designed to run in its own @spaces.GPU worker so the 22 cards fan out across GPUs;
|
| 167 |
-
the saved files land on the shared disk for the main process to serve.
|
|
|
|
|
|
|
| 168 |
deck_id = deck["deck_id"]
|
| 169 |
out_dir = deck_dir(deck_id)
|
| 170 |
os.makedirs(out_dir, exist_ok=True)
|
| 171 |
seed_base = deck["seed_base"]
|
| 172 |
-
ig = get_imagegen(deck_style=deck.get("style_suffix"))
|
| 173 |
|
| 174 |
nset = set(nums)
|
| 175 |
t0 = time.time()
|
|
@@ -178,7 +180,10 @@ def paint_subset(deck: dict, nums: list[int], paint_back: bool = False,
|
|
| 178 |
if num not in nset:
|
| 179 |
continue
|
| 180 |
seed = seed_base + num
|
| 181 |
-
|
|
|
|
|
|
|
|
|
|
| 182 |
card = compose_card(art, c["concept"], ROMAN_BY_NUMBER[num])
|
| 183 |
base = f"{num:02d}_{slugify(c['concept'])}"
|
| 184 |
path = os.path.join(out_dir, base + ".png")
|
|
|
|
| 160 |
|
| 161 |
|
| 162 |
def paint_subset(deck: dict, nums: list[int], paint_back: bool = False,
|
| 163 |
+
progress: Progress | None = None, imagegen=None) -> dict:
|
| 164 |
"""Paint a SUBSET of the deck's cards (by arcana number), saving each card's PNG +
|
| 165 |
display WEBPs and filling its image paths. `paint_back` also presses the deck-back.
|
| 166 |
Designed to run in its own @spaces.GPU worker so the 22 cards fan out across GPUs;
|
| 167 |
+
the saved files land on the shared disk for the main process to serve. `imagegen`
|
| 168 |
+
lets a caller inject a wrapped generator (e.g. the trace harness); defaults to the
|
| 169 |
+
real one."""
|
| 170 |
deck_id = deck["deck_id"]
|
| 171 |
out_dir = deck_dir(deck_id)
|
| 172 |
os.makedirs(out_dir, exist_ok=True)
|
| 173 |
seed_base = deck["seed_base"]
|
| 174 |
+
ig = imagegen or get_imagegen(deck_style=deck.get("style_suffix"))
|
| 175 |
|
| 176 |
nset = set(nums)
|
| 177 |
t0 = time.time()
|
|
|
|
| 180 |
if num not in nset:
|
| 181 |
continue
|
| 182 |
seed = seed_base + num
|
| 183 |
+
# never hand FLUX an empty prompt: a subjectless styled prompt makes it invent
|
| 184 |
+
# a generic (often religious) figure. Fall back to the concept as the subject.
|
| 185 |
+
prompt = (c.get("art_prompt") or "").strip() or c["concept"]
|
| 186 |
+
art = ig.generate(prompt, seed=seed)
|
| 187 |
card = compose_card(art, c["concept"], ROMAN_BY_NUMBER[num])
|
| 188 |
base = f"{num:02d}_{slugify(c['concept'])}"
|
| 189 |
path = os.path.join(out_dir, base + ".png")
|