From b7060b933e06b7a5b6c6f5d3fad88ba7ecdb8013 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Thu, 29 Oct 2026 19:52:33 -0400 Subject: [PATCH] Serialize TFLite and Coral input shapes as native integers --- .github/workflows/backend-metadata.yml | 17 ++++++++++++++ backends/edgetpu/backend.py | 2 +- backends/tflite/backend.py | 2 +- tests/test_backend_model_info.py | 32 ++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/backend-metadata.yml create mode 100644 tests/test_backend_model_info.py diff --git a/.github/workflows/backend-metadata.yml b/.github/workflows/backend-metadata.yml new file mode 100644 index 0000000..ab3a1ec --- /dev/null +++ b/.github/workflows/backend-metadata.yml @@ -0,0 +1,17 @@ +name: Backend metadata regression +on: + pull_request: + push: + branches: [main] +permissions: + contents: read +jobs: + metadata: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install 'numpy<2' tflite-runtime==2.14.0 fastapi pillow + - run: python -m unittest discover -s tests -p test_backend_model_info.py -v diff --git a/backends/edgetpu/backend.py b/backends/edgetpu/backend.py index 9c5c4c7..d30b041 100644 --- a/backends/edgetpu/backend.py +++ b/backends/edgetpu/backend.py @@ -601,7 +601,7 @@ def get_model_info(self) -> Dict[str, Any]: "model_type": self.model_type, "model_path": self.model_path, "labels_path": self.labels_path, - "input_shape": list(self.input_shape), + "input_shape": [int(dimension) for dimension in self.input_shape], "num_labels": len(self.labels), "default_confidence_threshold": self.confidence_threshold, "device": self.device or "auto", diff --git a/backends/tflite/backend.py b/backends/tflite/backend.py index 6d9a61e..d6b9897 100644 --- a/backends/tflite/backend.py +++ b/backends/tflite/backend.py @@ -273,7 +273,7 @@ def get_model_info(self) -> Dict[str, Any]: "backend": "tflite", "model_path": self.model_path, "labels_path": self.labels_path, - "input_shape": list(self.input_shape), + "input_shape": [int(dimension) for dimension in self.input_shape], "num_labels": len(self.labels), "default_confidence_threshold": self.confidence_threshold } diff --git a/tests/test_backend_model_info.py b/tests/test_backend_model_info.py new file mode 100644 index 0000000..d69304d --- /dev/null +++ b/tests/test_backend_model_info.py @@ -0,0 +1,32 @@ +"""Backend discovery must serialize NumPy-shaped TFLite metadata as JSON.""" +import json +import unittest + +import numpy as np +from fastapi.encoders import jsonable_encoder + +from backends.tflite.backend import TFLiteBackend +from backends.edgetpu.backend import EdgeTPUBackend + + +class ModelInfoTest(unittest.TestCase): + def test_numpy_dimensions_are_json_serializable_without_hardware(self): + for cls in (TFLiteBackend, EdgeTPUBackend): + with self.subTest(backend=cls.__name__): + # Metadata requires neither an interpreter nor a physical Coral. + backend = object.__new__(cls) + backend.model_path = "model.tflite" + backend.labels_path = "labels.txt" + backend.input_shape = np.array([1, 300, 300, 3], dtype=np.int32) + backend.labels = ["person"] + backend.confidence_threshold = 0.5 + backend.model_type = "ssd" + backend.device = "usb" + backend.requires_int8 = False + info = backend.get_model_info() + self.assertEqual(json.loads(json.dumps(info))["input_shape"], [1, 300, 300, 3]) + self.assertEqual(jsonable_encoder(info)["input_shape"], [1, 300, 300, 3]) + + +if __name__ == "__main__": + unittest.main()