LeafCat79 commited on
Commit
9998a8b
·
verified ·
1 Parent(s): b9bc5e1

Use free local Diffusers image model

Browse files
Files changed (1) hide show
  1. app.py +89 -5
app.py CHANGED
@@ -103,9 +103,15 @@ class StylePlan:
103
 
104
 
105
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
 
 
 
 
106
  HF_IMAGE_MODEL = os.environ.get("HF_IMAGE_MODEL", "black-forest-labs/FLUX.1-schnell")
107
  HF_PROMPT_MODEL = os.environ.get("HF_PROMPT_MODEL", "Qwen/Qwen2.5-Coder-7B-Instruct:fastest")
108
  HF_PROMPT_ENDPOINT = os.environ.get("HF_PROMPT_ENDPOINT", "https://router.huggingface.co/v1/chat/completions")
 
 
109
 
110
 
111
  def slugify(value: str) -> str:
@@ -263,6 +269,8 @@ def short_error(exc: Exception) -> str:
263
 
264
 
265
  def hf_prompt_json(html_code: str, role_lines: list[tuple[str, str]], style_hint: str) -> tuple[dict[str, str] | None, str | None]:
 
 
266
  if not HF_TOKEN:
267
  return None, "HF_TOKEN is not visible to the Space runtime"
268
 
@@ -978,7 +986,78 @@ def placeholder_png_bytes(role: str, width: int, height: int) -> bytes:
978
  return out.getvalue()
979
 
980
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
981
  def hf_image_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None, str | None]:
 
 
982
  if not HF_TOKEN:
983
  return None, "HF_TOKEN is not visible to the Space runtime"
984
  if InferenceClient is None:
@@ -1003,15 +1082,20 @@ def hf_image_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None
1003
 
1004
 
1005
  def generate_asset(spec: AssetSpec, index: int, run_id: int) -> tuple[str, str, str | None, str]:
1006
- png_content, hf_error = hf_image_png(spec, index, run_id)
1007
- source = HF_IMAGE_MODEL
 
 
 
 
 
1008
  if png_content is None:
1009
  png_content = local_asset_png(spec, index, run_id)
1010
- source = "local style fallback"
1011
  return (
1012
  png_bytes_to_data_uri(png_content),
1013
  write_gallery_image(png_content, spec.role),
1014
- hf_error if source == "local style fallback" else None,
1015
  source,
1016
  )
1017
 
@@ -1191,7 +1275,7 @@ def generate_images_and_game(html_code: str, roles: str, style_hint: str):
1191
  gallery.append((gallery_path, f"{spec.role} -> {spec.filename}"))
1192
  model_rows.append((spec.role, prompt_model, image_model))
1193
  if error:
1194
- errors.append(f"{spec.role}: image model failed ({error}); used local style fallback")
1195
 
1196
  rewritten = embed_assets(html_code, assets, specs)
