| 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_universal_model_card_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 |
| Phase 10: HF OAuth → HF Job → arbitrary model card → Pi/Qwen builds private Space → health/full-inference gate → Bucket traces/report |
| ``` |
| |
| 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 propose_universal_run_id() -> str: |
| return make_run_id("universal") |
|
|
|
|
| def launch_universal_model_card_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_universal_run_id()) |
| result = launch_universal_model_card_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_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 10 — Universal model-card builder"): |
| gr.Markdown( |
| """ |
| This phase generalizes the LongCat workflow: paste any Hugging Face model card URL or `owner/model` ID, and Pi will attempt to build the best possible private Gradio Space while following the HF Spaces gist. |
| |
| It uses a strict contract: if real inference is feasible, Pi should wire it. If not, it must produce `TECHNICAL_BLOCKERS.json` and the wrapper will classify the result as health-only or technical-blocker rather than pretending it is a full success. |
| |
| Hardware requests remain best-effort because OAuth/billing/ZeroGPU quota may block automatic upgrades. You can manually set hardware while the Job is waiting. |
| """ |
| ) |
| with gr.Row(): |
| universal_run_id_box = gr.Textbox(label="Run ID", value=propose_universal_run_id, interactive=True) |
| new_universal_run_btn = gr.Button("Generate new run id") |
| new_universal_run_btn.click(fn=propose_universal_run_id, inputs=None, outputs=universal_run_id_box) |
|
|
| universal_model_id_box = gr.Textbox( |
| label="Model card URL or model ID", |
| value="sshleifer/tiny-gpt2", |
| info="Examples: sshleifer/tiny-gpt2, runwayml/stable-diffusion-v1-5, or https://huggingface.co/owner/model", |
| ) |
| universal_target_space_name = gr.Textbox( |
| label="Target Space name", |
| placeholder="e.g. space-factory-custom-model-v1", |
| info="Use a fresh name. The Space is created under your username and remains private.", |
| ) |
| universal_pi_model_box = gr.Textbox( |
| label="Pi model", |
| value="Qwen/Qwen3-Coder-Next", |
| info="Model used by Pi through Hugging Face Inference Providers.", |
| ) |
| universal_impl_mode = gr.Dropdown( |
| label="Implementation mode", |
| choices=["full-inference-gated", "full-inference-attempt", "safe-scaffold"], |
| value="full-inference-gated", |
| info="Gated mode forbids placeholder success; impossible models must produce TECHNICAL_BLOCKERS.json.", |
| ) |
| with gr.Row(): |
| universal_preferred_hw = gr.Dropdown( |
| label="Preferred Space hardware", |
| choices=["cpu-basic", "zero-a10g", "t4-small", "t4-medium", "a10g-large", "l40sx1", "a100-large", "h200"], |
| value="cpu-basic", |
| info="Best-effort request. Use CPU for small models; choose GPU if you expect heavy inference and can set it manually if OAuth cannot.", |
| ) |
| universal_allow_fallback = gr.Checkbox(label="Allow fixed GPU fallback", value=False) |
| universal_fallback_hw = gr.Dropdown( |
| label="Fallback Space hardware", |
| choices=["l40sx1", "a10g-large", "a100-large", "h200", "t4-medium"], |
| value="l40sx1", |
| ) |
|
|
| launch_universal_btn = gr.Button("Build private Space from model card", variant="primary") |
| phase10_job_id_box = gr.Textbox(label="Job ID", interactive=True) |
| phase10_job_url_box = gr.Textbox(label="Job URL", interactive=False) |
| phase10_target_space_box = gr.Textbox(label="Target Space", interactive=False) |
| phase10_target_url_box = gr.Textbox(label="Target Space URL", interactive=False) |
| phase10_launch_result = gr.Code(label="Launch result", language="json") |
|
|
| launch_universal_btn.click( |
| fn=launch_universal_model_card_job_ui, |
| inputs=[ |
| universal_run_id_box, |
| universal_model_id_box, |
| universal_target_space_name, |
| universal_pi_model_box, |
| universal_preferred_hw, |
| universal_allow_fallback, |
| universal_fallback_hw, |
| universal_impl_mode, |
| ], |
| outputs=[ |
| universal_run_id_box, |
| phase10_job_id_box, |
| phase10_job_url_box, |
| phase10_target_space_box, |
| phase10_target_url_box, |
| phase10_launch_result, |
| ], |
| ) |
|
|
| phase10_refresh_btn = gr.Button("Refresh Phase 10 run status") |
| with gr.Tab("Phase 10 state"): |
| phase10_state = gr.Code(label="state.json", language="json") |
| with gr.Tab("Phase 10 events"): |
| phase10_events = gr.Code(label="events.jsonl", language="json") |
| with gr.Tab("Phase 10 report"): |
| phase10_report = gr.Markdown() |
| with gr.Tab("Phase 10 job"): |
| phase10_job_info = gr.Code(label="Job info/logs", language="json") |
|
|
| phase10_refresh_btn.click( |
| fn=refresh_run_ui, |
| inputs=[universal_run_id_box, phase10_job_id_box], |
| outputs=[phase10_state, phase10_events, phase10_report, phase10_job_info], |
| ) |
|
|
| 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() |
|
|