Real FLUX crayon sample book (cat doodle -> Ziggy and the Little Lost Star); drop unused placeholder assets
Browse files- assets/sample_book/page_1.png +0 -0
- assets/sample_book/page_2.png +0 -0
- assets/sample_book/page_3.png +0 -0
- assets/sample_book/page_4.png +0 -0
- assets/sample_book/page_5.png +0 -0
- assets/sample_book/page_6.png +0 -0
- assets/sample_book/sample.html +0 -0
- assets/sample_book/sample.pdf +0 -0
- generate_sample.py +88 -51
assets/sample_book/page_1.png
DELETED
|
Binary file (5.65 kB)
|
|
|
assets/sample_book/page_2.png
DELETED
|
Binary file (5.19 kB)
|
|
|
assets/sample_book/page_3.png
DELETED
|
Binary file (6.08 kB)
|
|
|
assets/sample_book/page_4.png
DELETED
|
Binary file (5.36 kB)
|
|
|
assets/sample_book/page_5.png
DELETED
|
Binary file (5.94 kB)
|
|
|
assets/sample_book/page_6.png
DELETED
|
Binary file (5.45 kB)
|
|
|
assets/sample_book/sample.html
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
assets/sample_book/sample.pdf
DELETED
|
Binary file (37.1 kB)
|
|
|
generate_sample.py
CHANGED
|
@@ -1,63 +1,100 @@
|
|
| 1 |
-
"""
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
"""
|
| 5 |
|
| 6 |
import os
|
| 7 |
import sys
|
|
|
|
| 8 |
|
| 9 |
-
# Add project root to path
|
| 10 |
sys.path.insert(0, os.path.dirname(__file__))
|
| 11 |
|
| 12 |
-
|
| 13 |
-
from
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
os.makedirs(SAMPLE_BOOK_PATH, exist_ok=True)
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
f.write(html)
|
| 47 |
-
print(f"Saved
|
| 48 |
-
|
| 49 |
-
# Save individual pages
|
| 50 |
-
for i, img_bytes in enumerate(images):
|
| 51 |
-
page_path = os.path.join(SAMPLE_BOOK_PATH, f"page_{i+1}.png")
|
| 52 |
-
with open(page_path, "wb") as f:
|
| 53 |
-
f.write(img_bytes)
|
| 54 |
-
print(f"Saved {len(images)} pages to {SAMPLE_BOOK_PATH}")
|
| 55 |
-
|
| 56 |
-
# Generate PDF
|
| 57 |
-
pdf_path = os.path.join(SAMPLE_BOOK_PATH, "sample.pdf")
|
| 58 |
-
export_pdf(images, texts, title, pdf_path)
|
| 59 |
-
print(f"Saved PDF: {pdf_path}")
|
| 60 |
|
| 61 |
|
| 62 |
if __name__ == "__main__":
|
| 63 |
-
|
|
|
|
| 1 |
+
"""Generate the loading SAMPLE book (assets/sample_book/) from REAL FLUX output.
|
| 2 |
+
|
| 3 |
+
Turns the example cat doodle into a consistent crayon storybook hero via the
|
| 4 |
+
deployed Modal pipeline, so the sample users see on load is genuine app output
|
| 5 |
+
(not the old placeholder blobs). Images are inlined as base64 so sample.html is
|
| 6 |
+
self-contained and renders on the HF Space regardless of temp paths.
|
| 7 |
+
|
| 8 |
+
Run once: python generate_sample.py
|
| 9 |
"""
|
| 10 |
|
| 11 |
import os
|
| 12 |
import sys
|
| 13 |
+
import base64
|
| 14 |
|
|
|
|
| 15 |
sys.path.insert(0, os.path.dirname(__file__))
|
| 16 |
|
| 17 |
+
import io
|
| 18 |
+
from PIL import Image
|
| 19 |
+
|
| 20 |
+
from config import SAMPLE_BOOK_PATH, BASE_SEED
|
| 21 |
+
from book_builder import COVER_HTML, PAGE_HTML, ENGINE_BADGES
|
| 22 |
+
import services.images as image_svc
|
| 23 |
+
|
| 24 |
+
HERE = os.path.dirname(__file__)
|
| 25 |
+
|
| 26 |
+
# Match the app's crayon look (app.py COLOR_ART_STYLE)
|
| 27 |
+
CRAYON = (
|
| 28 |
+
"hand-drawn crayon children's storybook illustration, soft waxy crayon "
|
| 29 |
+
"texture and visible crayon strokes, warm colorful crayon shading, "
|
| 30 |
+
"simple friendly shapes, looks drawn by hand with crayons"
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
TITLE = "Ziggy and the Little Lost Star"
|
| 34 |
+
CHAR_DESC = (
|
| 35 |
+
"Ziggy, a curious round-faced cartoon cat with big friendly eyes, "
|
| 36 |
+
"pointy ears, whiskers and a long tail"
|
| 37 |
+
)
|
| 38 |
+
# (page text, scene prompt) — a complete, gentle 6-page arc that fits the cat doodle
|
| 39 |
+
PAGES = [
|
| 40 |
+
("Ziggy the curious little cat loved watching the night sky from the rooftop.",
|
| 41 |
+
"a cute cat sitting on a cozy rooftop at night, gazing up at a big starry sky"),
|
| 42 |
+
("One quiet night, a tiny star tumbled down and landed softly in the garden.",
|
| 43 |
+
"a tiny glowing star falling into a flower garden while the surprised cat watches"),
|
| 44 |
+
("The little star was scared and far from home, blinking sadly.",
|
| 45 |
+
"the cat gently looking at a small sad glowing star sitting in the grass"),
|
| 46 |
+
("\"Don't worry,\" purred Ziggy, \"I'll help you climb back to the sky.\"",
|
| 47 |
+
"the kind cat comforting the little glowing star, cozy and warm at night"),
|
| 48 |
+
("Together they leapt from the tallest tree to the top of the old windmill.",
|
| 49 |
+
"the cat and the glowing star climbing a tall tree toward a windmill at night"),
|
| 50 |
+
("With one gentle hop, the star sparkled home, and Ziggy smiled, full of stars.",
|
| 51 |
+
"the happy cat on a hill waving as the star flies back into the starry sky"),
|
| 52 |
+
]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _b64(img_bytes: bytes, max_px: int = 720, quality: int = 84) -> str:
|
| 56 |
+
"""Compress to a reasonably small JPEG before inlining — full-res FLUX PNGs
|
| 57 |
+
would make sample.html >10MB and stall the frontend on load."""
|
| 58 |
+
im = Image.open(io.BytesIO(img_bytes)).convert("RGB")
|
| 59 |
+
if max(im.size) > max_px:
|
| 60 |
+
im.thumbnail((max_px, max_px), Image.LANCZOS)
|
| 61 |
+
buf = io.BytesIO()
|
| 62 |
+
im.save(buf, format="JPEG", quality=quality)
|
| 63 |
+
return "data:image/jpeg;base64," + base64.b64encode(buf.getvalue()).decode()
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def main():
|
| 67 |
+
texts = [t for t, _ in PAGES]
|
| 68 |
+
scenes = [s for _, s in PAGES]
|
| 69 |
+
with open(os.path.join(HERE, "assets", "sample_doodle.jpg"), "rb") as f:
|
| 70 |
+
doodle = f.read()
|
| 71 |
+
|
| 72 |
+
print("Generating real FLUX pages via Modal (this calls the deployed app)...")
|
| 73 |
+
images, engine = image_svc.generate_book_pages(
|
| 74 |
+
CHAR_DESC, scenes, doodle=doodle, art_style=CRAYON, seed=BASE_SEED,
|
| 75 |
+
)
|
| 76 |
+
print(f"engine={engine}, pages={len(images)}")
|
| 77 |
+
if engine != "flux" or not images:
|
| 78 |
+
raise SystemExit("FLUX did not run (got sketch); aborting so we never bake a placeholder.")
|
| 79 |
+
|
| 80 |
os.makedirs(SAMPLE_BOOK_PATH, exist_ok=True)
|
| 81 |
+
|
| 82 |
+
# Self-contained HTML: base64-inline the (compressed) images so the baked
|
| 83 |
+
# sample renders on the Space (the live builder uses temp-file URLs, which
|
| 84 |
+
# don't exist for a static file). Only sample.html is used by the app.
|
| 85 |
+
cover = COVER_HTML.format(title=TITLE, badge=ENGINE_BADGES.get("flux", ""))
|
| 86 |
+
pages_html = ""
|
| 87 |
+
for i, (b, text) in enumerate(zip(images, texts)):
|
| 88 |
+
pages_html += PAGE_HTML.format(
|
| 89 |
+
img_b64=_b64(b), text=text, page_num=i + 1,
|
| 90 |
+
alt_text=(text[:50] + "...") if len(text) > 50 else text,
|
| 91 |
+
)
|
| 92 |
+
html = f'<div class="book-container">\n{cover}\n{pages_html}\n</div>'
|
| 93 |
+
with open(os.path.join(SAMPLE_BOOK_PATH, "sample.html"), "w", encoding="utf-8") as f:
|
| 94 |
f.write(html)
|
| 95 |
+
print(f"Saved sample.html ({len(html.encode()) // 1024} KB)")
|
| 96 |
+
print("Done.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
|
| 99 |
if __name__ == "__main__":
|
| 100 |
+
main()
|