
- Set up FastAPI project structure with SQLite database - Create database models for tomato images and severity classifications - Implement image upload and processing endpoints - Develop a segmentation model for tomato disease severity detection - Add API endpoints for analysis and results retrieval - Implement health check endpoint - Set up Alembic for database migrations - Update project documentation
112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, status
|
|
from sqlalchemy.orm import Session
|
|
from typing import List
|
|
from pathlib import Path
|
|
|
|
from app.db.session import get_db
|
|
from app.db.crud_tomato import tomato_image
|
|
from app.schemas.tomato import TomatoImage, TomatoImageCreate, UploadResponse
|
|
from app.utils.image import save_uploaded_image
|
|
from app.core.config import settings
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/upload", response_model=UploadResponse, status_code=status.HTTP_201_CREATED)
|
|
async def upload_tomato_image(
|
|
file: UploadFile = File(...),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Upload a tomato image for analysis.
|
|
|
|
The image will be saved and registered in the database.
|
|
It can then be analyzed using the analysis endpoint.
|
|
"""
|
|
# Validate file type
|
|
if file.content_type not in settings.ALLOWED_IMAGE_TYPES:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
|
|
detail=f"Unsupported file type: {file.content_type}. Allowed types: {', '.join(settings.ALLOWED_IMAGE_TYPES)}"
|
|
)
|
|
|
|
# Read file content
|
|
contents = await file.read()
|
|
|
|
# Validate file size
|
|
if len(contents) > settings.MAX_IMAGE_SIZE:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
|
detail=f"File too large. Maximum size allowed: {settings.MAX_IMAGE_SIZE / (1024 * 1024)}MB"
|
|
)
|
|
|
|
# Save file and get metadata
|
|
image_data = save_uploaded_image(contents, file.filename)
|
|
|
|
# Create database record
|
|
image_in = TomatoImageCreate(**image_data)
|
|
db_image = tomato_image.create(db=db, obj_in=image_in)
|
|
|
|
return UploadResponse(
|
|
image=db_image,
|
|
message="Image uploaded successfully"
|
|
)
|
|
|
|
|
|
@router.get("/", response_model=List[TomatoImage])
|
|
def list_tomato_images(
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
List all uploaded tomato images.
|
|
"""
|
|
images = tomato_image.get_multi(db=db, skip=skip, limit=limit)
|
|
return images
|
|
|
|
|
|
@router.get("/{image_id}", response_model=TomatoImage)
|
|
def get_tomato_image(
|
|
image_id: str,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get a specific tomato image by ID.
|
|
"""
|
|
db_image = tomato_image.get(db=db, id=image_id)
|
|
if db_image is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Image not found"
|
|
)
|
|
return db_image
|
|
|
|
|
|
@router.delete("/{image_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None)
|
|
def delete_tomato_image(
|
|
image_id: str,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Delete a tomato image and its associated data.
|
|
"""
|
|
db_image = tomato_image.get(db=db, id=image_id)
|
|
if db_image is None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Image not found"
|
|
)
|
|
|
|
# Delete the image file
|
|
try:
|
|
if db_image.file_path and Path(db_image.file_path).exists():
|
|
Path(db_image.file_path).unlink()
|
|
except Exception:
|
|
# Log error but continue with database deletion
|
|
pass
|
|
|
|
# Delete database record (cascade will handle related records)
|
|
tomato_image.remove(db=db, id=image_id)
|
|
|
|
return None |