""" HF Playground — code-driven model playground. Enter any HuggingFace model ID in a code template and run. """ import spaces # MUST be first — signals ZeroGPU infrastructure import sys import asyncio import gradio as gr from api import build_fastapi_app from ui import build_app, theme, CSS # ZeroGPU startup probe. The runtime scans Gradio's *registered event handlers* # for a @spaces.GPU-marked function and refuses to start if none is found, so this # probe is wired to demo.load() below. The real work (run_custom_code) stays # undecorated so it runs in-process — models are CPU-bound and the sandbox needs # threads + queues that would break inside a forked ZeroGPU worker. @spaces.GPU(duration=10) def _gpu_probe(): return None # Python 3.10 asyncio cleanup fix: suppress "Invalid file descriptor: -1" on shutdown if sys.version_info >= (3, 10) and sys.platform == 'linux': try: _cls = asyncio.selector_events.BaseSelectorEventLoop _orig = _cls._close_self_pipe def _safe_close_self_pipe(self): try: _orig(self) except ValueError: pass _cls._close_self_pipe = _safe_close_self_pipe except Exception: pass with gr.Blocks(title="HF Model Playground") as demo: build_app() demo.load(fn=_gpu_probe, trigger_mode="once") # ZeroGPU client registration happens on the first Blocks.launch() call # (spaces.zero wraps gr.Blocks.launch to send the startup report to the device # API). Launch once on a throwaway port to trigger that registration, then # immediately close it. The real server starts below via uvicorn on 7860 and # serves both the Gradio UI and the OpenAI-compatible /v1 routes. demo.launch(prevent_thread_lock=True, server_name=None, server_port=8000, quiet=True) demo.close() fastapi_app = build_fastapi_app() app = gr.mount_gradio_app(fastapi_app, demo, path="/", theme=theme, css=CSS) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=7860)