Magnus Persson
Two-column Create layout with fixed slots, clearer labels, and a How it works pipeline tab
4fc023c Download src/ui/components.py from magnusp/image-lab: direct link, hf CLI and curl.
- Browser
- Download file 2.29 kB
-
https://huggingface.co/spaces/magnusp/image-lab/resolve/main/src/ui/components.py
- Command line
-
hf download hf://spaces/magnusp/image-lab/src/ui/components.py
-
curl -L -o components.py https://huggingface.co/spaces/magnusp/image-lab/resolve/main/src/ui/components.py
2.29 kB
| """Helpers that keep every visible string in the locale files and switchable at runtime.""" | |
| from __future__ import annotations | |
| import io | |
| from collections.abc import Callable, Iterable | |
| from typing import Any, Literal | |
| import gradio as gr | |
| from PIL import Image | |
| from src.i18n import I18n | |
| Block = gr.blocks.Block | |
| Updates = dict[Block, dict[str, Any]] | |
| Props = Callable[[str], dict[str, Any]] | |
| ApiVisibility = Literal["private", "undocumented"] | |
| class Localizer: | |
| """Creates components from locale-driven props and re-renders them for another language.""" | |
| def __init__(self, i18n: I18n) -> None: | |
| self.i18n = i18n | |
| self.default_language = i18n.default_language | |
| self._bindings: list[tuple[Block, Props]] = [] | |
| def t(self, lang: str, key: str, **values: object) -> str: | |
| return self.i18n.t(lang, key, **values) | |
| def make(self, cls: type[Block], props: Props, **static: Any) -> Any: | |
| """Build `cls` with props for the default language and remember how to re-localize it.""" | |
| component = cls(**props(self.default_language), **static) | |
| self._bindings.append((component, props)) | |
| return component | |
| def components(self) -> list[Block]: | |
| return [component for component, _ in self._bindings] | |
| def props(self, lang: str) -> Updates: | |
| return {component: props(lang) for component, props in self._bindings} | |
| def build_heading(loc: Localizer, title_key: str, hint_key: str) -> Any: | |
| """A bold section title with a one-line explanation under it.""" | |
| return loc.make( | |
| gr.Markdown, | |
| lambda lang: {"value": f"**{loc.t(lang, title_key)}** \n{loc.t(lang, hint_key)}"}, | |
| elem_classes=["section-heading"], | |
| ) | |
| def merge(*parts: Updates) -> Updates: | |
| merged: Updates = {} | |
| for part in parts: | |
| for component, props in part.items(): | |
| merged[component] = {**merged.get(component, {}), **props} | |
| return merged | |
| def pack(order: Iterable[Block], updates: Updates) -> list[Any]: | |
| """Turn updates into an output list aligned with `order`; untouched components get no-ops.""" | |
| return [gr.update(**updates[c]) if c in updates else gr.skip() for c in order] | |
| def to_pil(image: bytes) -> Image.Image: | |
| return Image.open(io.BytesIO(image)) | |