Spaces:
Running
Running
Download scripts/gen-thumbnail.py from bep40/VSEARCH: direct link, hf CLI and curl.
- Browser
- Download file 3.93 kB
-
https://huggingface.co/spaces/bep40/VSEARCH/resolve/main/scripts/gen-thumbnail.py
- Command line
-
hf download hf://spaces/bep40/VSEARCH/scripts/gen-thumbnail.py
-
curl -L -o gen-thumbnail.py https://huggingface.co/spaces/bep40/VSEARCH/resolve/main/scripts/gen-thumbnail.py
3.93 kB
| #!/usr/bin/env python3 | |
| """ | |
| Generate the social-share thumbnail for the semantic-image-field Space. | |
| Always the CURRENT 12 newest photographs: 8 newest interiors (by created_at) | |
| from bep40/vai-avatar2-interior + 4 newest added products (by _added_at) | |
| from bep40/grob-products-updated. Composed as a 4x3 grid at 1200x675 (2:1 | |
| social-card crop). Written to BOTH public/ and dist/ so whichever path the | |
| static Space serves, the resolved URL exists. | |
| Intended to run from a scheduled HF job (or locally) BEFORE the catalogue | |
| sync commits, so the committed thumbnail is refreshed at least as often as | |
| the mirror itself. | |
| """ | |
| import io, json, os, sys, urllib.request | |
| INTERIOR_INDEX = "https://huggingface.co/datasets/bep40/vai-avatar2-interior/resolve/main/index.json" | |
| INTERIOR_API = "https://bep40-vai-avatar2-interior-api.hf.space" | |
| PRODUCTS_URL = "https://huggingface.co/datasets/bep40/grob-products-updated/resolve/main/products_url_added.json" | |
| N_INTERIORS = 8 | |
| N_PRODUCTS = 4 | |
| W, H = 1200, 675 | |
| GAP = 6 | |
| COLS, ROWS = 4, 3 | |
| BG = (17, 20, 28) | |
| UA = {"User-Agent": "V.AI-STUDIO-thumbnail/1.0"} | |
| def fetch_json(url, timeout=25): | |
| req = urllib.request.Request(url, headers=UA) | |
| with urllib.request.urlopen(req, timeout=timeout) as r: | |
| return json.loads(r.read().decode("utf-8")) | |
| def fetch_bytes(url, timeout=25): | |
| req = urllib.request.Request(url, headers=UA) | |
| with urllib.request.urlopen(req, timeout=timeout) as r: | |
| return r.read() | |
| def main(): | |
| from PIL import Image | |
| interiors = fetch_json(INTERIOR_INDEX) | |
| products = fetch_json(PRODUCTS_URL) | |
| dated = [r for r in interiors | |
| if isinstance(r, dict) and isinstance(r.get("created_at"), str) | |
| and r.get("created_at") and r.get("image_id")] | |
| dated.sort(key=lambda r: r["created_at"], reverse=True) | |
| top_i = dated[:N_INTERIORS] | |
| prods = [p for p in products | |
| if isinstance(p, dict) and isinstance(p.get("_added_at"), str) | |
| and p.get("_added_at") and (p.get("imgs") or p.get("i"))] | |
| prods.sort(key=lambda p: str(p["_added_at"]), reverse=True) | |
| top_p = prods[:N_PRODUCTS] | |
| urls = [f"{INTERIOR_API}/image/{r['image_id']}.jpg" for r in top_i] | |
| urls += [(p.get("imgs") or [p.get("i")])[0] for p in top_p] | |
| cell_w = (W - GAP * (COLS - 1)) // COLS | |
| cell_h = (H - GAP * (ROWS - 1)) // ROWS | |
| canvas = Image.new("RGB", (W, H), BG) | |
| cells = [] | |
| for u in urls: | |
| try: | |
| data = fetch_bytes(u) | |
| im = Image.open(io.BytesIO(data)) | |
| if im.mode not in ("RGB", "RGBA"): | |
| im = im.convert("RGB") | |
| if im.mode == "RGBA": | |
| im = im.convert("RGB") | |
| cells.append(im) | |
| except Exception as e: | |
| print(f"skip {u[:80]}: {e}", file=sys.stderr) | |
| if not cells: | |
| print("FATAL: no images could be fetched", file=sys.stderr) | |
| sys.exit(1) | |
| idx = 0 | |
| for row in range(ROWS): | |
| for col in range(COLS): | |
| if idx >= len(cells): | |
| break | |
| im = cells[idx] | |
| idx += 1 | |
| iw, ih = im.size | |
| scale = max(cell_w / iw, cell_h / ih) | |
| sw, sh = max(1, round(iw * scale)), max(1, round(ih * scale)) | |
| im2 = im.resize((sw, sh), Image.LANCZOS) | |
| left = (sw - cell_w) // 2 | |
| top = (sh - cell_h) // 2 | |
| im2 = im2.crop((left, top, left + cell_w, top + cell_h)) | |
| canvas.paste(im2, (col * (cell_w + GAP), row * (cell_h + GAP))) | |
| out = io.BytesIO() | |
| canvas.save(out, format="PNG", optimize=True) | |
| png = out.getvalue() | |
| os.makedirs("public/share", exist_ok=True) | |
| os.makedirs("dist/share", exist_ok=True) | |
| for path in ("public/share/og-image.png", "dist/share/og-image.png"): | |
| with open(path, "wb") as f: | |
| f.write(png) | |
| print(f"OK wrote {len(png)} bytes {W}x{H} from {len(cells)} images") | |
| if __name__ == "__main__": | |
| main() | |