echo / app.py
sathish2352's picture
Update app.py
a2d05fd verified
# 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)
# ---------------------------------------------------------------------------
@lru_cache(maxsize=512)
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
# ---------------------------------------------------------------------------
@app.post("/echo")
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")