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