| from fastapi import FastAPI, File, UploadFile, Request
|
| from fastapi.responses import StreamingResponse, JSONResponse
|
| from fastapi.middleware.cors import CORSMiddleware
|
| from PIL import Image
|
| import io
|
| import os
|
| from datetime import datetime
|
| from dotenv import load_dotenv
|
|
|
| from analyzer import CrimeSceneAnalyzer
|
|
|
|
|
| load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '.env'))
|
|
|
| app = FastAPI()
|
|
|
|
|
|
|
|
|
| _frontend_url = os.environ.get("FRONTEND_URL", "http://localhost:5173")
|
| _backend_url = os.environ.get("VITE_API_BASE_URL", "http://localhost:5000")
|
|
|
| app.add_middleware(
|
| CORSMiddleware,
|
| allow_origins=[_frontend_url, _backend_url, "http://localhost:5173", "http://localhost:5000"],
|
| allow_credentials=False,
|
| allow_methods=["*"],
|
| allow_headers=["*"],
|
| )
|
|
|
| analyzer = CrimeSceneAnalyzer()
|
|
|
| @app.post("/analyze")
|
| async def analyze(file: UploadFile = File(...)):
|
| try:
|
| image_bytes = await file.read()
|
| image_pil = Image.open(io.BytesIO(image_bytes))
|
| except Exception as e:
|
| return JSONResponse(
|
| status_code=400,
|
| content={"error": f"Invalid or corrupted image file. Details: {str(e)}"}
|
| )
|
|
|
|
|
| result = analyzer.analyze_scene(image_pil)
|
|
|
| if not result or "error" in result:
|
| return JSONResponse(
|
| status_code=500,
|
| content={"error": result.get("error", "AI analysis error") if isinstance(result, dict) else "AI analysis error"}
|
| )
|
|
|
| pdf_bytes = result.get("pdf_bytes")
|
| if not pdf_bytes:
|
| return JSONResponse(
|
| status_code=500,
|
| content={"error": "No PDF bytes produced by AI analysis."}
|
| )
|
|
|
|
|
| pdf_stream = io.BytesIO(pdf_bytes)
|
|
|
| filename = f"CSR_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pdf"
|
|
|
| return StreamingResponse(
|
| content=pdf_stream,
|
| media_type="application/pdf",
|
| headers={"Content-Disposition": f"attachment; filename={filename}"}
|
| )
|
|
|