Spaces:
Running
Running
File size: 3,007 Bytes
a8962d7 efba968 a8962d7 5a01a63 a8962d7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | 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)",
)
@field_validator("data")
@classmethod
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
@field_validator("size")
@classmethod
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]
@router.post(
"/qr-generator",
response_model=QRGenerateResponse,
summary="Generate QR codes for a batch of data strings",
description="Accepts up to 500 data strings and returns QR code image URLs for each. "
"The actual QR image is hosted by an external service.",
)
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],
)
|