import spaces import gradio as gr import subprocess, os, sys, time import urllib.request, urllib.error from fastapi import Request from fastapi.responses import Response, HTMLResponse PORT = 9001 FM_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "file-manager") # --- Launch the file manager as a background child process --- proc = {"p": None} def start_fm(): if proc["p"] and proc["p"].poll() is None: proc["p"].terminate() try: proc["p"].wait(timeout=5) except Exception: proc["p"].kill() proc["p"] = subprocess.Popen([sys.executable, "app.py"], cwd=FM_DIR, stdout=sys.stdout, stderr=sys.stderr) start_fm() # --- Required ZeroGPU gate (unused, but mandatory to boot) --- @spaces.GPU def gpu_function(): return "ok" with gr.Blocks() as demo: gr.Markdown("Self-editing computer. File manager at /fm, hot-reload at /reload") demo.queue() demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False, prevent_thread_lock=True) app = demo.app # --- Hot-reload: respawn ONLY the file-manager process, no Space rebuild --- @app.get("/reload") def reload_fm(): start_fm() time.sleep(1) return HTMLResponse('Reloaded file-manager process. back to /fm') # --- Proxy: /fm/... -> 127.0.0.1:9001/fm/... (methods + body forwarded) --- @app.api_route("/fm", methods=["GET", "POST"]) @app.api_route("/fm/{path:path}", methods=["GET", "POST"]) async def proxy(request: Request, path: str = ""): url = f"http://127.0.0.1:{PORT}/fm/{path}" if request.url.query: url += "?" + request.url.query body = await request.body() fwd = {k: v for k, v in request.headers.items() if k.lower() != "host"} req = urllib.request.Request(url, data=body or None, method=request.method, headers=fwd) try: with urllib.request.urlopen(req) as r: data, status, headers = r.read(), r.status, r.headers except urllib.error.HTTPError as e: data, status, headers = e.read(), e.code, e.headers except urllib.error.URLError: return Response(content=b"file-manager not up yet on 9001", status_code=502) out = {k: v for k, v in headers.items() if k.lower() in ("set-cookie", "location", "content-type")} return Response(content=data, status_code=status, headers=out) while True: time.sleep(3600)