From 54de94da73d78c7696953e77caeaaf701f599065 Mon Sep 17 00:00:00 2001 From: blaise-muhirwa <135643310+blaise-muhirwa@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:31:36 -0700 Subject: [PATCH] Cache for Image Query ID's Originating from the Edge Endpoint (#17) * iqe_cache * add `iqe_` cache * Automatically reformatting code with black and isort * edge detector manager class * Automatically reformatting code with black and isort * formatting --------- Co-authored-by: Blaise Munyampirwa Co-authored-by: Auto-format Bot --- app/api/routes/image_queries.py | 24 +++++++++++++++++++++--- app/core/edge_detector_manager.py | 11 +++++++++++ app/core/motion_detection.py | 2 +- app/core/utils.py | 4 ++++ app/main.py | 6 ++++-- 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 app/core/edge_detector_manager.py diff --git a/app/api/routes/image_queries.py b/app/api/routes/image_queries.py index fc5faf3f..7e22ce3c 100644 --- a/app/api/routes/image_queries.py +++ b/app/api/routes/image_queries.py @@ -2,11 +2,17 @@ from io import BytesIO import numpy as np -from fastapi import APIRouter, Depends, Request +from fastapi import APIRouter, Depends, HTTPException, Request from model import ImageQuery from PIL import Image, ImageFile -from app.core.utils import get_groundlight_sdk_instance, get_motion_detector_instance, prefixed_ksuid, safe_call_api +from app.core.utils import ( + get_edge_detector_manager, + get_groundlight_sdk_instance, + get_motion_detector_instance, + prefixed_ksuid, + safe_call_api, +) logger = logging.getLogger(__name__) @@ -23,6 +29,7 @@ async def post_image_query( request: Request = None, gl: Depends = Depends(get_groundlight_sdk_instance), motion_detector: Depends = Depends(get_motion_detector_instance), + edge_detector_manager: Depends = Depends(get_edge_detector_manager), ): image = await request.body() img = Image.open(BytesIO(image)) @@ -44,9 +51,20 @@ async def post_image_query( logger.debug("No motion detected") new_image_query = ImageQuery(**motion_detector.image_query_response.dict()) new_image_query.id = prefixed_ksuid(prefix="iqe_") + edge_detector_manager.iqe_cache[new_image_query.id] = new_image_query + return new_image_query @router.get("/{id}", response_model=ImageQuery) -async def get_image_query(id: str, gl: Depends = Depends(get_groundlight_sdk_instance)): +async def get_image_query( + id: str, + gl: Depends = Depends(get_groundlight_sdk_instance), + edge_detector_manager: Depends = Depends(get_edge_detector_manager), +): + if id.startswith("iqe_"): + image_query = edge_detector_manager.iqe_cache.get(id, None) + if not image_query: + raise HTTPException(status_code=404, detail=f"Image query with ID {id} not found") + return image_query return safe_call_api(gl.get_image_query, id=id) diff --git a/app/core/edge_detector_manager.py b/app/core/edge_detector_manager.py new file mode 100644 index 00000000..e1a8a260 --- /dev/null +++ b/app/core/edge_detector_manager.py @@ -0,0 +1,11 @@ +class EdgeDetectorManager: + """ + Fow now this class is just a container for the IQE cache. + The cache allows us to control the SDK's polling behavior for image queries + without having to change the SDK itself. + """ + + def __init__(self) -> None: + # Cache for image query responses whose IDs start with "iqe_". This is needed + # because the cloud API does not currently recognize these IDs. + self.iqe_cache = {} diff --git a/app/core/motion_detection.py b/app/core/motion_detection.py index 46c0f646..52e73ae0 100644 --- a/app/core/motion_detection.py +++ b/app/core/motion_detection.py @@ -68,7 +68,7 @@ async def motion_detected(self, new_img: np.ndarray) -> bool: current_time = time.monotonic() if current_time - self._previous_motion_detection_time > self._max_time_between_images: self._previous_motion_detection_time = current_time - logger.debug("Maximum time between images exceeded") + logger.debug("Maximum time between cloud-submitted images exceeded") return True motion_is_detected = await asyncio.to_thread(self._motion_detector.motion_detected, new_img) diff --git a/app/core/utils.py b/app/core/utils.py index a456a042..fd45613d 100644 --- a/app/core/utils.py +++ b/app/core/utils.py @@ -14,6 +14,10 @@ def get_motion_detector_instance(request: Request): return request.app.state.motion_detector +def get_edge_detector_manager(request: Request): + return request.app.state.edge_detector_manager + + def safe_call_api(api_method: Callable, **kwargs): """ This ensures that we correctly handle HTTP error status codes. In some cases, diff --git a/app/main.py b/app/main.py index 406c8f8c..8c049a67 100644 --- a/app/main.py +++ b/app/main.py @@ -7,6 +7,7 @@ from app.api.api import api_router, ping_router from app.api.naming import API_BASE_PATH +from .core.edge_detector_manager import EdgeDetectorManager from .core.motion_detection import AsyncMotionDetector, MotdetParameterSettings LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO").upper() @@ -21,7 +22,8 @@ # Create global shared Groundlight SDK client object in the app's state app.state.groundlight = Groundlight() -parameters = MotdetParameterSettings() - # Create global shared motion detector object in the app's state app.state.motion_detector = AsyncMotionDetector(parameters=MotdetParameterSettings()) + +# Create global shared edge detector manager object in the app's state +app.state.edge_detector_manager = EdgeDetectorManager()