| """Generate the loading SAMPLE book (assets/sample_book/) from REAL FLUX output. |
| |
| Turns the example cat doodle into a consistent crayon storybook hero via the |
| deployed Modal pipeline, so the sample users see on load is genuine app output |
| (not the old placeholder blobs). Images are inlined as base64 so sample.html is |
| self-contained and renders on the HF Space regardless of temp paths. |
| |
| Run once: python generate_sample.py |
| """ |
|
|
| import os |
| import sys |
| import base64 |
|
|
| sys.path.insert(0, os.path.dirname(__file__)) |
|
|
| import io |
| from PIL import Image |
|
|
| from config import SAMPLE_BOOK_PATH, BASE_SEED |
| from book_builder import COVER_HTML, PAGE_HTML, ENGINE_BADGES |
| import services.images as image_svc |
|
|
| HERE = os.path.dirname(__file__) |
|
|
| |
| CRAYON = ( |
| "hand-drawn crayon children's storybook illustration, soft waxy crayon " |
| "texture and visible crayon strokes, warm colorful crayon shading, " |
| "simple friendly shapes, looks drawn by hand with crayons" |
| ) |
|
|
| TITLE = "Ziggy and the Little Lost Star" |
| CHAR_DESC = ( |
| "Ziggy, a curious round-faced cartoon cat with big friendly eyes, " |
| "pointy ears, whiskers and a long tail" |
| ) |
| |
| PAGES = [ |
| ("Ziggy the curious little cat loved watching the night sky from the rooftop.", |
| "a cute cat sitting on a cozy rooftop at night, gazing up at a big starry sky"), |
| ("One quiet night, a tiny star tumbled down and landed softly in the garden.", |
| "a tiny glowing star falling into a flower garden while the surprised cat watches"), |
| ("The little star was scared and far from home, blinking sadly.", |
| "the cat gently looking at a small sad glowing star sitting in the grass"), |
| ("\"Don't worry,\" purred Ziggy, \"I'll help you climb back to the sky.\"", |
| "the kind cat comforting the little glowing star, cozy and warm at night"), |
| ("Together they leapt from the tallest tree to the top of the old windmill.", |
| "the cat and the glowing star climbing a tall tree toward a windmill at night"), |
| ("With one gentle hop, the star sparkled home, and Ziggy smiled, full of stars.", |
| "the happy cat on a hill waving as the star flies back into the starry sky"), |
| ] |
|
|
|
|
| def _b64(img_bytes: bytes, max_px: int = 720, quality: int = 84) -> str: |
| """Compress to a reasonably small JPEG before inlining — full-res FLUX PNGs |
| would make sample.html >10MB and stall the frontend on load.""" |
| im = Image.open(io.BytesIO(img_bytes)).convert("RGB") |
| if max(im.size) > max_px: |
| im.thumbnail((max_px, max_px), Image.LANCZOS) |
| buf = io.BytesIO() |
| im.save(buf, format="JPEG", quality=quality) |
| return "data:image/jpeg;base64," + base64.b64encode(buf.getvalue()).decode() |
|
|
|
|
| def main(): |
| texts = [t for t, _ in PAGES] |
| scenes = [s for _, s in PAGES] |
| with open(os.path.join(HERE, "assets", "sample_doodle.jpg"), "rb") as f: |
| doodle = f.read() |
|
|
| print("Generating real FLUX pages via Modal (this calls the deployed app)...") |
| images, engine = image_svc.generate_book_pages( |
| CHAR_DESC, scenes, doodle=doodle, art_style=CRAYON, seed=BASE_SEED, |
| ) |
| print(f"engine={engine}, pages={len(images)}") |
| if engine != "flux" or not images: |
| raise SystemExit("FLUX did not run (got sketch); aborting so we never bake a placeholder.") |
|
|
| os.makedirs(SAMPLE_BOOK_PATH, exist_ok=True) |
|
|
| |
| |
| |
| cover = COVER_HTML.format(title=TITLE, badge=ENGINE_BADGES.get("flux", "")) |
| pages_html = "" |
| for i, (b, text) in enumerate(zip(images, texts)): |
| pages_html += PAGE_HTML.format( |
| img_b64=_b64(b), text=text, page_num=i + 1, |
| alt_text=(text[:50] + "...") if len(text) > 50 else text, |
| ) |
| html = f'<div class="book-container">\n{cover}\n{pages_html}\n</div>' |
| with open(os.path.join(SAMPLE_BOOK_PATH, "sample.html"), "w", encoding="utf-8") as f: |
| f.write(html) |
| print(f"Saved sample.html ({len(html.encode()) // 1024} KB)") |
| print("Done.") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|