| | 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)})) |
| |
|