from contextlib import asynccontextmanager from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from api.models import PaperResponse, ScanRequest, ScanResponse, StatusResponse from api.scanner import ( ScannerBusyError, ScannerManager, ScannerTimeoutError, ScannerUnavailableError, ) @asynccontextmanager async def lifespan(app: FastAPI): app.state.scanner = ScannerManager() yield app = FastAPI(title="scan-adf", lifespan=lifespan) @app.exception_handler(ScannerBusyError) async def busy_handler(request: Request, exc: ScannerBusyError): return JSONResponse(status_code=409, content={"detail": str(exc)}) @app.exception_handler(ScannerUnavailableError) async def unavailable_handler(request: Request, exc: ScannerUnavailableError): return JSONResponse(status_code=503, content={"detail": str(exc)}) @app.exception_handler(ScannerTimeoutError) async def timeout_handler(request: Request, exc: ScannerTimeoutError): return JSONResponse(status_code=504, content={"detail": str(exc)}) @app.post("/scan", status_code=201, response_model=ScanResponse) async def scan(request: Request, body: ScanRequest): scanner: ScannerManager = request.app.state.scanner output = await scanner.start_scan( mode=body.mode.value, resolution=body.resolution, language=body.language, output=body.output, ) return ScanResponse( message="Scan started", output=output, mode=body.mode.value, resolution=body.resolution, ) @app.get("/status", response_model=StatusResponse) async def status(request: Request): scanner: ScannerManager = request.app.state.scanner return StatusResponse( scanning=scanner.is_scanning, last_result=scanner.last_result, current=scanner.current_scan_info, ) @app.get("/paper", response_model=PaperResponse) async def paper(request: Request): scanner: ScannerManager = request.app.state.scanner result = await scanner.check_paper() return PaperResponse(**result)