From 15f369446cbbe768b150759f4a11605c76384695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torma=20Krist=C3=B3f?= Date: Tue, 25 Aug 2020 01:40:09 +0200 Subject: [PATCH] wire it all together --- requirements.txt | 21 +++++++++++++++ src/app.py | 19 +++++++++++--- src/preprocessor/soundpreprocessor.py | 27 ++++++++++++++++++-- src/sender/soundsender.py | 23 +++++++++++++++-- src/sensor/soundsensor.py | 6 +++-- src/signal_processor/soundsignalprocessor.py | 16 +++++++++++- src/utils/__init__.py | 2 +- src/utils/config.py | 12 ++++++++- 8 files changed, 114 insertions(+), 12 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5051901..9ca9f42 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,22 @@ sentry_sdk +requests + +cython + +cycler==0.10.0 +deprecation==2.0.7 +eyeD3==0.9.5 +filetype==1.0.6 +hmmlearn==0.2.3 +joblib==0.14.1 +kiwisolver==1.2.0 +matplotlib==3.2.1 +numpy==1.18.2 +pyAudioAnalysis==0.3.0 +pydub==0.23.1 +pyparsing==2.4.6 +python-dateutil==2.8.1 +scikit-learn==0.21.3 +scipy==1.4.1 +simplejson==3.17.0 +six==1.14.0 \ No newline at end of file diff --git a/src/app.py b/src/app.py index 7cc9d87..c79cef8 100644 --- a/src/app.py +++ b/src/app.py @@ -2,7 +2,8 @@ import logging import sentry_sdk from sentry_sdk.integrations.logging import LoggingIntegration -from utils import config +from utils import config, LoopingTimer +from signal_processor import SoundSignalProcessor """ Main Entrypoint @@ -30,12 +31,24 @@ if config.SENTRY_DSN: ) -def main(): +def timer_tick(*args) -> None: + """ + Tick of a timer + :param listofabcsignaprocessors: + :return: + """ + for abcsignaprocessor in args: + abcsignaprocessor.processcurrentsignal() + + +def main() -> None: """ Main function :return: """ - pass + listofabcsignaprocessors = [SoundSignalProcessor()] + loopingtimer = LoopingTimer(function=timer_tick, args=[listofabcsignaprocessors], interval=config.TICK_INTERVAL) + loopingtimer.start() if __name__ == "__main__": diff --git a/src/preprocessor/soundpreprocessor.py b/src/preprocessor/soundpreprocessor.py index b86b9aa..5f828aa 100644 --- a/src/preprocessor/soundpreprocessor.py +++ b/src/preprocessor/soundpreprocessor.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +import requests +from pyAudioAnalysis import audioTrainTest as aT +from pyAudioAnalysis.audioTrainTest import load_model, load_model_knn +from utils import config from .abcpreprocessor import AbcPreProcessor """ @@ -15,9 +19,28 @@ class SoundPreProcessor(AbcPreProcessor): """ SoundPreProcessor class, responsible for detecting birb chirps in sound sample. """ - def preprocesssignal(self, signal): + + def preprocesssignal(self, signal: str) -> bool: """ Classify a sound sample. + :param signal: Access path of the sound sample up for processing. :return: """ - pass + # TODO: Dynamic model injection? + r = requests.get(f"http://model-service/model/{config.MODEL_ID}/details") + r.raise_for_status() + + model_details = r.json() + + if model_details['type'] == 'knn': + classifier, mean, std, classes, mid_window, mid_step, short_window, short_step, compute_beat \ + = load_model_knn(config.MODEL_ID + "MEANS") + + else: + classifier, mean, std, classes, mid_window, mid_step, short_window, short_step, compute_beat \ + = load_model(config.MODEL_ID + "MEANS") + + target_id = classes.index(config.TARGET_NAME) + + class_id, probability = aT.file_classification(signal, config.MODEL_ID, "svm") + return class_id == target_id diff --git a/src/sender/soundsender.py b/src/sender/soundsender.py index b627372..40dd0bc 100644 --- a/src/sender/soundsender.py +++ b/src/sender/soundsender.py @@ -1,5 +1,11 @@ #!/usr/bin/env python3 +import os +import json +import logging +from datetime import datetime +import requests from .abcsender import AbcSender +from utils import config """ Send a sound sample @@ -15,9 +21,22 @@ class SoundSender(AbcSender): """ SoundSender class, responsible for sending sound samples to the cloud. """ - def sendvalue(self, value, decision): + + def sendvalue(self, value: str, decision: bool) -> None: """ Send a sound sample to the cloud. :return: """ - pass + if decision: + files = { + "file": (os.path.basename(value), open(value, 'rb').read(), 'audio/wave', + {'Content-length': os.path.getsize(value)}), + "description": ( + None, json.dumps({'date': datetime.now().isoformat(), 'device_id': config.DEVICE_ID}), + "application/json") + } + + r = requests.post(config.INPUT_SVC_URL, files=files) + logging.info("Content: ", r.content) + logging.info("Headers:", r.headers) + r.raise_for_status() diff --git a/src/sensor/soundsensor.py b/src/sensor/soundsensor.py index 3765b21..e6257d7 100644 --- a/src/sensor/soundsensor.py +++ b/src/sensor/soundsensor.py @@ -15,9 +15,11 @@ class SoundSensor(AbcSensor): """ SoundSensor class. Responsible for sound retrieval from any microphones present. """ - def getvalue(self): + def getvalue(self) -> str: """ Retrieve a 5 second sound clip from a microphone. :return: """ - pass + # Recieve sound from microphone and save it to a file on the filesystem. + # Then return the filename + return "filename.wav" diff --git a/src/signal_processor/soundsignalprocessor.py b/src/signal_processor/soundsignalprocessor.py index 4f18a2a..4895236 100644 --- a/src/signal_processor/soundsignalprocessor.py +++ b/src/signal_processor/soundsignalprocessor.py @@ -1,4 +1,7 @@ #!/usr/bin/env python3 +from sensor import SoundSensor +from sender import SoundSender +from preprocessor import SoundPreProcessor from .abcsignalprocessor import AbcSignalProcessor """ @@ -15,9 +18,20 @@ class SoundSignalProcessor(AbcSignalProcessor): """ SoundSignalProcessor class, responsible for handling the sound signal processor pipeline. """ + + def __init__(self): + """ + Create dependency objects. + """ + self.soundsensor = SoundSensor() + self.soundpreprocessor = SoundPreProcessor() + self.soundsender = SoundSender() + def processcurrentsignal(self): """ Process a sound sample. :return: """ - pass + soundsample_name = self.soundsensor.getvalue() + sample_decision = self.soundpreprocessor.preprocesssignal(soundsample_name) + self.soundsender.sendvalue(soundsample_name, sample_decision) diff --git a/src/utils/__init__.py b/src/utils/__init__.py index 9d7d137..57bbb05 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,2 +1,2 @@ #!/usr/bin/env python3 -from .config import SENTRY_DSN, RELEASE_ID, RELEASEMODE +from .loopingtimer import LoopingTimer diff --git a/src/utils/config.py b/src/utils/config.py index aabbd62..4b1f541 100644 --- a/src/utils/config.py +++ b/src/utils/config.py @@ -12,4 +12,14 @@ __version__text__ = "1" SENTRY_DSN = os.environ.get("SENTRY_DSN") RELEASE_ID = os.environ.get("RELEASE_ID", "test") -RELEASEMODE = os.environ.get("INPUT_SERVICE_RELEASEMODE", "dev") +RELEASEMODE = os.environ.get("RELEASEMODE", "dev") + +DEVICE_ID = os.environ.get("DEVICE_ID", "devraspi") + +TICK_INTERVAL = int(os.environ.get("TICK_INTERVAL", "3")) + + +TARGET_NAME = os.environ.get("TARGET_CLASS_NAME") +MODEL_ID = os.environ.get("MODEL_ID") + +INPUT_SVC_URL = os.environ.get("INPUT_SVC_URL", "http://localhost:8080/sample")