| | """ |
| | 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") |