Spaces:
Sleeping
Sleeping
# app.py | |
from fastapi import FastAPI, HTTPException, Request | |
from fastapi.responses import StreamingResponse | |
import qrcode | |
import io | |
from functools import lru_cache | |
app = FastAPI() | |
# --------------------------------------------------------------------------- | |
# QR‑code generation helper (cached) | |
# --------------------------------------------------------------------------- | |
def _qr_png(text: str) -> bytes: | |
"""Return PNG bytes for *text*. | |
* Uses `qrcode.make`, which is faster than constructing a `QRCode` object | |
manually. | |
* Memoised with `lru_cache` so repeated requests for the same text are | |
served from memory (~10× faster, avoids QR code re‑creation and pillow | |
image encoding). | |
""" | |
img = qrcode.make(text) # Fast 1‑liner QR generation | |
buf = io.BytesIO() | |
img.save(buf, format="PNG") | |
return buf.getvalue() | |
# --------------------------------------------------------------------------- | |
# API endpoint | |
# --------------------------------------------------------------------------- | |
async def echo(request: Request): | |
"""Generate a QR‑code for the given JSON body. | |
Accepted payloads: | |
• Plain JSON string → "Hello" | |
• Object with `text` → {"text": "Hello"} | |
Any other JSON types are stringified via `str(payload)`. | |
""" | |
# --------------------------------------------------------------------- | |
# 1. Extract JSON body | |
# --------------------------------------------------------------------- | |
try: | |
payload = await request.json() | |
except Exception: | |
raise HTTPException(status_code=400, detail="Expected a JSON body") | |
if payload in (None, "", []): | |
raise HTTPException(status_code=400, detail="Payload cannot be empty") | |
# Normalise to string | |
text = payload["text"] if isinstance(payload, dict) and "text" in payload else str(payload) | |
# --------------------------------------------------------------------- | |
# 2. Build / fetch QR code PNG (cached) | |
# --------------------------------------------------------------------- | |
png_bytes = _qr_png(text) | |
# --------------------------------------------------------------------- | |
# 3. Return as stream (new BytesIO per request so multiple clients can read) | |
# --------------------------------------------------------------------- | |
return StreamingResponse(io.BytesIO(png_bytes), media_type="image/png") | |