| """ |
| Routes for the Image Similarity Search API |
| Contains all endpoints for the application |
| """ |
|
|
| from fastapi import APIRouter, FastAPI, File, UploadFile, Form, Query, Path |
| from typing import List, Optional |
| from pydantic import BaseModel |
|
|
| from services.embedding_service import ImageEmbeddingModel |
| from services.vector_db_service import VectorDatabaseClient |
|
|
|
|
| class SearchResponse(BaseModel): |
| """Response model for search results""" |
| image_id: str |
| similarity: float |
| metadata: Optional[dict] = None |
|
|
|
|
| def register_routes( |
| app: FastAPI, |
| embedding_model: ImageEmbeddingModel, |
| vector_db: VectorDatabaseClient, |
| |
| ): |
| """Register all routes with the FastAPI app""" |
| router = APIRouter() |
|
|
| @router.post("/upload", response_model=dict) |
| async def upload_image( |
| file: UploadFile = File(...), |
| metadata: Optional[str] = Form(None), |
| |
| ): |
| """Upload an image and store its embedding""" |
| |
| image_data = await file.read() |
| embedding = embedding_model.generate_embedding(image_data) |
| |
| |
| image_id = vector_db.add_embedding(embedding, file.filename, metadata) |
| |
| return {"image_id": image_id, "message": "Image uploaded successfully"} |
| |
| @router.get("/search/by-id/{image_id}", response_model=List[SearchResponse]) |
| async def search_by_id( |
| image_id: str = Path(..., description="ID of the uploaded image to use as query"), |
| limit: int = Query(5, description="Maximum number of results to return"), |
| |
| ): |
| """Search for similar images using an existing image ID as the query""" |
| results = vector_db.search_by_id(image_id, limit) |
| return [ |
| SearchResponse( |
| image_id=result.id, |
| similarity=result.score, |
| metadata=result.metadata |
| ) |
| for result in results |
| ] |
| |
| @router.post("/search/by-image", response_model=List[SearchResponse]) |
| async def search_by_image( |
| file: UploadFile = File(...), |
| limit: int = Query(5, description="Maximum number of results to return"), |
| |
| ): |
| """Search for similar images by uploading a new image""" |
| |
| image_data = await file.read() |
| embedding = embedding_model.generate_embedding(image_data) |
| |
| |
| results = vector_db.search_by_embedding(embedding, limit) |
| return [ |
| SearchResponse( |
| image_id=result.id, |
| similarity=result.score, |
| metadata=result.metadata |
| ) |
| for result in results |
| ] |
| |
| @router.delete("/images/{image_id}") |
| async def delete_image( |
| image_id: str = Path(..., description="ID of the image to delete"), |
| |
| ): |
| """Delete an image from the database""" |
| success = vector_db.delete_embedding(image_id) |
| if success: |
| return {"message": f"Image {image_id} deleted successfully"} |
| return {"message": f"Image {image_id} not found"} |
| |
| |
| |
| app.include_router(router, prefix="/api/v1") |