tmp-files / app.py
looknicemm1
tmp-file-service: FastAPI upload/download (gradio->docker)
9d5755d
Raw
History Blame Contribute Delete
2.96 kB
import os
import pathlib
import uuid
from fastapi import FastAPI, File, HTTPException, Request, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
DATA_DIR = pathlib.Path(os.environ.get("DATA_DIR", "/tmp/uploads"))
DATA_DIR.mkdir(parents=True, exist_ok=True)
MAX_BYTES = int(os.environ.get("MAX_BYTES", str(30 * 1024 * 1024)))
# Optional shared upload token. If UPLOAD_TOKEN is unset, uploads are open (temp use).
UPLOAD_TOKEN = os.environ.get("UPLOAD_TOKEN", "").strip()
# Optional public base override, e.g. https://looknicemm1-tmp-files.hf.space
PUBLIC_BASE = os.environ.get("PUBLIC_BASE", "").strip().rstrip("/")
EXT_BY_TYPE = {
"image/jpeg": "jpg",
"image/jpg": "jpg",
"image/png": "png",
"image/webp": "webp",
"image/gif": "gif",
"video/mp4": "mp4",
"video/quicktime": "mov",
"video/webm": "webm",
"audio/mpeg": "mp3",
"audio/mp4": "m4a",
"audio/wav": "wav",
"audio/x-wav": "wav",
"audio/aac": "aac",
"audio/ogg": "ogg",
}
app = FastAPI(title="tmp-file-service")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
def public_base(request: Request) -> str:
if PUBLIC_BASE:
return PUBLIC_BASE
host = request.headers.get("x-forwarded-host") or request.headers.get("host") or "localhost"
proto = request.headers.get("x-forwarded-proto", "https")
return f"{proto}://{host}"
def check_auth(request: Request) -> None:
if not UPLOAD_TOKEN:
return
header = request.headers.get("authorization", "")
token = header[7:].strip() if header.lower().startswith("bearer ") else request.query_params.get("token", "")
if token != UPLOAD_TOKEN:
raise HTTPException(401, "invalid upload token")
def pick_ext(file: UploadFile) -> str:
ext = EXT_BY_TYPE.get((file.content_type or "").lower())
if ext:
return ext
suffix = pathlib.Path(file.filename or "").suffix.lstrip(".").lower()
return suffix or "bin"
@app.get("/")
def health():
return {"ok": True, "service": "tmp-file-service", "auth": bool(UPLOAD_TOKEN)}
@app.post("/upload")
async def upload(request: Request, file: UploadFile = File(...)):
check_auth(request)
data = await file.read()
if not data:
raise HTTPException(400, "empty file")
if len(data) > MAX_BYTES:
raise HTTPException(413, f"file too large (> {MAX_BYTES} bytes)")
name = f"{uuid.uuid4().hex}.{pick_ext(file)}"
(DATA_DIR / name).write_bytes(data)
url = f"{public_base(request)}/files/{name}"
return {"success": True, "url": url, "filename": name, "size": len(data)}
@app.get("/files/{name}")
def get_file(name: str):
if "/" in name or ".." in name:
raise HTTPException(400, "bad name")
path = DATA_DIR / name
if not path.is_file():
raise HTTPException(404, "not found")
return FileResponse(path)