Skip to content

Commit

Permalink
Add NLU audio
Browse files Browse the repository at this point in the history
  • Loading branch information
titilambert committed Sep 4, 2016
1 parent ccc5522 commit fdce4cb
Show file tree
Hide file tree
Showing 9 changed files with 454 additions and 20 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ pyaudio==0.2.8
git+https://github.com/NuanceDev/pyspeex.git@0.9.0#egg=pyspeex
SpeechRecognition==3.4.6
pocketsphinx==0.1.1
agecalc==3.5.2
36 changes: 36 additions & 0 deletions tuxeatpi/actions/tux.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,39 @@ def get_uptime(self, print_it=False, text_it=False, say_it=False):
self.tuxdroid.say(text)
if text_it is True:
return text

def get_age(self, print_it=False, text_it=False, say_it=False):
"""Return tux age"""
years, months, days = self.tuxdroid.get_age()

if years is None and months is None:
if days <= 1:
text = gtt("I'm {} day old").format(days)
else:
text = gtt("I'm {} days old").format(days)
elif years == 0:
if months == 1:
text = gtt("I'm {} month old").format(months)
else:
text = gtt("I'm {} months old").format(months)
elif years == 1:
if months == 0:
text = gtt("I'm {} year").format(years, months)
elif months == 1:
text = gtt("I'm {} year and {} month").format(years, months)
else:
text = gtt("I'm {} year and {} months").format(years, months)
else:
if months == 0:
text = gtt("I'm {} years").format(years, months)
elif months == 1:
text = gtt("I'm {} years and {} month").format(years, months)
else:
text = gtt("I'm {} years and {} months").format(years, months)

if print_it is True:
print(text)
if say_it is True:
self.tuxdroid.say(text)
if text_it is True:
return text
88 changes: 86 additions & 2 deletions tuxeatpi/hotword/hotword.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,32 @@

import os
from multiprocessing import Process
import wave

import pyaudio
from pocketsphinx.pocketsphinx import Decoder

from tuxeatpi.libs.lang import gtt
from tuxeatpi.nlu.audio import nlu_audio


class HotWord(Process):
"""Define hotword component
For now hotword uses pocketsphinx with speech_recognition
"""
def __init__(self, settings, tts_queue, logger):
def __init__(self, settings, action_queue, tts_queue, logger):
Process.__init__(self)
# Set logger
self.logger = logger.getChild("Hotword")
self.logger.debug("Initialization")
self.tts_queue = tts_queue
self.action_queue = action_queue
# Init private attributes
self._settings = settings
self._must_run = True
self._rerun = True
self._answer_sound_path = "sounds/answer.wav"
self._config = Decoder.default_config()
if not self.prepare_decoder():
self._must_run = False
Expand Down Expand Up @@ -57,12 +61,57 @@ def prepare_decoder(self):
self._decoder.set_keyphrase('wakeup', self._hotword)
self._decoder.set_search('wakeup')

def _say(self, text):
"""Put text in tts queue"""
self.tts_queue.put(text)

def _run_action(self, action, method, args, print_it=False, text_it=True, say_it=False):
"""Put action in action queue"""
data = {"action": action,
"method": method,
"args": args,
"print_it": print_it,
"text_it": text_it,
"say_it": say_it,
}
self.action_queue.put(data)

def misunderstand(self, confidence, text_it=False, say_it=False):
"""bad understanding"""
# TODO add text_it and say_it
msg = ''
if confidence < 0.8 and confidence > 0.5:
msg = gtt("I need a confirmation, Could you repeat please ?")
self.logger.warning("NLU: misunderstood: {}".format(msg))
# TODO ask a confirmation
if confidence < 0.5:
msg = gtt("Sorry, I just don't get it")
self.logger.warning("NLU: misunderstood: {}".format(msg))
if say_it is True:
self._say(msg)
if text_it is True:
return msg
# TODO say it

def stop(self):
"""Stop process"""
self._must_run = False
self._rerun = False
self.terminate()

def _answering(self):
"""Play the hotwoard confirmation sound"""
f_ans = wave.open(self._answer_sound_path, "rb")
stream = self._paudio.open(format=self._paudio.get_format_from_width(f_ans.getsampwidth()),
channels=f_ans.getnchannels(),
rate=f_ans.getframerate(),
output=True)
data = f_ans.readframes(1024)
while len(data) > 0:
stream.write(data)
data = f_ans.readframes(1024)
f_ans.close()

