Download core/describe.py from FineEnvs/DesignGym: direct link, hf CLI and curl.
- Browser
- Download file 4.59 kB
-
https://huggingface.co/spaces/FineEnvs/DesignGym/resolve/main/core/describe.py
- Command line
-
hf download hf://spaces/FineEnvs/DesignGym/core/describe.py
-
curl -L -o describe.py https://huggingface.co/spaces/FineEnvs/DesignGym/resolve/main/core/describe.py
4.59 kB
| """Task 2's prompt: the design described in words instead of shown as an image. | |
| The description is generated from the ground-truth document, so it is exactly | |
| as informative as intended and never hallucinates: every asset and every word | |
| of copy is named, colours and fonts are given, and placement is coarse, in the | |
| vocabulary a designer would use in a brief ("top left", "centred", "large"). | |
| The model has to turn that into coordinates, which is the skill the task tests. | |
| """ | |
| from __future__ import annotations | |
| from .colors import color_name | |
| from .doc import DesignDoc, Element | |
| def _where(el: Element, doc: DesignDoc) -> str: | |
| x0, y0 = max(0.0, el.x), max(0.0, el.y) | |
| x1, y1 = min(doc.width, el.x + el.width), min(doc.height, el.y + el.height) | |
| if x1 <= x0 or y1 <= y0: | |
| return "mostly off the canvas" | |
| cover_w = (x1 - x0) / doc.width | |
| cover_h = (y1 - y0) / doc.height | |
| if cover_w > 0.9 and cover_h > 0.9: | |
| return "covering the whole canvas" | |
| cx = (x0 + x1) / 2 / doc.width | |
| cy = (y0 + y1) / 2 / doc.height | |
| col = "left" if cx < 0.36 else "right" if cx > 0.64 else "center" | |
| row = "top" if cy < 0.36 else "bottom" if cy > 0.64 else "middle" | |
| if cover_w > 0.9: | |
| return {"top": "across the top", "middle": "across the middle", | |
| "bottom": "across the bottom"}[row] | |
| if cover_h > 0.9: | |
| return {"left": "down the left side", "center": "down the middle", | |
| "right": "down the right side"}[col] | |
| if row == "middle" and col == "center": | |
| return "in the center" | |
| if col == "center": | |
| return f"at the {row} center" | |
| if row == "middle": | |
| return f"at the middle {col}" | |
| return f"at the {row} {col}" | |
| def _size(el: Element, doc: DesignDoc) -> str: | |
| frac = (el.width * el.height) / (doc.width * doc.height) | |
| if frac > 0.6: | |
| return "full-bleed" | |
| if frac > 0.25: | |
| return "large" | |
| if frac > 0.07: | |
| return "medium" | |
| if frac > 0.015: | |
| return "small" | |
| return "tiny" | |
| def _text_size(el: Element, doc: DesignDoc) -> str: | |
| rel = el.font_size / doc.height | |
| if rel > 0.12: | |
| return "huge" | |
| if rel > 0.06: | |
| return "large" | |
| if rel > 0.03: | |
| return "medium" | |
| return "small" | |
| def describe(doc: DesignDoc, meta: dict, asset_meta: dict[str, dict]) -> str: | |
| fmt = meta.get("format") or "design" | |
| title = meta.get("title") or "" | |
| head = f"A {fmt} design, {doc.width}x{doc.height}px" | |
| if title: | |
| head += f', titled "{title}"' | |
| lines = [head + "."] | |
| lines.append( | |
| f"Background colour: {color_name(doc.background)} ({doc.background})." | |
| ) | |
| lines.append("Layers from back to front:") | |
| for n, el in enumerate(doc.elements, 1): | |
| where = _where(el, doc) | |
| if el.kind == "image": | |
| kind = asset_meta.get(el.asset_id, {}).get("kind", "image") | |
| noun = {"photo": "photo", "graphic": "graphic", "background": "background texture"}.get( | |
| kind, "image" | |
| ) | |
| desc = f"{n}. A {_size(el, doc)} {noun} (asset {el.asset_id}) {where}" | |
| elif el.kind == "shape": | |
| desc = f"{n}. A {el.shape} in {color_name(el.fill or '#000000')} {where}" | |
| else: | |
| text = el.display_text().replace("\n", " / ") | |
| style = [] | |
| if el.bold: | |
| style.append("bold") | |
| if el.italic: | |
| style.append("italic") | |
| color = el.color or "#000000" | |
| desc = ( | |
| f'{n}. Text "{text}" in {" ".join(style + [el.font_family or ""]).strip()}, ' | |
| f"{_text_size(el, doc)} ({el.font_size:.0f}px), {color_name(color)} ({color}), " | |
| f"{el.align}-aligned, {where}" | |
| ) | |
| if el.letter_spacing and abs(el.letter_spacing) >= 0.5: | |
| desc += f", letter-spacing {el.letter_spacing:.0f}px" | |
| if len(el.lines) > 1: | |
| desc += f", {len(el.lines)} lines" | |
| if el.runs: | |
| colors = sorted({color_name(r.color) for r in el.styled_runs() if r.text.strip()}) | |
| if len(colors) > 1: | |
| desc += f" (mixed colours: {', '.join(colors)})" | |
| if el.angle: | |
| desc += f", rotated {el.angle:.0f} degrees" | |
| if el.opacity < 0.95: | |
| desc += f", {round(el.opacity * 100)}% opacity" | |
| lines.append(desc + ".") | |
| keywords = [k for k in (meta.get("keywords") or [])][:8] | |
| if keywords: | |
| lines.append(f"Mood / keywords: {', '.join(keywords)}.") | |
| return "\n".join(lines) | |