from __future__ import annotations import json from typing import Any import gradio as gr from src.bucket import read_run_bundle from src.config import settings from src.jobs import ( fetch_recent_logs_safe, inspect_job_safe, launch_create_private_space_job, launch_hello_job, launch_longcat_article_job, launch_pi_gist_recipe_job, launch_pi_model_card_job, launch_runtime_recommender_job, launch_pi_space_smoke_job, ) from src.runs import make_run_id, validate_run_id from src.security import redact APP_DESCRIPTION = f""" # Agentic Space Factory — V9 LongCat Full-Inference Gate This version validates the two critical foundations: ```text Phase 1: HF OAuth → HF Job → mounted private Bucket → run state/events/report → UI readback Phase 2: HF OAuth → HF Job → private target Space → file upload → live Gradio API validation → Bucket report Phase 3: HF OAuth → HF Job → Pi modifies app.py → private target Space → live API validation → Pi traces Phase 4: HF OAuth → HF Job → Pi reads gist → uses hf CLI → private Space → wrapper live API validation Phase 5: HF OAuth → HF Job → model-card analysis → Pi adapts template → private model Space → live API validation Phase 6: HF OAuth → HF Job → model-card/runtime analysis → runtime/hardware recommendation → Bucket report Phase 9: HF OAuth → HF Job → LongCat full-inference gate → HF Kernels/SDPA investigation → health/blocker reporting ``` Configured bucket: `{settings.bucket_uri}` """ def _profile_username(profile: Any) -> str | None: if profile is None: return None if isinstance(profile, dict): return profile.get("preferred_username") or profile.get("username") or profile.get("name") return getattr(profile, "preferred_username", None) or getattr(profile, "username", None) or getattr(profile, "name", None) def _token_value(oauth_token: Any) -> str | None: if oauth_token is None: return None if isinstance(oauth_token, str): return oauth_token return getattr(oauth_token, "token", None) or getattr(oauth_token, "access_token", None) def get_login_status(profile: gr.OAuthProfile | None) -> str: username = _profile_username(profile) if not username: return "Not signed in. Use the Hugging Face login button before launching a Job." return f"Signed in as **{username}**. Phase 2 will only create target Spaces under `{username}/...`." def propose_hello_run_id() -> str: return make_run_id("hello") def propose_space_run_id() -> str: return make_run_id("space") def propose_pi_run_id() -> str: return make_run_id("pi") def propose_gist_run_id() -> str: return make_run_id("gist") def propose_model_run_id() -> str: return make_run_id("model") def propose_runtime_run_id() -> str: return make_run_id("runtime") def propose_longcat_run_id() -> str: return make_run_id("longcat") def launch_longcat_article_job_ui( requested_run_id: str, model_id: str, target_space_name: str, pi_model: str, preferred_hardware: str, allow_fixed_gpu_fallback: bool, fallback_hardware: str, implementation_mode: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_longcat_run_id()) result = launch_longcat_article_job( token=token, username=username, target_slug=target_space_name, model_id=model_id, pi_model=pi_model, preferred_space_hardware=preferred_hardware, fallback_space_hardware=fallback_hardware, allow_fixed_gpu_fallback=allow_fixed_gpu_fallback, implementation_mode=implementation_mode, run_id=run_id, ) job_url = result.get("job_url") or "" target_space = result.get("target_space") or "" target_url = result.get("target_space_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, target_space, target_url, summary def launch_runtime_recommender_job_ui( requested_run_id: str, model_id: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_runtime_run_id()) result = launch_runtime_recommender_job( token=token, username=username, model_id=model_id, run_id=run_id, ) job_url = result.get("job_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, summary def launch_pi_model_card_job_ui( requested_run_id: str, model_id: str, target_space_name: str, pi_model: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_model_run_id()) result = launch_pi_model_card_job( token=token, username=username, target_slug=target_space_name, model_id=model_id, pi_model=pi_model, run_id=run_id, ) job_url = result.get("job_url") or "" target_space = result.get("target_space") or "" target_url = result.get("target_space_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, target_space, target_url, summary def launch_pi_gist_job_ui( requested_run_id: str, target_space_name: str, pi_model: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_gist_run_id()) result = launch_pi_gist_recipe_job( token=token, username=username, target_slug=target_space_name, pi_model=pi_model, run_id=run_id, ) job_url = result.get("job_url") or "" target_space = result.get("target_space") or "" target_url = result.get("target_space_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, target_space, target_url, summary def launch_pi_space_job_ui( requested_run_id: str, target_space_name: str, pi_model: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_pi_run_id()) result = launch_pi_space_smoke_job( token=token, username=username, target_slug=target_space_name, pi_model=pi_model, run_id=run_id, ) job_url = result.get("job_url") or "" target_space = result.get("target_space") or "" target_url = result.get("target_space_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, target_space, target_url, summary def launch_hello_job_ui( requested_run_id: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_hello_run_id()) result = launch_hello_job(token=token, username=username, run_id=run_id) job_url = result.get("job_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, summary, f"Launched hello run `{run_id}`." def launch_private_space_job_ui( requested_run_id: str, target_space_name: str, profile: gr.OAuthProfile | None, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str, str, str]: username = _profile_username(profile) token = _token_value(oauth_token) if not username or not token: raise gr.Error("Please sign in with Hugging Face first. OAuth profile/token is missing.") run_id = validate_run_id(requested_run_id or propose_space_run_id()) result = launch_create_private_space_job( token=token, username=username, target_slug=target_space_name, run_id=run_id, ) job_url = result.get("job_url") or "" target_space = result.get("target_space") or "" target_url = result.get("target_space_url") or "" summary = json.dumps(result, indent=2) return run_id, result["job_id"], job_url, target_space, target_url, summary def refresh_run_ui( run_id: str, job_id: str, oauth_token: gr.OAuthToken | None, ) -> tuple[str, str, str, str]: token = _token_value(oauth_token) if not token: raise gr.Error("Please sign in with Hugging Face first.") run_id = validate_run_id(run_id) bundle = read_run_bundle(run_id, token=token) job_info = inspect_job_safe(job_id, token=token) if job_id else {} logs = redact(fetch_recent_logs_safe(job_id, token=token)) if job_id else "" state_text = json.dumps(bundle.get("state") or {"status": "not_available_yet"}, indent=2, ensure_ascii=False) events = bundle.get("events") or [] events_text = "\n".join(json.dumps(event, ensure_ascii=False) for event in events) or "No events found yet. The Job may still be scheduling." report_text = bundle.get("report") or "No report found yet. Refresh after the Job has started writing to the bucket." job_text = json.dumps(job_info, indent=2, ensure_ascii=False) if logs: job_text += "\n\nRecent job logs:\n" + logs return state_text, events_text, report_text, job_text def build_demo() -> gr.Blocks: with gr.Blocks(title="Agentic Space Factory") as demo: gr.Markdown(APP_DESCRIPTION) gr.LoginButton() login_status = gr.Markdown() demo.load(fn=get_login_status, inputs=None, outputs=login_status) with gr.Tab("Phase 9 — LongCat full-inference gate"): gr.Markdown( """ This phase attempts a stricter LongCat reproduction: Pi must either wire the closest real inference path or return a machine-readable technical blocker report. Health-only Spaces no longer count as full-inference success. It creates a **private** target Space, asks Pi to adapt a LongCat app scaffold while following the HF Spaces gist, requests `zero-a10g` first, and optionally falls back to a fixed GPU hardware if ZeroGPU is unavailable/quota-limited. Safety: the Space remains private, publication is never automatic, hardware changes are best-effort/manual if OAuth cannot request them, and the wrapper validates HTTP `/health` first while collecting Space runtime/log diagnostics. Full video generation may still require manual review and real GPU/runtime tuning. """ ) with gr.Row(): longcat_run_id_box = gr.Textbox(label="Run ID", value=propose_longcat_run_id, interactive=True) new_longcat_run_btn = gr.Button("Generate new run id") new_longcat_run_btn.click(fn=propose_longcat_run_id, inputs=None, outputs=longcat_run_id_box) longcat_model_id_box = gr.Textbox( label="Model ID", value="meituan-longcat/LongCat-Video-Avatar-1.5", info="Default is the model from the article. You can override for controlled experiments.", ) longcat_target_space_name = gr.Textbox( label="Target Space name", placeholder="e.g. space-factory-longcat-v1", info="Use a fresh name. The Space is created under your username and remains private.", ) longcat_pi_model_box = gr.Textbox( label="Pi model", value="Qwen/Qwen3-Coder-Next", info="Model used by Pi through Hugging Face Inference Providers. Switch back to moonshotai/Kimi-K2.5 if this provider/model is unavailable.", ) longcat_impl_mode = gr.Dropdown( label="Implementation mode", choices=["full-inference-gated", "full-inference-attempt", "safe-scaffold"], value="full-inference-gated", info="full-inference-gated forbids placeholder success and requires TECHNICAL_BLOCKERS.json if real inference cannot be wired; safe-scaffold focuses on bootable health/app structure.", ) with gr.Row(): longcat_preferred_hw = gr.Dropdown( label="Preferred Space hardware", choices=["zero-a10g", "l40sx1", "a10g-large", "a100-large", "h200"], value="zero-a10g", info="The worker requests this first. Use zero-a10g to try ZeroGPU.", ) longcat_allow_fallback = gr.Checkbox( label="Allow fixed GPU fallback", value=True, info="If ZeroGPU request fails, request the fallback hardware below. This may incur billing.", ) longcat_fallback_hw = gr.Dropdown( label="Fallback Space hardware", choices=["l40sx1", "a10g-large", "a100-large", "h200", "t4-medium"], value="l40sx1", info="Used only if preferred hardware request fails and fallback is enabled.", ) launch_longcat_btn = gr.Button("Run LongCat full-inference gate", variant="primary") phase9_job_id_box = gr.Textbox(label="Job ID", interactive=True) phase9_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase9_target_space_box = gr.Textbox(label="Target Space", interactive=False) phase9_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) phase9_launch_result = gr.Code(label="Launch result", language="json") launch_longcat_btn.click( fn=launch_longcat_article_job_ui, inputs=[ longcat_run_id_box, longcat_model_id_box, longcat_target_space_name, longcat_pi_model_box, longcat_preferred_hw, longcat_allow_fallback, longcat_fallback_hw, longcat_impl_mode, ], outputs=[ longcat_run_id_box, phase9_job_id_box, phase9_job_url_box, phase9_target_space_box, phase9_target_url_box, phase9_launch_result, ], ) phase9_refresh_btn = gr.Button("Refresh Phase 9 run status") with gr.Tab("Phase 9 state"): phase9_state = gr.Code(label="state.json", language="json") with gr.Tab("Phase 9 events"): phase9_events = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 9 report"): phase9_report = gr.Markdown() with gr.Tab("Phase 9 job"): phase9_job_info = gr.Code(label="Job info/logs", language="json") phase9_refresh_btn.click( fn=refresh_run_ui, inputs=[longcat_run_id_box, phase9_job_id_box], outputs=[phase9_state, phase9_events, phase9_report, phase9_job_info], ) with gr.Tab("Phase 6 — Runtime recommender"): gr.Markdown( """ This phase does **not** create a Space. It analyzes a `model_id` and writes a runtime/hardware recommendation into the Bucket. Use it as a gate before auto-building a Space: small text models can go through Phase 5, Diffusers models become ZeroGPU candidates, and large/custom/gated models are marked for manual review. """ ) with gr.Row(): runtime_run_id_box = gr.Textbox(label="Run ID", value=propose_runtime_run_id, interactive=True) new_runtime_run_btn = gr.Button("Generate new run id") new_runtime_run_btn.click(fn=propose_runtime_run_id, inputs=None, outputs=runtime_run_id_box) runtime_model_id_box = gr.Textbox( label="Model ID", value="sshleifer/tiny-gpt2", info="Try `sshleifer/tiny-gpt2` for CPU Basic, or a Diffusers text-to-image model to see a ZeroGPU candidate recommendation.", ) launch_runtime_btn = gr.Button("Analyze runtime recommendation", variant="primary") phase6_job_id_box = gr.Textbox(label="Job ID", interactive=False) phase6_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase6_launch_result = gr.Code(label="Launch result", language="json") launch_runtime_btn.click( fn=launch_runtime_recommender_job_ui, inputs=[runtime_run_id_box, runtime_model_id_box], outputs=[runtime_run_id_box, phase6_job_id_box, phase6_job_url_box, phase6_launch_result], ) phase6_refresh_btn = gr.Button("Refresh Phase 6 run status") with gr.Tab("Phase 6 state"): phase6_state = gr.Code(label="state.json", language="json") with gr.Tab("Phase 6 events"): phase6_events = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 6 report"): phase6_report = gr.Markdown() with gr.Tab("Phase 6 job"): phase6_job_info = gr.Code(label="Job info/logs", language="json") phase6_refresh_btn.click( fn=refresh_run_ui, inputs=[runtime_run_id_box, phase6_job_id_box], outputs=[phase6_state, phase6_events, phase6_report, phase6_job_info], ) with gr.Tab("Phase 5 — Model card → private Space"): gr.Markdown( """ This phase starts from a real Hugging Face `model_id`. The Job fetches model metadata/model card, gates to a small set of simple Transformers text-pipeline tasks, prepares a Gradio template, asks Pi to adapt the app, then creates a **private** target Space and validates the live API. Recommended first test model: `sshleifer/tiny-gpt2`. This phase is intentionally limited: simple text models only, private Space only, no ZeroGPU yet, no gated-model secret injection yet. """ ) with gr.Row(): model_run_id_box = gr.Textbox(label="Run ID", value=propose_model_run_id, interactive=True) new_model_run_btn = gr.Button("Generate new run id") new_model_run_btn.click(fn=propose_model_run_id, inputs=None, outputs=model_run_id_box) model_id_box = gr.Textbox( label="Model ID", value="sshleifer/tiny-gpt2", info="Use a small public model for the first test. Phase 5 supports simple Transformers text pipeline tasks only.", ) model_target_space_name = gr.Textbox( label="Target Space name", placeholder="e.g. space-factory-model-tiny-gpt2-v1", info="Use a new name. The Space is created under your own username and is private.", ) model_pi_model_box = gr.Textbox( label="Pi model", value="moonshotai/Kimi-K2.5", info="Model used by Pi through Hugging Face Inference Providers.", ) launch_model_btn = gr.Button("Generate model Space", variant="primary") phase5_job_id_box = gr.Textbox(label="Job ID", interactive=True) phase5_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase5_target_space_box = gr.Textbox(label="Target Space", interactive=False) phase5_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) phase5_launch_result = gr.Code(label="Launch result", language="json") launch_model_btn.click( fn=launch_pi_model_card_job_ui, inputs=[model_run_id_box, model_id_box, model_target_space_name, model_pi_model_box], outputs=[ model_run_id_box, phase5_job_id_box, phase5_job_url_box, phase5_target_space_box, phase5_target_url_box, phase5_launch_result, ], ) phase5_refresh_btn = gr.Button("Refresh Phase 5 run status") with gr.Tab("Phase 5 state"): phase5_state_code = gr.Code(label="state.json", language="json") with gr.Tab("Phase 5 events"): phase5_events_code = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 5 report"): phase5_report_md = gr.Markdown() with gr.Tab("Phase 5 job"): phase5_job_code = gr.Code(label="Job status/logs", language="json") phase5_refresh_btn.click( fn=refresh_run_ui, inputs=[model_run_id_box, phase5_job_id_box], outputs=[phase5_state_code, phase5_events_code, phase5_report_md, phase5_job_code], ) with gr.Tab("Phase 4 — Pi gist recipe"): gr.Markdown( """ This phase is the first closer reproduction of the article workflow. The HF Job installs Pi, gives it the HF Spaces Agent Quickstart gist, and asks Pi to use the `hf` CLI to create/upload a **private** target Space. The wrapper still stays in control of final success: it independently checks that the target Space exists and validates the live Gradio API. Use a fresh Space name. This phase intentionally fails if the target Space already exists. """ ) with gr.Row(): gist_run_id_box = gr.Textbox(label="Run ID", value=propose_gist_run_id, interactive=True) new_gist_run_btn = gr.Button("Generate new run id") new_gist_run_btn.click(fn=propose_gist_run_id, inputs=None, outputs=gist_run_id_box) gist_target_space_name = gr.Textbox( label="Target Space name", placeholder="e.g. space-factory-pi-gist-v1", info="Use a new name. Pi is asked to create this private Space under your username using hf CLI.", ) gist_model_box = gr.Textbox( label="Pi model", value="moonshotai/Kimi-K2.5", info="Model used by Pi through Hugging Face Inference Providers.", ) launch_gist_btn = gr.Button("Run Pi gist recipe", variant="primary") phase4_job_id_box = gr.Textbox(label="Job ID", interactive=True) phase4_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase4_target_space_box = gr.Textbox(label="Target Space", interactive=False) phase4_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) phase4_launch_result = gr.Code(label="Launch result", language="json") launch_gist_btn.click( fn=launch_pi_gist_job_ui, inputs=[gist_run_id_box, gist_target_space_name, gist_model_box], outputs=[ gist_run_id_box, phase4_job_id_box, phase4_job_url_box, phase4_target_space_box, phase4_target_url_box, phase4_launch_result, ], ) phase4_refresh_btn = gr.Button("Refresh Phase 4 run status") with gr.Tab("Phase 4 state"): phase4_state_code = gr.Code(label="state.json", language="json") with gr.Tab("Phase 4 events"): phase4_events_code = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 4 report"): phase4_report_md = gr.Markdown() with gr.Tab("Phase 4 job"): phase4_job_code = gr.Code(label="Job status/logs", language="json") phase4_refresh_btn.click( fn=refresh_run_ui, inputs=[gist_run_id_box, phase4_job_id_box], outputs=[phase4_state_code, phase4_events_code, phase4_report_md, phase4_job_code], ) with gr.Tab("Phase 3 — Pi smoke test"): gr.Markdown( """ This is the first Pi integration. It launches an HF Job that installs Pi, configures it with Hugging Face Inference Providers, asks Pi to make a small safe edit to `app.py`, then creates a **private** target Space and validates the live API. This phase is intentionally narrow: Pi must only add the marker phrase `Pi modified this app` to the hello app. If Pi fails or does not make the expected edit, the Job fails safely before reporting success. """ ) with gr.Row(): pi_run_id_box = gr.Textbox(label="Run ID", value=propose_pi_run_id, interactive=True) new_pi_run_btn = gr.Button("Generate new run id") new_pi_run_btn.click(fn=propose_pi_run_id, inputs=None, outputs=pi_run_id_box) pi_target_space_name = gr.Textbox( label="Target Space name", placeholder="e.g. space-factory-pi-smoke-v1", info="Use a new name. The Space is created under your own username and is private.", ) pi_model_box = gr.Textbox( label="Pi model", value="moonshotai/Kimi-K2.5", info="Model used by Pi through Hugging Face Inference Providers. You can replace it with another provider-backed coding model.", ) launch_pi_btn = gr.Button("Run Pi smoke test", variant="primary") phase3_job_id_box = gr.Textbox(label="Job ID", interactive=True) phase3_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase3_target_space_box = gr.Textbox(label="Target Space", interactive=False) phase3_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) phase3_launch_result = gr.Code(label="Launch result", language="json") launch_pi_btn.click( fn=launch_pi_space_job_ui, inputs=[pi_run_id_box, pi_target_space_name, pi_model_box], outputs=[ pi_run_id_box, phase3_job_id_box, phase3_job_url_box, phase3_target_space_box, phase3_target_url_box, phase3_launch_result, ], ) phase3_refresh_btn = gr.Button("Refresh Phase 3 run status") with gr.Tab("Phase 3 state"): phase3_state_code = gr.Code(label="state.json", language="json") with gr.Tab("Phase 3 events"): phase3_events_code = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 3 report"): phase3_report_md = gr.Markdown() with gr.Tab("Phase 3 job"): phase3_job_code = gr.Code(label="Job status/logs", language="json") phase3_refresh_btn.click( fn=refresh_run_ui, inputs=[pi_run_id_box, phase3_job_id_box], outputs=[phase3_state_code, phase3_events_code, phase3_report_md, phase3_job_code], ) with gr.Tab("Phase 2 — Create private Space"): gr.Markdown( """ This is the next safe increment. It creates a **private** hello-world Gradio Space under your own namespace, uploads files, waits for the live API, then writes the result to the bucket. It will fail safely if the target Space already exists, to avoid overwriting user resources unexpectedly. """ ) with gr.Row(): space_run_id_box = gr.Textbox(label="Run ID", value=propose_space_run_id, interactive=True) new_space_run_btn = gr.Button("Generate new run id") new_space_run_btn.click(fn=propose_space_run_id, inputs=None, outputs=space_run_id_box) target_space_name = gr.Textbox( label="Target Space name", placeholder="e.g. space-factory-hello-test", info="Use a new name. For Phase 2, the Space is always created under your own username and is private.", ) launch_space_btn = gr.Button("Create private hello Space", variant="primary") phase2_job_id_box = gr.Textbox(label="Job ID", interactive=True) phase2_job_url_box = gr.Textbox(label="Job URL", interactive=False) phase2_target_space_box = gr.Textbox(label="Target Space", interactive=False) phase2_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) phase2_launch_result = gr.Code(label="Launch result", language="json") launch_space_btn.click( fn=launch_private_space_job_ui, inputs=[space_run_id_box, target_space_name], outputs=[ space_run_id_box, phase2_job_id_box, phase2_job_url_box, phase2_target_space_box, phase2_target_url_box, phase2_launch_result, ], ) phase2_refresh_btn = gr.Button("Refresh Phase 2 run status") with gr.Tab("Phase 2 state"): phase2_state_code = gr.Code(label="state.json", language="json") with gr.Tab("Phase 2 events"): phase2_events_code = gr.Code(label="events.jsonl", language="json") with gr.Tab("Phase 2 report"): phase2_report_md = gr.Markdown() with gr.Tab("Phase 2 job"): phase2_job_code = gr.Code(label="Job status/logs", language="json") phase2_refresh_btn.click( fn=refresh_run_ui, inputs=[space_run_id_box, phase2_job_id_box], outputs=[phase2_state_code, phase2_events_code, phase2_report_md, phase2_job_code], ) with gr.Tab("Phase 1 — Hello Job"): gr.Markdown("Keep this tab as a regression test for OAuth → Job → Bucket only.") with gr.Row(): run_id_box = gr.Textbox(label="Run ID", value=propose_hello_run_id, interactive=True) new_run_btn = gr.Button("Generate new run id") new_run_btn.click(fn=propose_hello_run_id, inputs=None, outputs=run_id_box) launch_btn = gr.Button("Launch hello HF Job", variant="secondary") job_id_box = gr.Textbox(label="Job ID", interactive=True) job_url_box = gr.Textbox(label="Job URL", interactive=False) launch_result = gr.Code(label="Launch result", language="json") status_md = gr.Markdown() launch_btn.click( fn=launch_hello_job_ui, inputs=[run_id_box], outputs=[run_id_box, job_id_box, job_url_box, launch_result, status_md], ) refresh_btn = gr.Button("Refresh hello run status") with gr.Tab("Hello state"): state_code = gr.Code(label="state.json", language="json") with gr.Tab("Hello events"): events_code = gr.Code(label="events.jsonl", language="json") with gr.Tab("Hello report"): report_md = gr.Markdown() with gr.Tab("Hello job"): job_code = gr.Code(label="Job status/logs", language="json") refresh_btn.click( fn=refresh_run_ui, inputs=[run_id_box, job_id_box], outputs=[state_code, events_code, report_md, job_code], ) gr.Markdown( """ ## Next increments After Phase 5 passes, the next step is Phase 6: 1. add a ZeroGPU Diffusers template, 2. improve model compatibility gating, 3. support richer validation by output type, 4. keep the wrapper-owned live API validation gate. """ ) return demo if __name__ == "__main__": build_demo().launch()