def run(self):
"""Text to speech"""
self._rerun = True
Expand All @@ -80,9 +129,44 @@ def run(self):
while self._must_run:
buf = stream.read(1024)
self._decoder.process_raw(buf, False, False)
if not self.tts_queue.empty():
# If tts_queue is not empty, this means the Droid
# is currently speaking. So we don't want to it listen itself
# TODO replace this stuff by speaker annulation
continue
if self._decoder.hyp() and self._decoder.hyp().hypstr == self._hotword:
self.logger.debug("Hotword detected")
self.tts_queue.put(gtt(self._answer))
# self.tts_queue.put(gtt(self._answer))
# self.tts_queue.put(gtt("mmm"))
self._answering()
ret = nlu_audio(self._settings, self.logger)

# GOT ACTIONS
interpretations = ret.get("nlu_interpretation_results", {}).\
get("payload", {}).get("interpretations", {})
# TODO: what about if len(interpretations) > 1 ??
for interpretation in interpretations:
intent = interpretation.get("action", {}).get("intent", {})
self.logger.info("Intent: {}".format(intent.get("value")))
self.logger.info("Confidence: {}".format(intent.get("confidence")))
# TODO log arguments
if intent.get("value") == "NO_MATCH":
# I don't understand :/
self.misunderstand(0, True, True)
elif intent.get("confidence") < 0.8:
# I'm not sure to undestand :/
self.misunderstand(intent.get("confidence"), True, True)
else:
# Check intent name
if len(intent.get("value").split("__")) != 2:
self.logger.critical("BAD Intent name: "
"{}".format(intent.get("value")))
self.misunderstand(0, True, True)
# Run function with parameters
action, method = intent.get("value").split("__")
# Run action
# TODO add parameters from NLU response
self._run_action(action, method, {}, False, True, True)
# TODO run nlu audio detection
self._rerun = True
break
Expand Down
22 changes: 16 additions & 6 deletions tuxeatpi/libs/lang.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
"""Module handling i18n and l10n for tuxeatpi"""
import gettext
import locale


LANGUAGES = {}
LANGUAGES = {'eng-USA': {'gettext': None,
'locale': 'en_US.UTF-8'},
'fra-FRA': {'gettext': None,
'locale': 'fr_FR.UTF-8'},
'fra-CAN': {'gettext': None,
'locale': 'fr_CA.UTF-8'},
}

_GTT = None


Expand All @@ -19,13 +27,13 @@ def load_languages():
localedir='tuxeatpi/locale',
languages=['en'],
fallback=True)
LANGUAGES['eng-USA'] = _lang_en
LANGUAGES['eng-USA']['gettext'] = _lang_en
try:
_lang_fr = gettext.translation('tuxeatpi',
localedir='tuxeatpi/locale',
languages=['fr'])
LANGUAGES['fra-FRA'] = _lang_fr
LANGUAGES['fra-CAN'] = _lang_fr
LANGUAGES['fra-FRA']['gettext'] = _lang_fr
LANGUAGES['fra-CAN']['gettext'] = _lang_fr
except OSError:
pass

Expand All @@ -35,8 +43,10 @@ def set_language(lang):
global _GTT # pylint: disable=W0603
if lang not in LANGUAGES:
raise Exception("Language not supported")
LANGUAGES[lang].install('tuxeatpi')
_GTT = LANGUAGES[lang].gettext
LANGUAGES[lang]['gettext'].install('tuxeatpi')
_GTT = LANGUAGES[lang]['gettext'].gettext
# TODO
locale.setlocale(locale.LC_TIME, LANGUAGES[lang]['locale'])


def gtt(message):
Expand Down
46 changes: 43 additions & 3 deletions tuxeatpi/locale/en/LC_MESSAGES/tuxeatpi.po
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2016-08-30 17:25-0400\n"
"POT-Creation-Date: 2016-09-03 18:20-0400\n"
"PO-Revision-Date: 2016-08-29 23:41-0400\n"
"Last-Translator: \n"
"Language-Team: \n"
Expand All @@ -25,10 +25,50 @@ msgstr "My name is {}"
msgid "I'm born on {}"
msgstr "I'm born on {}"

