Spaces:
Running on Zero
Running on Zero
Generate assets directly from text prompts
Browse filesRemove procedural image guides from the production diffusion path. Generate sprites and backgrounds directly from written prompts, keep fail-closed neural enforcement, and make realistic style parsing negation-aware.
app.py
CHANGED
|
@@ -126,8 +126,6 @@ PRIMARY_LORA_MODEL = os.environ.get("PRIMARY_LORA_MODEL", "latent-consistency/lc
|
|
| 126 |
PRIMARY_IMAGE_STEPS = int(os.environ.get("PRIMARY_IMAGE_STEPS", "4"))
|
| 127 |
PRIMARY_SPRITE_STEPS = int(os.environ.get("PRIMARY_SPRITE_STEPS", "6"))
|
| 128 |
PRIMARY_GUIDANCE_SCALE = float(os.environ.get("PRIMARY_GUIDANCE_SCALE", "1.5"))
|
| 129 |
-
PRIMARY_BACKGROUND_STRENGTH = float(os.environ.get("PRIMARY_BACKGROUND_STRENGTH", "0.72"))
|
| 130 |
-
PRIMARY_SPRITE_STRENGTH = float(os.environ.get("PRIMARY_SPRITE_STRENGTH", "0.82"))
|
| 131 |
USE_PRIMARY_IMAGE_MODEL = os.environ.get("USE_PRIMARY_IMAGE_MODEL", "1") == "1"
|
| 132 |
REQUIRE_PRIMARY_IMAGE_MODEL = os.environ.get(
|
| 133 |
"REQUIRE_PRIMARY_IMAGE_MODEL",
|
|
@@ -154,7 +152,6 @@ FREE_DIFFUSION_ERROR = None
|
|
| 154 |
CONTROLNET_PIPE = None
|
| 155 |
CONTROLNET_ERROR = None
|
| 156 |
PRIMARY_TEXT_PIPE = None
|
| 157 |
-
PRIMARY_IMAGE_TO_IMAGE_PIPE = None
|
| 158 |
PRIMARY_MODEL_ERROR = None
|
| 159 |
|
| 160 |
|
|
@@ -225,7 +222,18 @@ def interpret_style_hint(style_hint: str) -> StylePlan:
|
|
| 225 |
tags: list[str] = []
|
| 226 |
|
| 227 |
def has(*words: str) -> bool:
|
| 228 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
|
| 230 |
if has("watercolor", "ink wash", "gouache", "paper"):
|
| 231 |
tags.append("watercolor")
|
|
@@ -255,6 +263,13 @@ def interpret_style_hint(style_hint: str) -> StylePlan:
|
|
| 255 |
texture = "visible bristle strokes and canvas-like texture"
|
| 256 |
lighting = "dramatic directional light"
|
| 257 |
linework = "painted edges instead of hard outlines"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
elif has("pixel", "8-bit", "16-bit", "retro"):
|
| 259 |
tags.append("pixel")
|
| 260 |
medium = "retro pixel-art game asset"
|
|
@@ -1374,9 +1389,7 @@ def draw_sprite(spec: AssetSpec, rng: random.Random) -> bytes:
|
|
| 1374 |
return out.getvalue()
|
| 1375 |
|
| 1376 |
if spec.camera == "side_view":
|
| 1377 |
-
# Profile silhouette
|
| 1378 |
-
# neural img2img camera guide. A single visible eye and forward nose
|
| 1379 |
-
# prevent the model from reverting to its common front-facing pose.
|
| 1380 |
draw.ellipse((cx - 28 * scale, cy + 31 * scale, cx + 31 * scale, cy + 46 * scale), fill=(0, 0, 0, 55))
|
| 1381 |
draw.rounded_rectangle(
|
| 1382 |
(cx - 15 * scale, cy - 16 * scale, cx + 17 * scale, cy + 32 * scale),
|
|
@@ -1544,7 +1557,7 @@ def diffusion_negative_prompt(spec: AssetSpec) -> str:
|
|
| 1544 |
)
|
| 1545 |
return (
|
| 1546 |
common
|
| 1547 |
-
+ ", landscape, environment scene, room, horizon,
|
| 1548 |
"trees, foliage, ground, floor, scenery, background objects, frame, border"
|
| 1549 |
)
|
| 1550 |
|
|
@@ -1602,8 +1615,8 @@ def build_camera_control_image(spec: AssetSpec, width: int = 1024, height: int =
|
|
| 1602 |
|
| 1603 |
|
| 1604 |
def initialize_primary_image_model() -> None:
|
| 1605 |
-
"""Load the production
|
| 1606 |
-
global PRIMARY_TEXT_PIPE,
|
| 1607 |
if not USE_PRIMARY_IMAGE_MODEL or PRIMARY_TEXT_PIPE is not None or PRIMARY_MODEL_ERROR:
|
| 1608 |
return
|
| 1609 |
if not os.environ.get("SPACE_ID"):
|
|
@@ -1611,7 +1624,7 @@ def initialize_primary_image_model() -> None:
|
|
| 1611 |
|
| 1612 |
try:
|
| 1613 |
import torch
|
| 1614 |
-
from diffusers import
|
| 1615 |
|
| 1616 |
model_kwargs = {
|
| 1617 |
"torch_dtype": torch.float16,
|
|
@@ -1631,13 +1644,7 @@ def initialize_primary_image_model() -> None:
|
|
| 1631 |
if hasattr(text_pipe, "enable_vae_slicing"):
|
| 1632 |
text_pipe.enable_vae_slicing()
|
| 1633 |
|
| 1634 |
-
image_pipe = AutoPipelineForImage2Image.from_pipe(text_pipe)
|
| 1635 |
-
image_pipe.scheduler = LCMScheduler.from_config(image_pipe.scheduler.config)
|
| 1636 |
-
if hasattr(image_pipe, "set_progress_bar_config"):
|
| 1637 |
-
image_pipe.set_progress_bar_config(disable=True)
|
| 1638 |
-
|
| 1639 |
PRIMARY_TEXT_PIPE = text_pipe
|
| 1640 |
-
PRIMARY_IMAGE_TO_IMAGE_PIPE = image_pipe
|
| 1641 |
except Exception as exc:
|
| 1642 |
PRIMARY_MODEL_ERROR = short_error(exc)
|
| 1643 |
|
|
@@ -1645,33 +1652,21 @@ def initialize_primary_image_model() -> None:
|
|
| 1645 |
def primary_diffusion_prompt(spec: AssetSpec) -> str:
|
| 1646 |
if is_background_spec(spec):
|
| 1647 |
return (
|
| 1648 |
-
f"{spec.prompt}
|
| 1649 |
-
"
|
| 1650 |
-
"No characters and no decorative overlay."
|
| 1651 |
)
|
| 1652 |
return (
|
| 1653 |
f"{spec.prompt} One complete isolated game sprite only, centered, fully visible, readable silhouette, "
|
| 1654 |
-
"
|
|
|
|
| 1655 |
"Add recognizable costume, equipment, materials, and character details. "
|
| 1656 |
"No scenery, floor, trees, foliage, frame, or environmental props."
|
| 1657 |
)
|
| 1658 |
|
| 1659 |
|
| 1660 |
-
def primary_image_guide(spec: AssetSpec, index: int, run_id: int) -> Image.Image:
|
| 1661 |
-
"""Build a clean camera-and-palette guide for the neural image-to-image pass."""
|
| 1662 |
-
guide_png = local_asset_png(spec, index, run_id)
|
| 1663 |
-
guide = Image.open(io.BytesIO(guide_png)).convert("RGBA")
|
| 1664 |
-
if is_background_spec(spec):
|
| 1665 |
-
return guide.convert("RGB").resize((1344, 768), Image.LANCZOS)
|
| 1666 |
-
|
| 1667 |
-
guide = guide.resize((1024, 1024), Image.LANCZOS)
|
| 1668 |
-
white = Image.new("RGB", guide.size, (255, 255, 255))
|
| 1669 |
-
white.paste(guide.convert("RGB"), mask=guide.getchannel("A"))
|
| 1670 |
-
return white
|
| 1671 |
-
|
| 1672 |
-
|
| 1673 |
def primary_diffusion_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None, str | None]:
|
| 1674 |
-
"""Generate every production asset
|
| 1675 |
if PRIMARY_MODEL_ERROR:
|
| 1676 |
return None, PRIMARY_MODEL_ERROR
|
| 1677 |
if PRIMARY_TEXT_PIPE is None:
|
|
@@ -1691,13 +1686,10 @@ def primary_diffusion_png(spec: AssetSpec, index: int, run_id: int) -> tuple[byt
|
|
| 1691 |
"guidance_scale": PRIMARY_GUIDANCE_SCALE,
|
| 1692 |
"generator": generator,
|
| 1693 |
}
|
| 1694 |
-
if
|
| 1695 |
-
|
| 1696 |
-
|
| 1697 |
-
|
| 1698 |
-
image = PRIMARY_IMAGE_TO_IMAGE_PIPE(
|
| 1699 |
-
image=guide,
|
| 1700 |
-
strength=strength,
|
| 1701 |
**common,
|
| 1702 |
).images[0]
|
| 1703 |
return polish_diffusion_asset(image, spec), None
|
|
@@ -2115,7 +2107,7 @@ def model_source_note(image_model: str) -> str:
|
|
| 2115 |
if "via fal-ai" in lowered or "via replicate" in lowered:
|
| 2116 |
return "routed image-to-image refinement—preserves a layout guide but consumes account inference credit"
|
| 2117 |
if "zerogpu" in lowered:
|
| 2118 |
-
return "locally hosted
|
| 2119 |
return "diffusion output—higher visual variety; verify subject, perspective, alpha edges, and prompt compliance"
|
| 2120 |
|
| 2121 |
|
|
@@ -2124,16 +2116,17 @@ def model_configuration_summary() -> str:
|
|
| 2124 |
sprite_chain = []
|
| 2125 |
primary_source = f"{PRIMARY_IMAGE_MODEL} + {PRIMARY_LORA_MODEL} on ZeroGPU"
|
| 2126 |
if USE_PRIMARY_IMAGE_MODEL:
|
| 2127 |
-
sprite_chain.append(f"
|
| 2128 |
if USE_DIFFUSION_FOR_SPRITES:
|
| 2129 |
sprite_chain.append(FREE_IMAGE_MODEL)
|
| 2130 |
if USE_HF_IMAGE_PROVIDER:
|
| 2131 |
sprite_chain.append(HF_IMAGE_MODEL)
|
| 2132 |
-
|
|
|
|
| 2133 |
sprite_source = " → ".join(sprite_chain)
|
| 2134 |
background_chain = []
|
| 2135 |
if USE_PRIMARY_IMAGE_MODEL:
|
| 2136 |
-
background_chain.append(f"
|
| 2137 |
if USE_CONTROLNET_FOR_BACKGROUNDS:
|
| 2138 |
background_chain.append(f"{CONTROLNET_BASE_MODEL} + {CONTROLNET_MODEL}")
|
| 2139 |
if USE_HF_STRUCTURE_PROVIDER:
|
|
@@ -2142,7 +2135,8 @@ def model_configuration_summary() -> str:
|
|
| 2142 |
background_chain.append(FREE_IMAGE_MODEL)
|
| 2143 |
if USE_HF_IMAGE_PROVIDER:
|
| 2144 |
background_chain.append(HF_IMAGE_MODEL)
|
| 2145 |
-
|
|
|
|
| 2146 |
background_source = " → ".join(background_chain)
|
| 2147 |
remote_sources = []
|
| 2148 |
if USE_HF_STRUCTURE_PROVIDER:
|
|
@@ -2171,9 +2165,9 @@ def model_configuration_summary() -> str:
|
|
| 2171 |
f"prompts: `{prompt_source}` · sprites: `{sprite_source}` · backgrounds: `{background_source}` · "
|
| 2172 |
f"remote image fallback: `{remote_fallback}` · neural image models: `{neural_status}` · "
|
| 2173 |
f"neural enforcement: `{enforcement}` · primary readiness: `{readiness}`. "
|
| 2174 |
-
"Every production image is generated by the primary
|
| 2175 |
-
"
|
| 2176 |
-
"
|
| 2177 |
)
|
| 2178 |
|
| 2179 |
|
|
|
|
| 126 |
PRIMARY_IMAGE_STEPS = int(os.environ.get("PRIMARY_IMAGE_STEPS", "4"))
|
| 127 |
PRIMARY_SPRITE_STEPS = int(os.environ.get("PRIMARY_SPRITE_STEPS", "6"))
|
| 128 |
PRIMARY_GUIDANCE_SCALE = float(os.environ.get("PRIMARY_GUIDANCE_SCALE", "1.5"))
|
|
|
|
|
|
|
| 129 |
USE_PRIMARY_IMAGE_MODEL = os.environ.get("USE_PRIMARY_IMAGE_MODEL", "1") == "1"
|
| 130 |
REQUIRE_PRIMARY_IMAGE_MODEL = os.environ.get(
|
| 131 |
"REQUIRE_PRIMARY_IMAGE_MODEL",
|
|
|
|
| 152 |
CONTROLNET_PIPE = None
|
| 153 |
CONTROLNET_ERROR = None
|
| 154 |
PRIMARY_TEXT_PIPE = None
|
|
|
|
| 155 |
PRIMARY_MODEL_ERROR = None
|
| 156 |
|
| 157 |
|
|
|
|
| 222 |
tags: list[str] = []
|
| 223 |
|
| 224 |
def has(*words: str) -> bool:
|
| 225 |
+
negation = re.compile(
|
| 226 |
+
r"(?:\bno\b|\bnot\b|\bwithout\b|\bavoid(?:ing)?\b|"
|
| 227 |
+
r"\bexclude(?:d|ing)?\b|\brather\s+than\b|\bnon[- ]?)\s+"
|
| 228 |
+
r"(?:[\w-]+\s+){0,3}$"
|
| 229 |
+
)
|
| 230 |
+
for word in words:
|
| 231 |
+
pattern = re.compile(rf"(?<![\w-]){re.escape(word)}(?![\w-])")
|
| 232 |
+
for match in pattern.finditer(text):
|
| 233 |
+
prefix = text[max(0, match.start() - 48) : match.start()]
|
| 234 |
+
if not negation.search(prefix):
|
| 235 |
+
return True
|
| 236 |
+
return False
|
| 237 |
|
| 238 |
if has("watercolor", "ink wash", "gouache", "paper"):
|
| 239 |
tags.append("watercolor")
|
|
|
|
| 263 |
texture = "visible bristle strokes and canvas-like texture"
|
| 264 |
lighting = "dramatic directional light"
|
| 265 |
linework = "painted edges instead of hard outlines"
|
| 266 |
+
elif has("photorealistic", "photo-realistic", "realistic", "cinematic realism", "lifelike"):
|
| 267 |
+
tags.append("realistic")
|
| 268 |
+
medium = "realistic game concept art"
|
| 269 |
+
palette = "natural material colors with controlled cinematic contrast"
|
| 270 |
+
texture = "physically plausible fabric, skin, metal, and surface detail"
|
| 271 |
+
lighting = "cinematic directional light with realistic shadows"
|
| 272 |
+
linework = "natural painted edges without graphic outlines"
|
| 273 |
elif has("pixel", "8-bit", "16-bit", "retro"):
|
| 274 |
tags.append("pixel")
|
| 275 |
medium = "retro pixel-art game asset"
|
|
|
|
| 1389 |
return out.getvalue()
|
| 1390 |
|
| 1391 |
if spec.camera == "side_view":
|
| 1392 |
+
# Profile silhouette for the optional local procedural fallback.
|
|
|
|
|
|
|
| 1393 |
draw.ellipse((cx - 28 * scale, cy + 31 * scale, cx + 31 * scale, cy + 46 * scale), fill=(0, 0, 0, 55))
|
| 1394 |
draw.rounded_rectangle(
|
| 1395 |
(cx - 15 * scale, cy - 16 * scale, cx + 17 * scale, cy + 32 * scale),
|
|
|
|
| 1557 |
)
|
| 1558 |
return (
|
| 1559 |
common
|
| 1560 |
+
+ ", landscape, environment scene, room, horizon, complex background, drop shadow, "
|
| 1561 |
"trees, foliage, ground, floor, scenery, background objects, frame, border"
|
| 1562 |
)
|
| 1563 |
|
|
|
|
| 1615 |
|
| 1616 |
|
| 1617 |
def initialize_primary_image_model() -> None:
|
| 1618 |
+
"""Load the production text-to-image pipeline once under ZeroGPU CUDA emulation."""
|
| 1619 |
+
global PRIMARY_TEXT_PIPE, PRIMARY_MODEL_ERROR
|
| 1620 |
if not USE_PRIMARY_IMAGE_MODEL or PRIMARY_TEXT_PIPE is not None or PRIMARY_MODEL_ERROR:
|
| 1621 |
return
|
| 1622 |
if not os.environ.get("SPACE_ID"):
|
|
|
|
| 1624 |
|
| 1625 |
try:
|
| 1626 |
import torch
|
| 1627 |
+
from diffusers import AutoPipelineForText2Image, LCMScheduler
|
| 1628 |
|
| 1629 |
model_kwargs = {
|
| 1630 |
"torch_dtype": torch.float16,
|
|
|
|
| 1644 |
if hasattr(text_pipe, "enable_vae_slicing"):
|
| 1645 |
text_pipe.enable_vae_slicing()
|
| 1646 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1647 |
PRIMARY_TEXT_PIPE = text_pipe
|
|
|
|
| 1648 |
except Exception as exc:
|
| 1649 |
PRIMARY_MODEL_ERROR = short_error(exc)
|
| 1650 |
|
|
|
|
| 1652 |
def primary_diffusion_prompt(spec: AssetSpec) -> str:
|
| 1653 |
if is_background_spec(spec):
|
| 1654 |
return (
|
| 1655 |
+
f"{spec.prompt} Generate this scene directly from the written description as a production-quality "
|
| 1656 |
+
"2D game background. Follow the stated camera projection exactly and keep gameplay space readable. "
|
| 1657 |
+
"Use connected environmental forms and clean terrain structure. No characters and no decorative overlay."
|
| 1658 |
)
|
| 1659 |
return (
|
| 1660 |
f"{spec.prompt} One complete isolated game sprite only, centered, fully visible, readable silhouette, "
|
| 1661 |
+
"with its anatomy, body shape, camera angle, and pose derived directly from the written description. "
|
| 1662 |
+
"Use a plain uniform white studio background for clean extraction. "
|
| 1663 |
"Add recognizable costume, equipment, materials, and character details. "
|
| 1664 |
"No scenery, floor, trees, foliage, frame, or environmental props."
|
| 1665 |
)
|
| 1666 |
|
| 1667 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1668 |
def primary_diffusion_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None, str | None]:
|
| 1669 |
+
"""Generate every production asset directly from text with the primary model."""
|
| 1670 |
if PRIMARY_MODEL_ERROR:
|
| 1671 |
return None, PRIMARY_MODEL_ERROR
|
| 1672 |
if PRIMARY_TEXT_PIPE is None:
|
|
|
|
| 1686 |
"guidance_scale": PRIMARY_GUIDANCE_SCALE,
|
| 1687 |
"generator": generator,
|
| 1688 |
}
|
| 1689 |
+
width, height = (1344, 768) if is_background_spec(spec) else (1024, 1024)
|
| 1690 |
+
image = PRIMARY_TEXT_PIPE(
|
| 1691 |
+
width=width,
|
| 1692 |
+
height=height,
|
|
|
|
|
|
|
|
|
|
| 1693 |
**common,
|
| 1694 |
).images[0]
|
| 1695 |
return polish_diffusion_asset(image, spec), None
|
|
|
|
| 2107 |
if "via fal-ai" in lowered or "via replicate" in lowered:
|
| 2108 |
return "routed image-to-image refinement—preserves a layout guide but consumes account inference credit"
|
| 2109 |
if "zerogpu" in lowered:
|
| 2110 |
+
return "direct locally hosted text-to-image diffusion—no procedural guide or per-image API credit; visual review required"
|
| 2111 |
return "diffusion output—higher visual variety; verify subject, perspective, alpha edges, and prompt compliance"
|
| 2112 |
|
| 2113 |
|
|
|
|
| 2116 |
sprite_chain = []
|
| 2117 |
primary_source = f"{PRIMARY_IMAGE_MODEL} + {PRIMARY_LORA_MODEL} on ZeroGPU"
|
| 2118 |
if USE_PRIMARY_IMAGE_MODEL:
|
| 2119 |
+
sprite_chain.append(f"direct text-to-image {primary_source}")
|
| 2120 |
if USE_DIFFUSION_FOR_SPRITES:
|
| 2121 |
sprite_chain.append(FREE_IMAGE_MODEL)
|
| 2122 |
if USE_HF_IMAGE_PROVIDER:
|
| 2123 |
sprite_chain.append(HF_IMAGE_MODEL)
|
| 2124 |
+
if not (USE_PRIMARY_IMAGE_MODEL and REQUIRE_PRIMARY_IMAGE_MODEL):
|
| 2125 |
+
sprite_chain.append("shape-aware procedural renderer (development fallback only)")
|
| 2126 |
sprite_source = " → ".join(sprite_chain)
|
| 2127 |
background_chain = []
|
| 2128 |
if USE_PRIMARY_IMAGE_MODEL:
|
| 2129 |
+
background_chain.append(f"direct text-to-image {primary_source}")
|
| 2130 |
if USE_CONTROLNET_FOR_BACKGROUNDS:
|
| 2131 |
background_chain.append(f"{CONTROLNET_BASE_MODEL} + {CONTROLNET_MODEL}")
|
| 2132 |
if USE_HF_STRUCTURE_PROVIDER:
|
|
|
|
| 2135 |
background_chain.append(FREE_IMAGE_MODEL)
|
| 2136 |
if USE_HF_IMAGE_PROVIDER:
|
| 2137 |
background_chain.append(HF_IMAGE_MODEL)
|
| 2138 |
+
if not (USE_PRIMARY_IMAGE_MODEL and REQUIRE_PRIMARY_IMAGE_MODEL):
|
| 2139 |
+
background_chain.append("camera-safe procedural renderer (development fallback only)")
|
| 2140 |
background_source = " → ".join(background_chain)
|
| 2141 |
remote_sources = []
|
| 2142 |
if USE_HF_STRUCTURE_PROVIDER:
|
|
|
|
| 2165 |
f"prompts: `{prompt_source}` · sprites: `{sprite_source}` · backgrounds: `{background_source}` · "
|
| 2166 |
f"remote image fallback: `{remote_fallback}` · neural image models: `{neural_status}` · "
|
| 2167 |
f"neural enforcement: `{enforcement}` · primary readiness: `{readiness}`. "
|
| 2168 |
+
"Every production image is generated directly from its written prompt by the primary text-to-image model. "
|
| 2169 |
+
"No procedural guide is supplied to the model. The procedural renderer is development-only and is blocked in "
|
| 2170 |
+
"the deployed Space when the primary model fails."
|
| 2171 |
)
|
| 2172 |
|
| 2173 |
|