1197
  status = (
 
103
 
104
 
105
  HF_TOKEN = os.environ.get("HF_TOKEN", "")
106
+ FREE_IMAGE_MODEL = os.environ.get("FREE_IMAGE_MODEL", "segmind/tiny-sd")
107
+ FREE_IMAGE_STEPS = int(os.environ.get("FREE_IMAGE_STEPS", "5"))
108
+ USE_HF_PROMPT_PROVIDER = os.environ.get("USE_HF_PROMPT_PROVIDER", "0") == "1"
109
+ USE_HF_IMAGE_PROVIDER = os.environ.get("USE_HF_IMAGE_PROVIDER", "0") == "1"
110
  HF_IMAGE_MODEL = os.environ.get("HF_IMAGE_MODEL", "black-forest-labs/FLUX.1-schnell")
111
  HF_PROMPT_MODEL = os.environ.get("HF_PROMPT_MODEL", "Qwen/Qwen2.5-Coder-7B-Instruct:fastest")
112
  HF_PROMPT_ENDPOINT = os.environ.get("HF_PROMPT_ENDPOINT", "https://router.huggingface.co/v1/chat/completions")
113
+ FREE_DIFFUSION_PIPE = None
114
+ FREE_DIFFUSION_ERROR = None
115
 
116
 
117
  def slugify(value: str) -> str:
 
269
 
270
 
271
  def hf_prompt_json(html_code: str, role_lines: list[tuple[str, str]], style_hint: str) -> tuple[dict[str, str] | None, str | None]:
272
+ if not USE_HF_PROMPT_PROVIDER:
273
+ return None, None
274
  if not HF_TOKEN:
275
  return None, "HF_TOKEN is not visible to the Space runtime"
276
 
 
986
  return out.getvalue()
987
 
988
 
989
+ def diffusion_dimensions(spec: AssetSpec) -> tuple[int, int]:
990
+ if is_background_spec(spec):
991
+ return 384, 216
992
+ return 256, 256
993
+
994
+
995
+ def polish_diffusion_asset(image: Image.Image, spec: AssetSpec) -> bytes:
996
+ image = image.convert("RGBA")
997
+ if not is_background_spec(spec):
998
+ # Text-to-image models do not produce real transparency. This makes sprites
999
+ # usable by fading out colors similar to the generated corner background.
1000
+ small = image.resize((128, 128), Image.LANCZOS)
1001
+ corners = [
1002
+ small.getpixel((0, 0)),
1003
+ small.getpixel((127, 0)),
1004
+ small.getpixel((0, 127)),
1005
+ small.getpixel((127, 127)),
1006
+ ]
1007
+ bg = tuple(sum(pixel[i] for pixel in corners) // len(corners) for i in range(3))
1008
+ pixels = small.load()
1009
+ for y in range(small.height):
1010
+ for x in range(small.width):
1011
+ r, g, b, a = pixels[x, y]
1012
+ dist = abs(r - bg[0]) + abs(g - bg[1]) + abs(b - bg[2])
1013
+ edge = min(x, y, small.width - 1 - x, small.height - 1 - y)
1014
+ if dist < 64 or edge < 3:
1015
+ a = 0
1016
+ elif dist < 125:
1017
+ a = max(0, min(a, (dist - 64) * 4))
1018
+ pixels[x, y] = (r, g, b, a)
1019
+ image = small.resize((spec.width, spec.height), Image.LANCZOS)
1020
+ else:
1021
+ image = image.resize((spec.width, spec.height), Image.LANCZOS)
1022
+ out = io.BytesIO()
1023
+ image.save(out, format="PNG")
1024
+ return out.getvalue()
1025
+
1026
+
1027
+ def free_diffusion_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None, str | None]:
1028
+ global FREE_DIFFUSION_PIPE, FREE_DIFFUSION_ERROR
1029
+ if FREE_DIFFUSION_ERROR:
1030
+ return None, FREE_DIFFUSION_ERROR
1031
+ try:
1032
+ import torch
1033
+ from diffusers import DiffusionPipeline
1034
+
1035
+ if FREE_DIFFUSION_PIPE is None:
1036
+ FREE_DIFFUSION_PIPE = DiffusionPipeline.from_pretrained(FREE_IMAGE_MODEL)
1037
+ FREE_DIFFUSION_PIPE = FREE_DIFFUSION_PIPE.to("cpu")
1038
+ if hasattr(FREE_DIFFUSION_PIPE, "enable_attention_slicing"):
1039
+ FREE_DIFFUSION_PIPE.enable_attention_slicing()
1040
+
1041
+ width, height = diffusion_dimensions(spec)
1042
+ seed = abs(hash(f"{spec.role}|{spec.prompt}|{index}|{run_id}")) % 2147483647
1043
+ generator = torch.Generator(device="cpu").manual_seed(seed)
1044
+ image = FREE_DIFFUSION_PIPE(
1045
+ spec.prompt,
1046
+ width=width,
1047
+ height=height,
1048
+ num_inference_steps=FREE_IMAGE_STEPS,
1049
+ guidance_scale=6.0,
1050
+ generator=generator,
1051
+ ).images[0]
1052
+ return polish_diffusion_asset(image, spec), None
1053
+ except Exception as exc:
1054
+ FREE_DIFFUSION_ERROR = short_error(exc)
1055
+ return None, FREE_DIFFUSION_ERROR
1056
+
1057
+
1058
  def hf_image_png(spec: AssetSpec, index: int, run_id: int) -> tuple[bytes | None, str | None]:
1059
+ if not USE_HF_IMAGE_PROVIDER:
1060
+ return None, None
1061
  if not HF_TOKEN:
1062
  return None, "HF_TOKEN is not visible to the Space runtime"
1063
  if InferenceClient is None:
 
1082
 
1083
 
1084
  def generate_asset(spec: AssetSpec, index: int, run_id: int) -> tuple[str, str, str | None, str]:
1085
+ png_content, free_error = free_diffusion_png(spec, index, run_id)
1086
+ source = FREE_IMAGE_MODEL
1087
+ error = free_error
1088
+ if png_content is None:
1089
+ png_content, hf_error = hf_image_png(spec, index, run_id)
1090
+ source = HF_IMAGE_MODEL
1091
+ error = hf_error or free_error
1092
  if png_content is None:
1093
  png_content = local_asset_png(spec, index, run_id)
1094
+ source = "local procedural fallback"
1095
  return (
1096
  png_bytes_to_data_uri(png_content),
1097
  write_gallery_image(png_content, spec.role),
1098
+ error if source == "local procedural fallback" else None,
1099
  source,
1100
  )
1101
 
 
1275
  gallery.append((gallery_path, f"{spec.role} -> {spec.filename}"))
1276
  model_rows.append((spec.role, prompt_model, image_model))
1277
  if error:
1278
+ errors.append(f"{spec.role}: image model failed ({error}); used local procedural fallback")
1279
 
1280
  rewritten = embed_assets(html_code, assets, specs)
1281
  status = (