| @@ -37,23 +37,8 @@ jobs: | |||||
| - name: Run Linting and Tests | - name: Run Linting and Tests | ||||
| run: | | run: | | ||||
| for dir in node-hub/*/ ; do | |||||
| if [ -d "$dir" ]; then | |||||
| if [ -f "$dir/pyproject.toml" ]; then | |||||
| echo "Running linting and tests for Python project in $dir..." | |||||
| (cd "$dir" && pip install .) | |||||
| (cd "$dir" && poetry run black --check .) | |||||
| (cd "$dir" && poetry run pylint --disable=C,R --ignored-modules=cv2 **/*.py) | |||||
| (cd "$dir" && poetry run pytest) | |||||
| fi | |||||
| if [ -f "$dir/Cargo.toml" ]; then | |||||
| echo "Running build and tests for Rust project in $dir..." | |||||
| (cd "$dir" && cargo build) | |||||
| (cd "$dir" && cargo test) | |||||
| fi | |||||
| fi | |||||
| done | |||||
| chmod +x .github/workflows/node_hub_test.sh | |||||
| .github/workflows/node_hub_test.sh | |||||
| publish: | publish: | ||||
| needs: [ci] | needs: [ci] | ||||
| @@ -0,0 +1,20 @@ | |||||
| #!/bin/bash | |||||
| set -euo | |||||
| for dir in node-hub/*/ ; do | |||||
| if [ -d "$dir" ]; then | |||||
| if [ -f "$dir/pyproject.toml" ]; then | |||||
| echo "Running linting and tests for Python project in $dir..." | |||||
| (cd "$dir" && pip install .) | |||||
| (cd "$dir" && poetry run black --check .) | |||||
| (cd "$dir" && poetry run pylint --disable=C,R --ignored-modules=cv2 **/*.py) | |||||
| (cd "$dir" && poetry run pytest) | |||||
| fi | |||||
| if [ -f "$dir/Cargo.toml" ]; then | |||||
| echo "Running build and tests for Rust project in $dir..." | |||||
| (cd "$dir" && cargo build) | |||||
| (cd "$dir" && cargo test) | |||||
| fi | |||||
| fi | |||||
| done | |||||
| @@ -1,5 +1,5 @@ | |||||
| from pynput import keyboard | from pynput import keyboard | ||||
| from pynput.keyboard import Key, Events | |||||
| from pynput.keyboard import Events | |||||
| import pyarrow as pa | import pyarrow as pa | ||||
| from dora import Node | from dora import Node | ||||
| @@ -32,6 +32,7 @@ def main(): | |||||
| silence_start_time = tm.time() | silence_start_time = tm.time() | ||||
| node = Node() | node = Node() | ||||
| # pylint: disable=unused-argument | |||||
| def callback(indata, frames, time, status): | def callback(indata, frames, time, status): | ||||
| nonlocal buffer, state, silence_start_time, node | nonlocal buffer, state, silence_start_time, node | ||||
| @@ -1,11 +0,0 @@ | |||||
| import os | |||||
| # Define the path to the README file relative to the package directory | |||||
| readme_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "README.md") | |||||
| # Read the content of the README file | |||||
| try: | |||||
| with open(readme_path, "r", encoding="utf-8") as f: | |||||
| __doc__ = f.read() | |||||
| except FileNotFoundError: | |||||
| __doc__ = "README file not found." | |||||
| @@ -1,61 +0,0 @@ | |||||
| import sounddevice as sd | |||||
| import numpy as np | |||||
| import pyarrow as pa | |||||
| import time as tm | |||||
| from enum import Enum | |||||
| from dora import Node | |||||
| class RecordingState(Enum): | |||||
| """Enum for recording states.""" | |||||
| PENDING = 0 | |||||
| RUNNING = 1 | |||||
| SILENCE = 2 | |||||
| def detect_speech(audio_data, threshold): | |||||
| """Check if the amplitude of the audio signal exceeds the threshold.""" | |||||
| return np.any(np.abs(audio_data) > threshold) | |||||
| def main(): | |||||
| # Parameters | |||||
| threshold = 500 # Threshold for detecting speech (adjust this as needed) | |||||
| SAMPLE_RATE = 16000 | |||||
| silence_duration = 4 # Duration of silence before stopping the recording | |||||
| # Initialize buffer and recording flag | |||||
| buffer = [] | |||||
| state = RecordingState.PENDING | |||||
| silence_start_time = tm.time() | |||||
| node = Node() | |||||
| def callback(indata, frames, time, status): | |||||
| nonlocal buffer, state, silence_start_time, node | |||||
| is_speaking = detect_speech(indata[:, 0], threshold) | |||||
| if is_speaking: | |||||
| if state == RecordingState.PENDING: | |||||
| buffer = [] | |||||
| state = RecordingState.RUNNING | |||||
| buffer.extend(indata[:, 0]) | |||||
| elif not is_speaking and state == RecordingState.RUNNING: | |||||
| silence_start_time = tm.time() # Reset silence timer | |||||
| buffer.extend(indata[:, 0]) | |||||
| state = RecordingState.SILENCE | |||||
| elif not is_speaking and state == RecordingState.SILENCE: | |||||
| if tm.time() - silence_start_time > silence_duration: | |||||
| audio_data = np.array(buffer).ravel().astype(np.float32) / 32768.0 | |||||
| node.send_output("audio", pa.array(audio_data)) | |||||
| state = RecordingState.PENDING | |||||
| else: | |||||
| buffer.extend(indata[:, 0]) | |||||
| # Start recording | |||||
| with sd.InputStream( | |||||
| callback=callback, dtype=np.int16, channels=1, samplerate=SAMPLE_RATE | |||||
| ): | |||||
| while True: | |||||
| sd.sleep(int(100 * 1000)) | |||||
| @@ -0,0 +1,2 @@ | |||||
| def test_placeholder(): | |||||
| pass | |||||
| @@ -44,9 +44,8 @@ def main(): | |||||
| ) | ) | ||||
| try: | try: | ||||
| data = ast.literal_eval(data) | data = ast.literal_eval(data) | ||||
| except Exception: | |||||
| except ValueError: | |||||
| print("Passing input as string") | print("Passing input as string") | ||||
| pass | |||||
| if isinstance(data, list): | if isinstance(data, list): | ||||
| data = pa.array(data) # initialize pyarrow array | data = pa.array(data) # initialize pyarrow array | ||||
| elif isinstance(data, str): | elif isinstance(data, str): | ||||
| @@ -0,0 +1,2 @@ | |||||
| def test_placeholder(): | |||||
| pass | |||||