Spaces:
Running on Zero
Running on Zero
feat(ui): labeled_label and model_selector_html helpers
Browse files- tests/test_ui.py +45 -0
- ui.py +55 -0
tests/test_ui.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pytest
|
| 2 |
+
|
| 3 |
+
import ui
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def test_labeled_label_returns_html_string():
|
| 7 |
+
out = ui.labeled_label("Steps", "Denoising steps.")
|
| 8 |
+
assert isinstance(out, str)
|
| 9 |
+
assert "<label" in out and "</label>" in out
|
| 10 |
+
assert ">Steps<" in out
|
| 11 |
+
assert 'data-info="Denoising steps."' in out
|
| 12 |
+
assert ">i<" in out # the icon glyph
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def test_labeled_label_escapes_html_chars():
|
| 16 |
+
out = ui.labeled_label("Steps <x>", 'A "quoted" hint')
|
| 17 |
+
assert "<x>" not in out
|
| 18 |
+
assert "<x>" in out
|
| 19 |
+
assert ""quoted"" in out
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def test_model_selector_html_marks_current_as_on():
|
| 23 |
+
out = ui.model_selector_html(current="Turbo")
|
| 24 |
+
assert 'class="zis-model on" data-value="Turbo"' in out
|
| 25 |
+
assert 'class="zis-model" data-value="Base"' in out
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_model_selector_html_includes_both_soon_cards_with_github_link():
|
| 29 |
+
out = ui.model_selector_html(current="Turbo")
|
| 30 |
+
assert out.count("github.com/Tongyi-MAI/Z-Image#model-zoo") == 2
|
| 31 |
+
assert "Edit" in out
|
| 32 |
+
assert "Omni Base" in out
|
| 33 |
+
assert "soon-tag" in out
|
| 34 |
+
assert 'target="_blank"' in out
|
| 35 |
+
assert 'rel="noopener noreferrer"' in out
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def test_model_selector_html_defaults_to_turbo():
|
| 39 |
+
out = ui.model_selector_html()
|
| 40 |
+
assert 'class="zis-model on" data-value="Turbo"' in out
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def test_model_selector_html_escapes_current_value():
|
| 44 |
+
out = ui.model_selector_html(current='<script>alert(1)</script>')
|
| 45 |
+
assert "<script>" not in out
|
ui.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Gradio UI builders + small HTML helpers for the (i) tooltip pattern and the custom model selector."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
from html import escape
|
| 5 |
+
|
| 6 |
+
GITHUB_MODEL_ZOO_URL = "https://github.com/Tongyi-MAI/Z-Image#model-zoo"
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def labeled_label(text: str, info_text: str) -> str:
|
| 10 |
+
"""Return HTML for a label with an (i) tooltip icon next to it.
|
| 11 |
+
|
| 12 |
+
Use immediately before a ``gr.Slider`` / ``gr.Textbox`` / ``gr.File`` etc.
|
| 13 |
+
that itself has ``show_label=False``. The CSS for ``.zis-row-label`` and
|
| 14 |
+
``.zis-info`` is defined in :mod:`theme`.
|
| 15 |
+
"""
|
| 16 |
+
return (
|
| 17 |
+
f'<label class="zis-row-label">{escape(text)}'
|
| 18 |
+
f'<span class="zis-info" data-info="{escape(info_text)}">i</span>'
|
| 19 |
+
f'</label>'
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def model_selector_html(current: str = "Turbo") -> str:
|
| 24 |
+
"""Custom T2I model selector — 2-col phone / 4-col tablet+ grid of cards.
|
| 25 |
+
|
| 26 |
+
Two functional ``<button>`` cards (Base, Turbo) — clicks fire
|
| 27 |
+
``zis.setModel('<name>')`` defined in app.py's ``head=`` script.
|
| 28 |
+
|
| 29 |
+
Two coming-soon ``<a>`` cards (Edit, Omni Base) — open the Z-Image GitHub
|
| 30 |
+
README's Model Zoo section in a new tab. Marked with a `.soon` class and a
|
| 31 |
+
"soon" pill that doesn't overlap the model name (separate flex children).
|
| 32 |
+
"""
|
| 33 |
+
current_safe = escape(current)
|
| 34 |
+
cards: list[str] = []
|
| 35 |
+
for name in ("Base", "Turbo"):
|
| 36 |
+
cls = "zis-model on" if name == current else "zis-model"
|
| 37 |
+
cards.append(
|
| 38 |
+
f'<button type="button" class="{cls}" data-value="{name}" '
|
| 39 |
+
f'onclick="zis.setModel(\'{name}\')">'
|
| 40 |
+
f'<span class="dot"></span>'
|
| 41 |
+
f'<span class="name">{name}</span>'
|
| 42 |
+
f'</button>'
|
| 43 |
+
)
|
| 44 |
+
for name in ("Edit", "Omni Base"):
|
| 45 |
+
cards.append(
|
| 46 |
+
f'<a class="zis-model soon" '
|
| 47 |
+
f'href="{GITHUB_MODEL_ZOO_URL}" '
|
| 48 |
+
f'target="_blank" rel="noopener noreferrer">'
|
| 49 |
+
f'<span class="dot"></span>'
|
| 50 |
+
f'<span class="name">{name}<span class="ext">↗</span></span>'
|
| 51 |
+
f'<span class="soon-tag">soon</span>'
|
| 52 |
+
f'</a>'
|
| 53 |
+
)
|
| 54 |
+
_ = current_safe # current is matched in cls above; this line keeps escape() exercised
|
| 55 |
+
return f'<div class="zis-models">{"".join(cards)}</div>'
|