| from fastapi import BackgroundTasks, FastAPI, HTTPException, Depends, Request, Form |
| from fastapi.responses import HTMLResponse, RedirectResponse |
| from fastapi.staticfiles import StaticFiles |
| from fastapi.templating import Jinja2Templates |
| from fastapi.middleware.gzip import GZipMiddleware |
| import uuid |
| from app.models import DeployRequest, DeployStatus |
| from app.store import TaskStore |
| from app.deploy import deploy_space, SpaceDeployError |
| from app.auth import require_api_key |
|
|
| app = FastAPI(title="HF Space Deployer", version="1.0.0") |
|
|
| |
| app.mount("/static", StaticFiles(directory="app/static"), name="static") |
| app.add_middleware(GZipMiddleware) |
| templates = Jinja2Templates(directory="app/templates") |
|
|
|
|
| |
| @app.get("/", response_class=HTMLResponse) |
| async def index(request: Request): |
| return templates.TemplateResponse("index.html", {"request": request}) |
|
|
|
|
| @app.post("/web/deploy") |
| async def web_deploy( |
| request: Request, |
| hf_token: str = Form(...), |
| git_repo_url: str = Form(...), |
| space_name: str = Form(...), |
| description: str = Form(""), |
| space_port: int = Form(7860), |
| private: bool = Form(False), |
| env_vars_text: str = Form(""), |
| deploy_path: str = Form("/"), |
| bg: BackgroundTasks = BackgroundTasks() |
| ): |
| |
| env_vars = {} |
| if env_vars_text.strip(): |
| for line in env_vars_text.strip().split('\n'): |
| if '=' in line: |
| key, value = line.split('=', 1) |
| env_vars[key.strip()] = value.strip() |
|
|
| deploy_req = DeployRequest( |
| hf_token=hf_token, |
| git_repo_url=git_repo_url, |
| space_name=space_name, |
| description=description, |
| space_port=space_port, |
| private=private, |
| env_vars=env_vars, |
| deploy_path=deploy_path |
| ) |
|
|
| task_id = str(uuid.uuid4()) |
| TaskStore.save(DeployStatus(task_id=task_id, status="PENDING")) |
| bg.add_task(_run_task, task_id, deploy_req) |
|
|
| |
| return RedirectResponse(url=f"/deploy/{task_id}", status_code=303) |
|
|
|
|
| @app.get("/deploy/{task_id}", response_class=HTMLResponse) |
| async def deploy_status_page(request: Request, task_id: str): |
| status = TaskStore.load(task_id) |
| if not status: |
| raise HTTPException(status_code=404, detail="Task not found") |
|
|
| return templates.TemplateResponse("deploy_status.html", { |
| "request": request, |
| "task_id": task_id, |
| "status": status.status |
| }) |
|
|
|
|
| |
| @app.post("/deploy", response_model=DeployStatus, status_code=202) |
| async def deploy(req: DeployRequest, bg: BackgroundTasks): |
| task_id = str(uuid.uuid4()) |
| TaskStore.save(DeployStatus(task_id=task_id, status="PENDING")) |
| bg.add_task(_run_task, task_id, req) |
| return TaskStore.load(task_id) |
|
|
|
|
| @app.get("/deploy/status/{task_id}", response_model=DeployStatus) |
| async def status(task_id: str): |
| status = TaskStore.load(task_id) |
| if not status: |
| raise HTTPException(status_code=404, detail="Task not found") |
| return status |
|
|
|
|
| |
|
|
| def _run_task(task_id: str, req: DeployRequest): |
| TaskStore.save(DeployStatus(task_id=task_id, status="IN_PROGRESS")) |
| try: |
| url = deploy_space(**req.dict()) |
| TaskStore.save(DeployStatus(task_id=task_id, status="SUCCESS", detail={"space_url": url})) |
| except SpaceDeployError as exc: |
| TaskStore.save(DeployStatus(task_id=task_id, status="FAILED", detail={"error": str(exc)})) |
|
|