Download app.py from tailot/universal-upscale: direct link, hf CLI and curl.
- Browser
- Download file 3.94 kB
-
https://huggingface.co/tailot/universal-upscale/resolve/main/app.py
- Command line
-
hf download hf://tailot/universal-upscale/app.py
-
curl -L -o app.py https://huggingface.co/tailot/universal-upscale/resolve/main/app.py
3.94 kB
| """Gradio Space demo for the Universal Upscale model.""" | |
| from pathlib import Path | |
| import gradio_client.utils as gutils | |
| # Monkey-patch gradio_client schema parser to handle boolean additionalProperties in Gradio 5. | |
| _orig_json_schema = gutils._json_schema_to_python_type | |
| def _safe_json_schema_to_python_type(schema, defs=None): | |
| if isinstance(schema, bool): | |
| return "Any" if schema else "Never" | |
| return _orig_json_schema(schema, defs) | |
| gutils._json_schema_to_python_type = _safe_json_schema_to_python_type | |
| import gradio as gr | |
| import numpy as np | |
| import torch | |
| from PIL import Image | |
| try: | |
| import spaces | |
| gpu_decorator = spaces.GPU | |
| except ImportError: | |
| def gpu_decorator(fn): | |
| return fn | |
| MODEL_PATH = Path(__file__).resolve().parent / "model_scripted.pt" | |
| def load_model(device: str): | |
| model = torch.jit.load(str(MODEL_PATH), map_location=device) | |
| model.eval() | |
| return model | |
| MAX_SIDE = 4096 | |
| # Largest scale factor verified end-to-end for the published checkpoint. The slider is capped | |
| # here; "Target Long Side" still accepts any size up to MAX_SIDE. | |
| MAX_SCALE = 9.2 | |
| def resolve_factor(input_size, scale, target_long_side): | |
| """Scale factor to apply: an explicit target size wins, scale requests stay under MAX_SCALE.""" | |
| target = float(target_long_side) if target_long_side is not None else 0.0 | |
| if target > 0: | |
| return target / float(max(input_size)), "" | |
| factor = float(scale if scale is not None else 4.0) | |
| if factor > MAX_SCALE: | |
| return MAX_SCALE, f" (clamped to the tested maximum {MAX_SCALE:g}x)" | |
| return factor, "" | |
| def upscale(image, scale: float = 4.0, target_long_side: float = 0.0): | |
| if image is None: | |
| return None, "No image provided." | |
| img = image if isinstance(image, Image.Image) else Image.open(image) | |
| img = img.convert("RGB") | |
| factor, clamped = resolve_factor(img.size, scale, target_long_side) | |
| out_w, out_h = max(1, int(round(img.width * factor))), max(1, int(round(img.height * factor))) | |
| if max(out_w, out_h) > MAX_SIDE: | |
| shrink = MAX_SIDE / float(max(out_w, out_h)) | |
| out_w, out_h = max(1, int(out_w * shrink)), max(1, int(out_h * shrink)) | |
| device = "cuda" if torch.cuda.is_available() else "cpu" | |
| model = load_model(device) | |
| lr = torch.from_numpy(np.asarray(img, dtype=np.float32) / 255.0).permute(2, 0, 1).contiguous().unsqueeze(0).to(device) | |
| with torch.no_grad(): | |
| out = model(lr, out_h, out_w) | |
| arr = (out.squeeze(0).permute(1, 2, 0).cpu().numpy() * 255.0).round().astype(np.uint8) | |
| res_img = Image.fromarray(arr) | |
| status = f"Input: {img.width}x{img.height} | Output: {res_img.width}x{res_img.height} (Scale: {factor:.2f}x) | Device: {device}{clamped}" | |
| return res_img, status | |
| example_files = [ | |
| [str(Path(__file__).resolve().parent / name)] | |
| for name in ("examples/input.png", "examples/demo_input.png") | |
| if (Path(__file__).resolve().parent / name).exists() | |
| ] | |
| demo = gr.Interface( | |
| fn=upscale, | |
| inputs=[ | |
| gr.Image(type="pil", label="Input Image"), | |
| gr.Slider(minimum=1.0, maximum=9.2, value=4.0, step=0.2, label="Scale Factor"), | |
| gr.Number(value=0, label="Or Target Long Side (px) [0 = use scale factor]"), | |
| ], | |
| outputs=[ | |
| gr.Image(type="pil", label="Upscaled Image"), | |
| gr.Textbox(label="Status / Image Info"), | |
| ], | |
| title="Universal Upscale", | |
| description=( | |
| "Arbitrary-scale super-resolution: upscale images to any scale factor from 1x up to the tested maximum " | |
| "9.2x, or to an exact target resolution. Built-in tiled inference enables high-resolution " | |
| "upscaling without memory issues (outputs are capped at 4096 px on the long side)." | |
| ), | |
| examples=example_files if example_files else None, | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |