diff --git a/containers/init_script/init_script.py b/containers/init_script/init_script.py index 009a5b7..2bcf2d4 100644 --- a/containers/init_script/init_script.py +++ b/containers/init_script/init_script.py @@ -1,4 +1,4 @@ -###### TODO REFACTOR : use the init scripts which are in the test_update_pi directory +#  TODO REFACTOR : use the init scripts which are in the test_update_pi directory #!/usr/bin/env python @@ -72,6 +72,7 @@ def write_json_file(file_path, data): organizations = pd.read_csv(f"data/csv/API_DATA{sub_path} - organizations.csv") cameras = pd.read_csv(f"data/csv/API_DATA{sub_path} - cameras.csv") cameras = cameras.fillna("") +poses = pd.read_csv(f"data/csv/API_DATA{sub_path} - poses.csv") for orga in organizations.itertuples(index=False): logging.info(f"saving orga : {orga.name}") @@ -131,6 +132,16 @@ def write_json_file(file_path, data): write_json_file(credentials_path, data) write_json_file(credentials_path_etl, data_wildfire) +logging.info("creating poses") +for pose in poses.itertuples(index=False): + payload = { + "camera_id": pose.camera_id, + "azimuth": pose.azimuth, + "patrol_id": pose.patrol_id, + } + api_request("post", f"{api_url}/poses/", superuser_auth, payload) + + # Load environment variables from .env file # load_dotenv() diff --git a/containers/notebooks/app/send_real_alerts.ipynb b/containers/notebooks/app/send_real_alerts.ipynb index ce63162..4d22449 100644 --- a/containers/notebooks/app/send_real_alerts.ipynb +++ b/containers/notebooks/app/send_real_alerts.ipynb @@ -139,6 +139,8 @@ "metadata": {}, "outputs": [], "source": [ + "send_alert_from_cam_ids = [2, 4, 5, 14] # select cameras\n", + "\n", "sequances_folders = glob.glob(f\"{SAMPLE_PATH}/*\")\n", "\n", "for camera_id in send_alert_from_cam_ids:\n", @@ -151,9 +153,12 @@ " imgs.sort()\n", " preds = glob.glob(f\"{sequances_folder}/labels_predictions/*\")\n", " preds.sort()\n", - " \n", - " cam_center_azimuth = random.randint(0,360)\n", - " print(f\"Sending alerts from camera {camera_id} at azimuth {cam_center_azimuth}\")\n", + "\n", + " cam_poses = camera_client.get_current_poses().json()\n", + " # pick a random pose id\n", + " pose_id = random.choice(cam_poses)['id']\n", + "\n", + " print(f\"Sending alerts from camera {camera_id} at (pose_id={pose_id})\")\n", " for img_file, pred_file in zip(imgs, preds):\n", " \n", " stream = io.BytesIO()\n", @@ -161,7 +166,7 @@ " im.save(stream, format=\"JPEG\", quality=80)\n", "\n", " bboxes = read_pred_file(pred_file)\n", - " response = camera_client.create_detection(stream.getvalue(), cam_center_azimuth, bboxes)\n", + " response = camera_client.create_detection(stream.getvalue(), bboxes, pose_id=pose_id)\n", " # Force a KeyError if the request failed\n", " \n", " response.json()[\"id\"]" @@ -193,7 +198,7 @@ "source": [ "SEQUENCES_DIR_PATH = \"../data/alert_samples/single_sequences/*\"\n", "sequences_directories = glob.glob(SEQUENCES_DIR_PATH)\n", - "CAM_MAPPING = {22:13, 42:7, 59:5, 14:11, 43:8, 79:14, 13:10, 11:15, 59:1, 60:2, 15:12, 12:9, 10:16, 41:2, 65:8}\n", + "CAM_MAPPING = {22: 13, 42: 7, 59: 5, 14: 11, 43: 8, 79: 14, 13: 10, 11: 15, 60: 2, 15: 12, 12: 9, 10: 16, 41: 2, 65: 8}\n", "\n", "for seq_path in sequences_directories:\n", " \n", @@ -211,9 +216,12 @@ " preds = glob.glob(f\"{seq_path}/labels_predictions/*\")\n", " preds.sort()\n", "\n", - " cam_center_azimuth = random.randint(0,360)\n", + " cam_poses = camera_client.get_current_poses().json()\n", + " # pick a random pose id\n", + " pose_id = random.choice(cam_poses)['id']\n", + "\n", " \n", - " print(f\"Sending alerts from camera {camera_id} at azimuth {cam_center_azimuth}\")\n", + " print(f\"Sending alerts from camera {camera_id} at (pose_id={pose_id})\")\n", " for img_file, pred_file in zip(imgs, preds):\n", " \n", " stream = io.BytesIO()\n", @@ -223,9 +231,9 @@ " #bboxes = read_pred_file(pred_file)\n", " with open(pred_file, 'r', encoding='utf-8') as file:\n", " bboxes = ast.literal_eval(file.read())\n", - " \n", " #bboxes = np.loadtxt(pred_file, ndmin=2)\n", - " response = camera_client.create_detection(stream.getvalue(), cam_center_azimuth, bboxes)\n", + " response = camera_client.create_detection(stream.getvalue(), bboxes, pose_id=pose_id)\n", + "\n", " # Force a KeyError if the request failed\n", " time.sleep(0.5)\n", " response.json()[\"id\"]" @@ -352,7 +360,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.7" + "version": "3.11.14" } }, "nbformat": 4, diff --git a/containers/notebooks/app/test poses.ipynb b/containers/notebooks/app/test poses.ipynb new file mode 100644 index 0000000..c801a17 --- /dev/null +++ b/containers/notebooks/app/test poses.ipynb @@ -0,0 +1,870 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "5b6797a0-8025-4e97-bf5e-5849f4623f69", + "metadata": {}, + "outputs": [], + "source": [ + "from dotenv import load_dotenv\n", + "import os\n", + "from api import get_token, get_camera_token\n", + "from pyroclient import Client\n", + "import requests\n", + "\n", + "\n", + "API_URL = \"http://api:5050\"\n", + "load_dotenv(\"../.env\")\n", + "SUPERADMIN_LOGIN = os.environ.get(\"SUPERADMIN_LOGIN\")\n", + "SUPERADMIN_PWD = os.environ.get(\"SUPERADMIN_PWD\")\n", + "\n", + "# Get access token\n", + "admin_access_token = get_token(API_URL, SUPERADMIN_LOGIN, SUPERADMIN_PWD)\n", + "\n", + "\n", + "api_client = Client(admin_access_token, API_URL)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "ec200386-bd8d-4716-9850-5948b99534c0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.create_pose(camera_id=1, azimuth=12, patrol_id=3)\n", + "api_client.create_pose(camera_id=1, azimuth=350, patrol_id=33333)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "861f2108-2d28-4103-a29e-cfcfcbb4a451", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 1,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [{'azimuth': 12.0, 'patrol_id': 3, 'id': 2, 'camera_id': 1},\n", + " {'azimuth': 350.0, 'patrol_id': 33333, 'id': 3, 'camera_id': 1},\n", + " {'azimuth': 12.0, 'patrol_id': 3, 'id': 4, 'camera_id': 1},\n", + " {'azimuth': 350.0, 'patrol_id': 33333, 'id': 5, 'camera_id': 1}],\n", + " 'created_at': '2025-12-19T10:18:43.964412'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 2,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.974069'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 3,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.979926'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 4,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.985838'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 5,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.991312'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 6,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.997215'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 7,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.002691'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 8,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.008032'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 9,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.013729'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-02',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 10,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.019147'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-03',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 11,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.024241'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-04',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 12,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.029660'},\n", + " {'elevation': 881.0,\n", + " 'lat': 44.3969,\n", + " 'lon': 4.0837,\n", + " 'organization_id': 3,\n", + " 'name': 'serre-de-barre-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 13,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.035088'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 14,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.040337'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 15,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.045870'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-03',\n", + " 'angle_of_view': 180.0,\n", + " 'is_trustable': True,\n", + " 'id': 16,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.051086'},\n", + " {'elevation': 987.0,\n", + " 'lat': 44.6884918213,\n", + " 'lon': 4.3135008812,\n", + " 'organization_id': 3,\n", + " 'name': 'marguerite-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 17,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.056639'}]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.fetch_cameras().json()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "9968d36c-f37b-4949-9e21-92cf69b6697b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.patch_pose(pose_id=2, azimuth=3)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "c0231abf-acd5-4e19-91cc-78d7e3c3ef7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 1,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [{'azimuth': 4.0, 'patrol_id': 2222, 'id': 1, 'camera_id': 1}],\n", + " 'created_at': '2025-12-19T10:18:43.964412'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 2,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.974069'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 3,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.979926'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 4,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.985838'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 5,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.991312'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 6,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.997215'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 7,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.002691'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 8,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.008032'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 9,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.013729'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-02',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 10,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.019147'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-03',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 11,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.024241'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-04',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 12,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.029660'},\n", + " {'elevation': 881.0,\n", + " 'lat': 44.3969,\n", + " 'lon': 4.0837,\n", + " 'organization_id': 3,\n", + " 'name': 'serre-de-barre-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 13,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.035088'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 14,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.040337'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 15,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.045870'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-03',\n", + " 'angle_of_view': 180.0,\n", + " 'is_trustable': True,\n", + " 'id': 16,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.051086'},\n", + " {'elevation': 987.0,\n", + " 'lat': 44.6884918213,\n", + " 'lon': 4.3135008812,\n", + " 'organization_id': 3,\n", + " 'name': 'marguerite-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 17,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.056639'}]" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.fetch_cameras().json()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f7e15332-f8c6-49c8-95fe-c2b65feb689a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.delete_pose(pose_id=1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3467cbc6-3ed3-42e3-a9f6-7d5e3377e25b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 1,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.964412'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4783,\n", + " 'lon': 2.4242,\n", + " 'organization_id': 2,\n", + " 'name': 'videlles-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 2,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.974069'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 3,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.979926'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.4267,\n", + " 'lon': 2.7109,\n", + " 'organization_id': 2,\n", + " 'name': 'croix-augas-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 4,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.985838'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 5,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.991312'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.3792,\n", + " 'lon': 2.8208,\n", + " 'organization_id': 2,\n", + " 'name': 'moret-sur-loing-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 6,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:43.997215'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 7,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.002691'},\n", + " {'elevation': 110.0,\n", + " 'lat': 48.2605,\n", + " 'lon': 2.7064,\n", + " 'organization_id': 2,\n", + " 'name': 'nemours-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 8,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.008032'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 9,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.013729'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-02',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 10,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.019147'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-03',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 11,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.024241'},\n", + " {'elevation': 110.0,\n", + " 'lat': 44.5451,\n", + " 'lon': 4.2165,\n", + " 'organization_id': 3,\n", + " 'name': 'brison-04',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 12,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.029660'},\n", + " {'elevation': 881.0,\n", + " 'lat': 44.3969,\n", + " 'lon': 4.0837,\n", + " 'organization_id': 3,\n", + " 'name': 'serre-de-barre-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 13,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.035088'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-01',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 14,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.040337'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-02',\n", + " 'angle_of_view': 54.2,\n", + " 'is_trustable': True,\n", + " 'id': 15,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.045870'},\n", + " {'elevation': 200.0,\n", + " 'lat': 44.92757,\n", + " 'lon': 4.84164,\n", + " 'organization_id': 3,\n", + " 'name': 'st-peray-03',\n", + " 'angle_of_view': 180.0,\n", + " 'is_trustable': True,\n", + " 'id': 16,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.051086'},\n", + " {'elevation': 987.0,\n", + " 'lat': 44.6884918213,\n", + " 'lon': 4.3135008812,\n", + " 'organization_id': 3,\n", + " 'name': 'marguerite-01',\n", + " 'angle_of_view': 87.0,\n", + " 'is_trustable': True,\n", + " 'id': 17,\n", + " 'last_active_at': None,\n", + " 'last_image': None,\n", + " 'last_image_url': None,\n", + " 'poses': [],\n", + " 'created_at': '2025-12-19T10:18:44.056639'}]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.fetch_cameras().json()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "5c40b370-e846-4a39-a50d-66cfcdfc3304", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "api_client.create_pose(camera_id=1, azimuth=3, patrol_id=\"re\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d6ba20c-ab93-4ac6-81b3-089e70618366", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/containers/notebooks/app/utils.py b/containers/notebooks/app/utils.py index 6dc7a1c..cb20243 100644 --- a/containers/notebooks/app/utils.py +++ b/containers/notebooks/app/utils.py @@ -1,3 +1,4 @@ +import ast import os import io import glob @@ -141,6 +142,22 @@ def dl_seqs_from_url(url, output_path): print("Extraction completed.") +def get_or_create_pose_id_for_azimuth( + camera_client, camera_id, azimuth, tol=0.1, patrol_id=None +): + resp = camera_client.get_current_poses() + resp.raise_for_status() + for pose in resp.json(): + if abs(pose["azimuth"] - azimuth) <= tol: + return pose["id"] + print(f"did not found a matching pose_id, gonna create one, azimuth was {azimuth}") + create_resp = camera_client.create_pose( + camera_id=camera_id, azimuth=azimuth, patrol_id=patrol_id + ) + create_resp.raise_for_status() + return create_resp.json()["id"] + + def send_triangulated_alerts( cam_triangulation, API_URL, Client, admin_access_token, sleep_seconds=1 ): @@ -170,15 +187,19 @@ def send_triangulated_alerts( img_file, pred_file = pair client = info["client"] azimuth = info["azimuth"] - + # print(f"cam if {cam_id}") + pose_id = get_or_create_pose_id_for_azimuth(client, cam_id, azimuth) + # print(f"pose_id:{pose_id}") stream = io.BytesIO() im = Image.open(img_file) im.save(stream, format="JPEG", quality=80) with open(pred_file, "r") as file: - bboxes = file.read() + bboxes = ast.literal_eval(file.read()) - response = client.create_detection(stream.getvalue(), azimuth, eval(bboxes)) + response = client.create_detection( + stream.getvalue(), bboxes, pose_id=pose_id + ) time.sleep(sleep_seconds) response.json()["id"] # Force a KeyError if the request failed diff --git a/containers/notebooks/requirements.txt b/containers/notebooks/requirements.txt index e6ec850..492d624 100644 --- a/containers/notebooks/requirements.txt +++ b/containers/notebooks/requirements.txt @@ -1,4 +1,4 @@ pandas python-dotenv pillow -pyroclient @ git+https://github.com/pyronear/pyro-api.git@c45d5c0f3f22979fe9f74fdd0d831a3a8b911b54#subdirectory=client +pyroclient @ git+https://github.com/pyronear/pyro-api.git@main#subdirectory=client diff --git a/data/csv/API_DATA_DEV - poses.csv b/data/csv/API_DATA_DEV - poses.csv new file mode 100644 index 0000000..9b0c6d6 --- /dev/null +++ b/data/csv/API_DATA_DEV - poses.csv @@ -0,0 +1,45 @@ +id,camera_id,azimuth,patrol_id +1,1,0,1 +2,1,120,2 +3,1,240,3 +4,2,60,1 +5,2,150,2 +6,2,240,3 +7,2,330,4 +8,3,0,1 +9,3,120,2 +10,3,240,3 +11,4,60,1 +12,4,150,2 +13,4,240,3 +14,4,330,4 +15,5,0,1 +16,5,120,2 +17,5,240,3 +18,6,60,1 +19,6,150,2 +20,6,240,3 +21,6,330,4 +22,7,0,1 +23,7,120,2 +24,7,240,3 +25,8,60,1 +26,8,150,2 +27,8,240,3 +28,8,330,4 +29,9,0,1 +30,10,90,2 +31,11,180,3 +32,12,270,4 +33,13,0,1 +34,13,120,2 +35,13,240,3 +36,14,0,1 +37,14,120,2 +38,14,240,3 +39,15,60,1 +40,15,150,2 +41,15,240,3 +42,15,330,4 +43,16,0,2 +44,17,180,3