Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, Request, Form, HTTPException, Depends | |
| from fastapi.responses import RedirectResponse, HTMLResponse, StreamingResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.templating import Jinja2Templates | |
| from fastapi.middleware.cors import CORSMiddleware | |
| import os | |
| import qrcode | |
| import io | |
| import uuid | |
| from typing import Dict, Optional | |
| import json | |
| from datetime import datetime, timedelta | |
| import uvicorn | |
| # Initialize FastAPI app | |
| app = FastAPI( | |
| title="Dynamic QR Generator", | |
| description="Enterprise-grade dynamic QR code management system", | |
| version="1.0.0" | |
| ) | |
| # Add CORS middleware | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Mount static files and templates | |
| os.makedirs("static", exist_ok=True) | |
| os.makedirs("templates", exist_ok=True) | |
| app.mount("/static", StaticFiles(directory="static"), name="static") | |
| templates = Jinja2Templates(directory="templates") | |
| # In-memory storage for QR codes (use database in production) | |
| qr_codes: Dict[str, Dict] = {} | |
| class QRCodeManager: | |
| """Middleware class for QR code management logic""" | |
| def generate_qr_id() -> str: | |
| """Generate unique QR code identifier""" | |
| return str(uuid.uuid4())[:8] | |
| def create_qr_code(qr_id: str, redirect_url: str, title: str = "Untitled") -> Dict: | |
| """Create a new QR code entry""" | |
| qr_data = { | |
| "id": qr_id, | |
| "title": title, | |
| "redirect_url": redirect_url, | |
| "scan_count": 0, | |
| "created_at": datetime.now().isoformat(), | |
| "last_scanned": None, | |
| "is_active": True | |
| } | |
| qr_codes[qr_id] = qr_data | |
| return qr_data | |
| def update_qr_code(qr_id: str, redirect_url: str, title: str = None) -> Optional[Dict]: | |
| """Update existing QR code""" | |
| if qr_id not in qr_codes: | |
| return None | |
| qr_codes[qr_id]["redirect_url"] = redirect_url | |
| if title: | |
| qr_codes[qr_id]["title"] = title | |
| qr_codes[qr_id]["updated_at"] = datetime.now().isoformat() | |
| return qr_codes[qr_id] | |
| def get_qr_code(qr_id: str) -> Optional[Dict]: | |
| """Get QR code data""" | |
| return qr_codes.get(qr_id) | |
| def increment_scan_count(qr_id: str) -> None: | |
| """Increment scan count and update last scanned time""" | |
| if qr_id in qr_codes: | |
| qr_codes[qr_id]["scan_count"] += 1 | |
| qr_codes[qr_id]["last_scanned"] = datetime.now().isoformat() | |
| def get_all_qr_codes() -> Dict[str, Dict]: | |
| """Get all QR codes""" | |
| return qr_codes | |
| def generate_qr_image(qr_id: str) -> io.BytesIO: | |
| """Generate QR code image""" | |
| base_url = os.getenv("BASE_URL", "https://huggingface.co/spaces/parthmax/dynamic-qr") | |
| qr_url = f"{base_url}/r/{qr_id}" | |
| qr = qrcode.QRCode( | |
| version=1, | |
| error_correction=qrcode.constants.ERROR_CORRECT_L, | |
| box_size=10, | |
| border=4, | |
| ) | |
| qr.add_data(qr_url) | |
| qr.make(fit=True) | |
| img = qr.make_image(fill_color="black", back_color="white") | |
| img_io = io.BytesIO() | |
| img.save(img_io, 'PNG') | |
| img_io.seek(0) | |
| return img_io | |
| # Initialize QR manager | |
| qr_manager = QRCodeManager() | |
| async def home(request: Request): | |
| """Main dashboard page""" | |
| all_qr_codes = qr_manager.get_all_qr_codes() | |
| return templates.TemplateResponse("index.html", { | |
| "request": request, | |
| "qr_codes": all_qr_codes | |
| }) | |
| async def create_qr( | |
| title: str = Form(...), | |
| redirect_url: str = Form(...), | |
| ): | |
| """Create a new QR code""" | |
| if not redirect_url.startswith(('http://', 'https://')): | |
| redirect_url = f"https://{redirect_url}" | |
| qr_id = qr_manager.generate_qr_id() | |
| qr_data = qr_manager.create_qr_code(qr_id, redirect_url, title) | |
| return RedirectResponse(url="/", status_code=303) | |
| async def update_qr( | |
| qr_id: str, | |
| title: str = Form(...), | |
| redirect_url: str = Form(...), | |
| ): | |
| """Update existing QR code""" | |
| if qr_id not in qr_codes: | |
| raise HTTPException(status_code=404, detail="QR code not found") | |
| if not redirect_url.startswith(('http://', 'https://')): | |
| redirect_url = f"https://{redirect_url}" | |
| qr_manager.update_qr_code(qr_id, redirect_url, title) | |
| return RedirectResponse(url="/", status_code=303) | |
| async def redirect_qr(qr_id: str): | |
| """Redirect endpoint for QR code scans""" | |
| qr_data = qr_manager.get_qr_code(qr_id) | |
| if not qr_data or not qr_data.get("is_active"): | |
| raise HTTPException(status_code=404, detail="QR code not found or inactive") | |
| # Increment scan count | |
| qr_manager.increment_scan_count(qr_id) | |
| return RedirectResponse(url=qr_data["redirect_url"]) | |
| async def get_qr_image(qr_id: str): | |
| """Generate and serve QR code image""" | |
| if qr_id not in qr_codes: | |
| raise HTTPException(status_code=404, detail="QR code not found") | |
| img_io = qr_manager.generate_qr_image(qr_id) | |
| return StreamingResponse(img_io, media_type="image/png") | |
| async def delete_qr(qr_id: str): | |
| """Delete QR code""" | |
| if qr_id not in qr_codes: | |
| raise HTTPException(status_code=404, detail="QR code not found") | |
| del qr_codes[qr_id] | |
| return {"message": "QR code deleted successfully"} | |
| async def get_qr_data(qr_id: str): | |
| """Get QR code data via API""" | |
| qr_data = qr_manager.get_qr_code(qr_id) | |
| if not qr_data: | |
| raise HTTPException(status_code=404, detail="QR code not found") | |
| return qr_data | |
| async def health_check(): | |
| """Health check endpoint""" | |
| return {"status": "healthy", "timestamp": datetime.now().isoformat()} | |
| if __name__ == "__main__": | |
| uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True) |