Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "node-hub/dora-magma/dora_magma/Magma"]
path = dora-magma/dora_magma/Magma
url = https://github.com/microsoft/Magma
[submodule "node-hub/dora-smolagents"]
path = node-hub/dora-smolagents
url = https://github.com/DEFAULTE-R/dora-smolagents.git
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ license = "Apache-2.0"
repository = "https://github.com/dora-rs/dora-hub/"

[workspace.dependencies]
dora-node-api = { version = "0.4.1", default-features = false }
dora-node-api = { version = "0.5.0", default-features = false }
dora-operator-api = { version = "0.4.1", default-features = false }
dora-operator-api-macros = { version = "0.4.1" }
dora-operator-api-types = { version = "0.4.1" }
dora-operator-api-c = { version = "0.4.1" }
dora-node-api-c = { version = "0.4.1" }
dora-node-api-c = { version = "0.5.0" }
dora-core = { version = "0.4.1" }
dora-arrow-convert = { version = "0.4.1" }
dora-tracing = { version = "0.4.1" }
Expand Down
1 change: 1 addition & 0 deletions node-hub/dora-smolagents
Submodule dora-smolagents added at 56e9aa
35 changes: 35 additions & 0 deletions node-hub/dora-tflite/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# dora-tflite

A Dora node for running TensorFlow Lite inference on edge and constrained devices (Raspberry Pi, microcontrollers).

## Installation

Comment on lines +1 to +6

Copilot AI Mar 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title/description focus on adding tracing to the dora-smolagents node, but this change set also introduces an entire new node package (dora-tflite) including its lockfile, tests, and docs. Please either update the PR description to cover the dora-tflite addition (and why it’s included) or split this into a separate PR to keep review scope aligned.

Copilot uses AI. Check for mistakes.
```bash
pip install dora-tflite
```

## Usage

```yaml
nodes:
- id: tflite-inference
path: dora-tflite
inputs:
tensor: source/tensor
outputs:
- inference
env:
MODEL: path/to/model.tflite
```

## Inputs

- `tensor`: Input tensor as a flat array (PyArrow)

## Outputs

- `inference`: Output tensor as a flat array (PyArrow)

## Environment Variables

- `MODEL`: Path to the .tflite model file (default: model.tflite)
Empty file.
79 changes: 79 additions & 0 deletions node-hub/dora-tflite/dora_tflite/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""Dora node for TensorFlow Lite inference on edge/constrained devices."""

import argparse
import os

import numpy as np
import pyarrow as pa
from dora import Node


def main():
"""Run the dora-tflite inference node."""
parser = argparse.ArgumentParser(
description="dora-tflite: TensorFlow Lite inference node for edge deployment.",
)
parser.add_argument(
"--name",
type=str,
required=False,
help="The name of the node in the dataflow.",
default="dora-tflite",
)
parser.add_argument(
"--model",
type=str,
required=False,
help="Path to the .tflite model file.",
default="model.tflite",
)
args = parser.parse_args()

model_path = os.getenv("MODEL", args.model)

try:
import tflite_runtime.interpreter as tflite
interpreter = tflite.Interpreter(model_path=model_path)
except ImportError:
try:
import tensorflow as tf
interpreter = tf.lite.Interpreter(model_path=model_path)
except ImportError as exc:
raise RuntimeError(
"Failed to import both tflite_runtime and tensorflow. "
"Please install either the tflite extra or tensorflow."
) from exc

interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()

node = Node(args.name)
pa.array([])

for event in node:
event_type = event["type"]

if event_type == "INPUT":
event_id = event["id"]

if event_id == "tensor":
storage = event["value"]
input_data = storage.to_numpy().astype(input_details[0]["dtype"])
input_shape = input_details[0]["shape"]
input_data = input_data.reshape(input_shape)

interpreter.set_tensor(input_details[0]["index"], input_data)
interpreter.invoke()

output_data = interpreter.get_tensor(output_details[0]["index"])
result = pa.array(output_data.ravel())

node.send_output("inference", result, event["metadata"])

elif event_type == "ERROR":
print(f"Received dora error: {event['error']}")


if __name__ == "__main__":
main()
31 changes: 31 additions & 0 deletions node-hub/dora-tflite/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[project]
name = "dora-tflite"
version = "0.0.1"
authors = [
{ name = "Hari L", email = "harilogesh2019@gmail.com" },
]
description = "Dora Node for edge inference using TensorFlow Lite for constrained devices"
license = { text = "MIT" }
readme = "README.md"
requires-python = ">=3.9"
dependencies = [
"dora-rs >= 0.4.0",
"numpy>=1.24.4",
]

[project.optional-dependencies]
tflite = ["tflite-runtime >= 2.14.0"]

dev = [
"pytest>=8.1.1",
"ruff>=0.9.1"
]
[project.scripts]
dora-tflite = "dora_tflite.main:main"

[tool.ruff]
target-version = "py39"

[tool.ruff.lint]
select = ["E", "F", "I"]
ignore = []
Empty file.
35 changes: 35 additions & 0 deletions node-hub/dora-tflite/tests/test_tflite_node.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Tests for dora-tflite inference node."""

import numpy as np
import pytest

from dora_tflite.main import main


def test_input_reshape():
"""Test that input data reshapes correctly to model input shape."""
input_shape = [1, 224, 224, 3]
dummy_data = np.random.rand(224 * 224 * 3).astype(np.float32)
reshaped = dummy_data.reshape(input_shape)
assert reshaped.shape == tuple(input_shape)


def test_output_ravel():
"""Test that output tensor flattens correctly for pyarrow serialization."""
dummy_output = np.array([[0.1, 0.9]], dtype=np.float32)
raveled = dummy_output.ravel()
assert len(raveled) == 2
assert abs(raveled[0] - 0.1) < 1e-5


def test_dtype_cast():
"""Test that input data is cast to correct dtype."""
data = np.array([1.0, 2.0, 3.0], dtype=np.float64)
casted = data.astype(np.float32)
assert casted.dtype == np.float32


def test_import_main():
"""Smoke test: main() should raise SystemExit or RuntimeError outside Dora dataflow."""
with pytest.raises((SystemExit, RuntimeError)):
main()
Loading