rainey commited on
Commit
c898b9e
·
verified ·
1 Parent(s): 3e29b8b

Deploy from GitHub Actions

Browse files
Files changed (3) hide show
  1. README.md +26 -5
  2. app.py +127 -0
  3. requirements.txt +15 -0
README.md CHANGED
@@ -1,13 +1,34 @@
1
  ---
2
  title: Cryptid Cannon
3
- emoji: 💻
4
- colorFrom: indigo
5
  colorTo: indigo
6
  sdk: gradio
7
- sdk_version: 6.18.0
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  title: Cryptid Cannon
3
+ emoji: 🔮
4
+ colorFrom: purple
5
  colorTo: indigo
6
  sdk: gradio
7
+ sdk_version: 5.49.1
 
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
+ suggested_hardware: zero-a10g
12
+ short_description: Fire the cannon, summon a random absurd cryptid on klein 4B
13
+ tags:
14
+ - build-small-hackathon
15
+ - thousand-token-wood
16
+ - tiny-titan
17
+ - flux
18
+ - text-to-image
19
  ---
20
 
21
+ # 🔮 Cryptid Cannon
22
+
23
+ A deliberately silly [Build Small](https://huggingface.co/build-small-hackathon)
24
+ toy. Press the button, summon a random absurd cryptid — a marshmallow golem mid-
25
+ sneeze, a Victorian frog detective drinking tea — rendered by **FLUX.2 [klein]
26
+ 4B** (4 billion parameters, Apache 2.0, ~1s per image on the Space GPU).
27
+
28
+ Leave the box empty for pure chaos, or whisper your own creature.
29
+
30
+ This is a quick smoke-test of the deploy pipeline — not a serious competition
31
+ entry. Built on the [klein starter](https://huggingface.co/spaces/stephenbtl/klein-build-small-starter).
32
+
33
+ **Model:** [`FLUX.2-klein-4B`](https://huggingface.co/black-forest-labs/FLUX.2-klein-4B)
34
+ · well under the hackathon's 32B cap (and under 4B-badge territory).
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🔮 Cryptid Cannon — fire the cannon, summon a random absurd cryptid.
3
+
4
+ A deliberately silly FLUX.2 [klein] 4B toy for the Build Small hackathon.
5
+ One button, one chaotic creature. Built on the klein starter's verified
6
+ ZeroGPU + pipeline pattern.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import random
11
+ import time
12
+
13
+ # --- ZeroGPU shim: import `spaces` BEFORE torch -----------------------------
14
+ try:
15
+ import spaces # type: ignore
16
+
17
+ GPU = spaces.GPU
18
+ except Exception: # local / non-ZeroGPU fallback
19
+
20
+ def GPU(*dargs, **dkwargs): # noqa: N802
21
+ if len(dargs) == 1 and callable(dargs[0]) and not dkwargs:
22
+ return dargs[0]
23
+
24
+ def wrap(fn):
25
+ return fn
26
+
27
+ return wrap
28
+
29
+
30
+ import gradio as gr
31
+ import torch
32
+ from diffusers import Flux2KleinPipeline
33
+
34
+ MODEL_ID = "black-forest-labs/FLUX.2-klein-4B" # 4B, Apache 2.0, ungated
35
+ STEPS = 4
36
+ GUIDANCE = 1.0
37
+ MAX_SEED = 2**31 - 1
38
+
39
+ # Build on CPU at module scope (ZeroGPU pattern), but guard the load so the UI
40
+ # still boots on tiny hardware instead of showing a blank runtime error.
41
+ pipe = None
42
+ LOAD_ERR = ""
43
+ try:
44
+ print(f"Loading {MODEL_ID} on CPU…")
45
+ pipe = Flux2KleinPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
46
+ print(" loaded.")
47
+ except Exception as e: # noqa: BLE001
48
+ LOAD_ERR = str(e)
49
+ print("Model load failed:", e)
50
+
51
+ CREATURES = [
52
+ "mushroom knight", "cloud cat", "disgruntled potato wizard", "sock goblin",
53
+ "philosophical jellyfish", "tiny bureaucrat dragon", "moss yeti",
54
+ "origami werewolf", "caffeinated snail", "Victorian frog detective",
55
+ "marshmallow golem", "interdimensional library owl",
56
+ ]
57
+ TRAITS = [
58
+ "wearing a tiny hat", "made of stained glass", "on a unicycle",
59
+ "knitting a scarf", "looking very smug", "mid-sneeze", "holding a lantern",
60
+ "deeply confused", "in formal attire", "glowing faintly", "drinking tea",
61
+ ]
62
+ STYLES = [
63
+ "children's storybook illustration, soft watercolor",
64
+ "claymation still, studio lighting",
65
+ "bold flat vector sticker art",
66
+ "cozy painted scene, warm light",
67
+ "1970s fantasy paperback cover",
68
+ "cute isometric 3D render",
69
+ ]
70
+
71
+
72
+ def _roll(twist: str) -> str:
73
+ if twist and twist.strip():
74
+ subject = twist.strip()
75
+ else:
76
+ subject = f"{random.choice(CREATURES)} {random.choice(TRAITS)}"
77
+ return f"A {subject}, {random.choice(STYLES)}, centered, whimsical, no text"
78
+
79
+
80
+ @GPU(duration=60)
81
+ def summon(twist: str):
82
+ if pipe is None:
83
+ raise gr.Error(f"Model isn't loaded (this Space needs a GPU). {LOAD_ERR[:200]}")
84
+ prompt = _roll(twist)
85
+ pipe.to("cuda")
86
+ seed = random.randint(0, MAX_SEED)
87
+ t = time.time()
88
+ img = pipe(
89
+ prompt=prompt,
90
+ width=1024,
91
+ height=1024,
92
+ num_inference_steps=STEPS,
93
+ guidance_scale=GUIDANCE,
94
+ generator=torch.Generator(device="cuda").manual_seed(seed),
95
+ ).images[0]
96
+ return img, f"🔮 {prompt}\n· seed {seed} · {time.time() - t:.1f}s"
97
+
98
+
99
+ with gr.Blocks(title="Cryptid Cannon", theme=gr.themes.Soft()) as demo:
100
+ gr.Markdown(
101
+ "# 🔮 Cryptid Cannon\n"
102
+ "Fire the cannon and summon a random absurd cryptid — powered by "
103
+ "**FLUX.2 [klein] 4B** (4B params, Apache 2.0, runs locally on the Space "
104
+ "GPU). Leave the box empty for pure chaos, or whisper your own creature."
105
+ )
106
+ with gr.Row():
107
+ with gr.Column():
108
+ twist = gr.Textbox(
109
+ label="Your creature (optional)",
110
+ placeholder="a grumpy mushroom knight",
111
+ lines=1,
112
+ )
113
+ btn = gr.Button("🔮 Fire the cannon", variant="primary")
114
+ gr.Examples(
115
+ ["", "a sleepy cloud cat", "a tiny bureaucrat dragon", "a philosophical jellyfish"],
116
+ twist,
117
+ label="Try one",
118
+ )
119
+ with gr.Column():
120
+ out = gr.Image(label="Your cryptid", height=480)
121
+ info = gr.Textbox(label="What you summoned", lines=3)
122
+ btn.click(summon, twist, [out, info])
123
+
124
+ if __name__ == "__main__":
125
+ demo.queue(max_size=8).launch(
126
+ server_name="0.0.0.0", server_port=7860, show_error=True
127
+ )
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # FLUX.2 [klein] needs a diffusers build that has Flux2KleinPipeline.
2
+ # As of writing that's diffusers main, not a tagged release.
3
+ git+https://github.com/huggingface/diffusers.git
4
+ torch
5
+ transformers
6
+ accelerate
7
+ # peft is the backend diffusers uses for load_lora_weights() — without it the
8
+ # LoRA tab raises "PEFT backend is required for this method."
9
+ peft
10
+ safetensors
11
+ sentencepiece
12
+ protobuf
13
+ pillow
14
+ # Provides @spaces.GPU on ZeroGPU hardware. Harmless elsewhere.
15
+ spaces