75 lines
2.0 KiB
Python
75 lines
2.0 KiB
Python
"""
|
|
FastAPI 入口。启动:
|
|
|
|
python -m uvicorn server.main:app --host 0.0.0.0 --port 8000
|
|
|
|
或在 python/ 目录下:
|
|
|
|
uvicorn server.main:app --host 0.0.0.0 --port 8000
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from fastapi import FastAPI, File, Form, HTTPException, UploadFile
|
|
from fastapi.responses import FileResponse, JSONResponse, Response
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from .face_renderer import (
|
|
EffectNotFoundError,
|
|
FaceRenderer,
|
|
NoFaceError,
|
|
RendererPaths,
|
|
)
|
|
|
|
# 路径相对本文件,避免 cwd 不同时找不到资源
|
|
_SERVER_DIR = Path(__file__).resolve().parent
|
|
_PATHS = RendererPaths(
|
|
obj_path=_SERVER_DIR / "assets" / "face_picture_3dmax.obj",
|
|
effects_dir=_SERVER_DIR / "effects",
|
|
)
|
|
|
|
app = FastAPI(title="Face SDK Web", version="0.1.0")
|
|
renderer = FaceRenderer(_PATHS)
|
|
|
|
_STATIC_DIR = _SERVER_DIR / "static"
|
|
|
|
|
|
@app.get("/")
|
|
def index() -> FileResponse:
|
|
return FileResponse(_STATIC_DIR / "index.html")
|
|
|
|
|
|
# /static/* 提供其它资源(CSS/JS 拆分时用得上;当前 index.html 内联)
|
|
app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static")
|
|
|
|
|
|
@app.get("/health")
|
|
def health() -> dict:
|
|
return {"ok": True}
|
|
|
|
|
|
@app.get("/effects")
|
|
def list_effects() -> dict:
|
|
return {"effects": renderer.list_effect_ids()}
|
|
|
|
|
|
@app.post("/render")
|
|
async def render(
|
|
image: UploadFile = File(...),
|
|
effect_id: int = Form(...),
|
|
) -> Response:
|
|
image_bytes = await image.read()
|
|
if not image_bytes:
|
|
raise HTTPException(status_code=400, detail="empty image")
|
|
try:
|
|
png_bytes = renderer.render(image_bytes, effect_id)
|
|
except NoFaceError:
|
|
return JSONResponse(status_code=400, content={"error": "no_face"})
|
|
except EffectNotFoundError as e:
|
|
raise HTTPException(status_code=404, detail=str(e))
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
return Response(content=png_bytes, media_type="image/png")
|