Download app.py from SIXR/README: direct link, hf CLI and curl.
- Browser
- Download file 7.83 kB
-
https://huggingface.co/spaces/SIXR/README/resolve/main/app.py
- Command line
-
hf download hf://spaces/SIXR/README/app.py
-
curl -L -o app.py https://huggingface.co/spaces/SIXR/README/resolve/main/app.py
7.83 kB
| """ | |
| SIXR Prompt‑to‑Prototype Studio – Gradio starter app | |
| ==================================================== | |
| A lightweight, one‑file scaffold you can push to a **Hugging Face Gradio Space**. | |
| It collects a creative prompt (plus optional reference image & visual style), | |
| then returns placeholder outputs for: | |
| • Loglines (3 variants) | |
| • Mood board (1 placeholder image + 9 themed text cells) | |
| • Shot list (6 items) | |
| • Animatic description (≈4 s) | |
| • Pitch summary | |
| • JSON download bundle | |
| Swap the stub generators with your real AI calls (OpenAI, Replicate, etc.) | |
| when you're ready. Works locally via `python app.py` or `gradio app.py`. | |
| """ | |
| from __future__ import annotations | |
| import datetime as _dt | |
| import json | |
| import uuid | |
| from pathlib import Path | |
| import os | |
| import gradio as gr | |
| from PIL import Image, ImageDraw, ImageFont | |
| # ----------------------------------------------------------------------------- | |
| # Config | |
| # ----------------------------------------------------------------------------- | |
| STYLES = [ | |
| "Default", | |
| "Cyberpunk", | |
| "Film Noir", | |
| "Watercolor", | |
| "Neo‑Deco", | |
| ] | |
| PLACEHOLDER_COLOR = (24, 24, 32) # dark bluish‑gray bg | |
| TEXT_COLOR = (220, 220, 230) | |
| TMP_DIR = Path("/tmp") | |
| # It's good practice to load secrets from environment variables. | |
| # On Hugging Face Spaces, you can set these in the repository settings. | |
| ACCESS_TOKEN = os.environ.get("HF_TOKEN") # Or whatever you named your secret | |
| # ----------------------------------------------------------------------------- | |
| # Helper functions | |
| # ----------------------------------------------------------------------------- | |
| def _make_placeholder_image(text: str = "Moodboard", size: tuple[int, int] = (512, 512)) -> Image.Image: # noqa: E501 | |
| """Generate a simple placeholder PIL image with centered text.""" | |
| img = Image.new("RGB", size, color=PLACEHOLDER_COLOR) | |
| draw = ImageDraw.Draw(img) | |
| try: | |
| font = ImageFont.truetype("arial.ttf", 32) | |
| except Exception: # font might be missing in container – fall back | |
| font = ImageFont.load_default() | |
| w, h = draw.textsize(text, font=font) | |
| draw.text(((size[0] - w) / 2, (size[1] - h) / 2), text, fill=TEXT_COLOR, font=font) | |
| return img | |
| def _timestamp() -> str: | |
| """Return an ISO‑8601 UTC timestamp (second precision).""" | |
| return _dt.datetime.utcnow().isoformat(timespec="seconds") + "Z" | |
| def read_readme(): | |
| with open("README.md", "r") as f: | |
| return f.read() | |
| # ----------------------------------------------------------------------------- | |
| # Core generator (stub – replace with your own AI calls) | |
| # ----------------------------------------------------------------------------- | |
| def generate_prototype(prompt: str, reference_image: Image.Image | None, style: str): | |
| """Return all UI outputs plus a path to the JSON bundle file.""" | |
| prompt = (prompt or "").strip() | |
| if not prompt: | |
| raise gr.Error("Please enter a creative prompt first! ☝️") | |
| # --- Loglines ------------------------------------------------------------ | |
| loglines = [ | |
| f"{prompt.capitalize()} – through the lens of {style.lower()} (take {i})." | |
| for i in range(1, 4) | |
| ] | |
| # --- Moodboard ----------------------------------------------------------- | |
| moodboard_img = _make_placeholder_image(f"{style} moodboard") | |
| moodboard_words = [f"{style} motif #{i}" for i in range(1, 10)] | |
| # --- Shot list ----------------------------------------------------------- | |
| framings = [ | |
| "Close‑up", | |
| "Medium shot", | |
| "Wide shot", | |
| "Low‑angle", | |
| "Over‑the‑shoulder", | |
| "Drone reveal", | |
| ] | |
| movements = [ | |
| "push‑in", | |
| "pull‑out", | |
| "pan‑left", | |
| "tilt‑up", | |
| "handheld", | |
| "steadycam glide", | |
| ] | |
| shot_list = [f"{framings[i]} with a {movements[i]}" for i in range(len(framings))] | |
| # --- Animatic ------------------------------------------------------------ | |
| animatic = ( | |
| "4‑second sequence: stars dissolve into silhouette; camera drifts forward, " | |
| "title flares in neon before cutting to black." | |
| ) | |
| # --- Pitch summary ------------------------------------------------------- | |
| pitch = ( | |
| f"An immersive concept blending {style.lower()} aesthetics with audience agency " | |
| f"around the theme: ‘{prompt}'." | |
| ) | |
| # --- Bundle everything into a JSON dict --------------------------------- | |
| bundle = { | |
| "prompt": prompt, | |
| "style": style, | |
| "generated_at": _timestamp(), | |
| "loglines": loglines, | |
| "moodboard": { | |
| "words": moodboard_words, | |
| "image_placeholder": "(placeholder – no image bytes)", | |
| }, | |
| "shot_list": shot_list, | |
| "animatic": animatic, | |
| "pitch_summary": pitch, | |
| } | |
| json_path = TMP_DIR / f"prototype_{uuid.uuid4().hex}.json" | |
| json_path.write_text(json.dumps(bundle, indent=2), encoding="utf-8") | |
| # Return tuple aligned with UI outputs order | |
| return ( | |
| loglines, | |
| moodboard_img, | |
| "\n".join(moodboard_words), | |
| "\n".join(shot_list), | |
| animatic, | |
| pitch, | |
| str(json_path), | |
| ) | |
| # ----------------------------------------------------------------------------- | |
| # Gradio interface definition | |
| # ----------------------------------------------------------------------------- | |
| def build_ui() -> gr.Blocks: | |
| with gr.Blocks(title="SIXR Prompt‑to‑Prototype Studio") as demo: | |
| gr.Markdown(read_readme()) | |
| if ACCESS_TOKEN: | |
| gr.Markdown("Your access token is configured!") | |
| else: | |
| gr.Markdown("Access token not found. Set it in your Space secrets.") | |
| # --------------------------- Inputs ---------------------------------- | |
| with gr.Row(): | |
| prompt_in = gr.Textbox( | |
| label="Creative prompt", | |
| placeholder="Describe your immersive idea…", | |
| lines=3, | |
| ) | |
| image_in = gr.Image( | |
| label="Reference image (optional)", | |
| type="pil", | |
| image_mode="RGB", | |
| ) | |
| style_in = gr.Dropdown(STYLES, value=STYLES[0], label="Visual style") | |
| generate_btn = gr.Button("Generate prototype", variant="primary") | |
| # --------------------------- Outputs --------------------------------- | |
| with gr.Tabs(): | |
| with gr.Tab("Loglines"): | |
| loglines_out = gr.JSON(label="Three logline variants") | |
| with gr.Tab("Moodboard"): | |
| mood_img_out = gr.Image(label="Moodboard image") | |
| mood_txt_out = gr.Textbox(label="Moodboard keywords", lines=10) | |
| with gr.Tab("Shot list"): | |
| shots_out = gr.Textbox(label="Shot list", lines=8) | |
| with gr.Tab("Animatic"): | |
| anim_out = gr.Textbox(label="Animatic description") | |
| with gr.Tab("Pitch summary"): | |
| pitch_out = gr.Textbox(label="Pitch summary") | |
| json_file_out = gr.File(label="Download JSON bundle", interactive=False) | |
| # Callback wiring | |
| generate_btn.click( | |
| fn=generate_prototype, | |
| inputs=[prompt_in, image_in, style_in], | |
| outputs=[ | |
| loglines_out, | |
| mood_img_out, | |
| mood_txt_out, | |
| shots_out, | |
| anim_out, | |
| pitch_out, | |
| json_file_out, | |
| ], | |
| ) | |
| return demo | |
| # ----------------------------------------------------------------------------- | |
| # Main entrypoint | |
| # ----------------------------------------------------------------------------- | |
| if __name__ == "__main__": | |
| ui = build_ui() | |
| # In Spaces, host/port are auto‑set; defaults work fine. | |
| ui.launch() | |