#: tuxeatpi/nlu/nlu.py:51
#: tuxeatpi/actions/tux.py:85
msgid "I'm {} day old"
msgstr ""

#: tuxeatpi/actions/tux.py:87
msgid "I'm {} days old"
msgstr ""

#: tuxeatpi/actions/tux.py:89
msgid "I'm {} month old"
msgstr ""

#: tuxeatpi/actions/tux.py:91
msgid "I'm {} months old"
msgstr ""

#: tuxeatpi/actions/tux.py:94
msgid "I'm {} year"
msgstr ""

#: tuxeatpi/actions/tux.py:96
msgid "I'm {} year and {} month"
msgstr ""

#: tuxeatpi/actions/tux.py:98
msgid "I'm {} year and {} months"
msgstr ""

#: tuxeatpi/actions/tux.py:101
msgid "I'm {} years"
msgstr ""

#: tuxeatpi/actions/tux.py:103
msgid "I'm {} years and {} month"
msgstr ""

#: tuxeatpi/actions/tux.py:105
msgid "I'm {} years and {} months"
msgstr ""

#: tuxeatpi/hotword/hotword.py:86 tuxeatpi/nlu/nlu.py:51
msgid "I need a confirmation, Could you repeat please ?"
msgstr "I need a confirmation, Could you repeat please ?"

#: tuxeatpi/nlu/nlu.py:55
#: tuxeatpi/hotword/hotword.py:90 tuxeatpi/nlu/nlu.py:55
msgid "Sorry, I just don't get it"
msgstr "Sorry, I just don't get it"
50 changes: 45 additions & 5 deletions tuxeatpi/locale/fr/LC_MESSAGES/tuxeatpi.po
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2016-08-30 17:25-0400\n"
"PO-Revision-Date: 2016-08-29 22:46-0400\n"
"POT-Creation-Date: 2016-09-03 18:20-0400\n"
"PO-Revision-Date: 2016-09-04 10:29-0400\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr_FR\n"
Expand All @@ -23,13 +23,53 @@ msgstr "Mon nom est {}"

#: tuxeatpi/actions/tux.py:45
msgid "I'm born on {}"
msgstr "Je suis né {}"
msgstr "Je suis né le {}"

#: tuxeatpi/nlu/nlu.py:51
#: tuxeatpi/actions/tux.py:85
msgid "I'm {} day old"
msgstr "J'ai {} jour"

#: tuxeatpi/actions/tux.py:87
msgid "I'm {} days old"
msgstr "J'ai {} jours"

#: tuxeatpi/actions/tux.py:89
msgid "I'm {} month old"
msgstr "J'ai {} mois"

#: tuxeatpi/actions/tux.py:91
msgid "I'm {} months old"
msgstr "J'ai {} mois"

#: tuxeatpi/actions/tux.py:94
msgid "I'm {} year"
msgstr "J'ai {} an"

#: tuxeatpi/actions/tux.py:96
msgid "I'm {} year and {} month"
msgstr "J'ai {} an et {} mois"

#: tuxeatpi/actions/tux.py:98
msgid "I'm {} year and {} months"
msgstr "J'ai {} an et {} mois"

#: tuxeatpi/actions/tux.py:101
msgid "I'm {} years"
msgstr "J'ai {} ans"

#: tuxeatpi/actions/tux.py:103
msgid "I'm {} years and {} month"
msgstr "J'ai {} ans et {} mois"

#: tuxeatpi/actions/tux.py:105
msgid "I'm {} years and {} months"
msgstr "J'ai {} ans et {} mois"

#: tuxeatpi/hotword/hotword.py:86 tuxeatpi/nlu/nlu.py:51
msgid "I need a confirmation, Could you repeat please ?"
msgstr "J'ai besoin d'une confirmation, Pouvez vous répéter s'il vous plait ?"

#: tuxeatpi/nlu/nlu.py:55
#: tuxeatpi/hotword/hotword.py:90 tuxeatpi/nlu/nlu.py:55
msgid "Sorry, I just don't get it"
msgstr "Désolé, je ne comprends pas"

Expand Down

0 comments on commit fdce4cb

Please sign in to comment.