diff --git a/data/hello.mp3 b/data/hello.mp3 new file mode 100644 index 0000000..d584cf3 Binary files /dev/null and b/data/hello.mp3 differ diff --git a/dev_requirements.in b/dev_requirements.in new file mode 100644 index 0000000..9aa1b14 --- /dev/null +++ b/dev_requirements.in @@ -0,0 +1,2 @@ +black +pip-tools diff --git a/dev_requirements.txt b/dev_requirements.txt new file mode 100644 index 0000000..ce1c082 --- /dev/null +++ b/dev_requirements.txt @@ -0,0 +1,41 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile dev_requirements.in +# +black==22.10.0 + # via -r dev_requirements.in +build==0.9.0 + # via pip-tools +click==8.1.3 + # via + # black + # pip-tools +mypy-extensions==0.4.3 + # via black +packaging==21.3 + # via build +pathspec==0.10.2 + # via black +pep517==0.13.0 + # via build +pip-tools==6.10.0 + # via -r dev_requirements.in +platformdirs==2.5.4 + # via black +pyparsing==3.0.9 + # via packaging +tomli==2.0.1 + # via + # black + # build + # pep517 +typing-extensions==4.4.0 + # via black +wheel==0.38.4 + # via pip-tools + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/play_audio/simple_play.py b/play_audio/simple_play.py index d3c0118..355c47b 100644 --- a/play_audio/simple_play.py +++ b/play_audio/simple_play.py @@ -1,6 +1,6 @@ import simpleaudio as sa -filename = 'myfile.wav' +filename = './data/hello.wav' wave_obj = sa.WaveObject.from_wave_file(filename) play_obj = wave_obj.play() play_obj.wait_done() # Wait until sound has finished playing \ No newline at end of file diff --git a/say b/say new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/say @@ -0,0 +1 @@ + diff --git a/socket_send_recieve/sender.py b/socket_send_recieve/sender.py index 4a44160..3ee8dfa 100644 --- a/socket_send_recieve/sender.py +++ b/socket_send_recieve/sender.py @@ -12,7 +12,7 @@ wave_file_path = sys.argv[1] if not wave_file_path.endswith('.wav'): raise ValueError("File must have .wav file extension.") -(HOST,PORT)=('rospi.runcible.io',9000) +(HOST,PORT)=('localhost',9000) s=socket.socket(socket.AF_INET,socket.SOCK_STREAM); s.connect((HOST,PORT)) with open(wave_file_path, 'rb') as wave_file: diff --git a/speech_recog/requirement.in b/speech_recog/requirement.in new file mode 100644 index 0000000..3afeebf --- /dev/null +++ b/speech_recog/requirement.in @@ -0,0 +1,3 @@ +pyaudio +SpeechRecognition +gTTs \ No newline at end of file diff --git a/speech_recog/requirement.txt b/speech_recog/requirement.txt new file mode 100644 index 0000000..c5f16db --- /dev/null +++ b/speech_recog/requirement.txt @@ -0,0 +1,26 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile requirement.in +# +certifi==2022.9.24 + # via requests +charset-normalizer==2.1.1 + # via requests +click==8.1.3 + # via gtts +gtts==2.2.4 + # via -r requirement.in +idna==3.4 + # via requests +pyaudio==0.2.12 + # via -r requirement.in +requests==2.28.1 + # via gtts +six==1.16.0 + # via gtts +speechrecognition==3.8.1 + # via -r requirement.in +urllib3==1.26.12 + # via requests diff --git a/speech_recog/virtual_assistant.py b/speech_recog/virtual_assistant.py new file mode 100644 index 0000000..7a07ee0 --- /dev/null +++ b/speech_recog/virtual_assistant.py @@ -0,0 +1,102 @@ +import webbrowser +import typing +import os +import sys +from abc import ABC, abstractmethod + +import speech_recognition as sr + +class Action(ABC): + + action_key: str + + @abstractmethod + def action_callback(self, action_text) -> typing.Any: + pass + + def register_va(self, virtual_assisant): + self._va = virtual_assisant + + def sans_action_key(self, action_text): + return action_text[len(self.action_key)+1:] + +class BrowserAction(Action): + + action_key = "open browser" + + def action_callback(self, action_text): + domain = self.sans_action_key(action_text) + url = f"https://{domain}" + print(f"Opening: {url}") + self._va.("Opening {domain}") + webbrowser.open(url) + +class EchoAction(Action): + + action_key = "echo" + + def action_callback(self, action_text) -> typing.Any: + print(action_text) + self._va.text_to_speech(self.sans_action_key(action_text)) + +class StopAction(Action): + + action_key = "stop listening" + + def action_callback(self, action_text) -> typing.Any: + print("Stopping Virtual Assistant...") + sys.exit(0) + + +class VirtualAssistant: + + def __init__(self, timeout: int = 3, actions: typing.List[Action]=[]): + self.listener = sr.Recognizer() + self.timeout = timeout + self.action_register = [] + for action in actions: + self.register_action(action) + + def register_action(self, action: Action): + """Adds new Action instances to the Virtual Assistant's action register.""" + self.action_register.append(action) + action.register_va(self) + + def parse_action(self, text: str): + """Checks the VA command register and executes callbacks when found.""" + for action in self.action_register: + if text.lower().startswith(action.action_key): + action.action_callback(text) + return + print(f"No actions taken on: {text}") + + def speech_to_text(self) -> str: + """""" + try: + with sr.Microphone() as mic: + print("Arni is listening...") + self.listener.adjust_for_ambient_noise(mic) + utterance = self.listener.listen(mic, timeout=self.timeout) + content = self.listener.recognize_google(utterance) + return content + except (sr.UnknownValueError, sr.RequestError, sr.WaitTimeoutError): + return "" + + def text_to_speech(self, text: str): + print(f"Saying: {text}") + cmd = f'gtts-cli --nocheck "{text}" | mpg123 -q -' + print(cmd) + os.system(cmd) + + + +def main(): + print("Creating virtual assistant...") + va = VirtualAssistant(actions=[BrowserAction(),EchoAction(), StopAction()]) + # breakpoint() + while True: + content = va.speech_to_text() + va.parse_action(content) + +if __name__ == "__main__": + main() \ No newline at end of file