Spaces:
Running
Running
| from __future__ import annotations | |
| import threading | |
| from typing import List, Optional | |
| from fastapi import APIRouter, HTTPException | |
| from pydantic import BaseModel, Field, field_validator | |
| from app.services.qr_generator_service import QRGeneratorError, QRGeneratorService | |
| router = APIRouter() | |
| _service_lock = threading.Lock() | |
| _shared_service: Optional[QRGeneratorService] = None | |
| def _get_service() -> QRGeneratorService: | |
| global _shared_service | |
| if _shared_service is None: | |
| with _service_lock: | |
| if _shared_service is None: | |
| _shared_service = QRGeneratorService() | |
| return _shared_service | |
| class QRGenerateRequest(BaseModel): | |
| data: List[str] = Field( | |
| ..., | |
| min_length=1, | |
| max_length=500, | |
| description="List of data strings to generate QR codes for (max 500)", | |
| ) | |
| size: str = Field( | |
| "300x300", | |
| description="QR code image size in WIDTHxHEIGHT format (e.g., 300x300)", | |
| ) | |
| def validate_data_items(cls, v: List[str]) -> List[str]: | |
| for i, item in enumerate(v): | |
| if not item or not item.strip(): | |
| raise ValueError(f"Data item at index {i} must be a non-empty string") | |
| if len(item) > 2048: | |
| raise ValueError( | |
| f"Data item at index {i} exceeds max length of 2048 characters" | |
| ) | |
| return v | |
| def validate_size(cls, v: str) -> str: | |
| parts = v.lower().split("x") | |
| if len(parts) != 2: | |
| raise ValueError("Size must be in format WIDTHxHEIGHT (e.g., 300x300)") | |
| for part in parts: | |
| if not part.isdigit() or int(part) < 1 or int(part) > 1000: | |
| raise ValueError("Width and height must be between 1 and 1000") | |
| return v | |
| class QRItemResult(BaseModel): | |
| index: int | |
| data: str | |
| qr_image_url: Optional[str] = None | |
| error: Optional[str] = None | |
| class QRGenerateResponse(BaseModel): | |
| success: bool | |
| total: int | |
| succeeded: int | |
| failed: int | |
| results: List[QRItemResult] | |
| def generate_qr_codes(body: QRGenerateRequest): | |
| service = _get_service() | |
| try: | |
| results = service.generate_bulk(body.data, body.size) | |
| except QRGeneratorError as e: | |
| raise HTTPException(status_code=400, detail={"success": False, "error": str(e)}) | |
| succeeded = sum(1 for r in results if r["error"] is None) | |
| failed = len(results) - succeeded | |
| return QRGenerateResponse( | |
| success=failed == 0, | |
| total=len(results), | |
| succeeded=succeeded, | |
| failed=failed, | |
| results=[QRItemResult(**r) for r in results], | |
| ) | |