Spaces:
Running
Running
| 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" | |
| def health(): | |
| return {"ok": True, "service": "tmp-file-service", "auth": bool(UPLOAD_TOKEN)} | |
| 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)} | |
| 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) | |