Skip to content
Closed
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
14 changes: 5 additions & 9 deletions client/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,18 @@ def handleForever(self):
for notif in notifications:
self._logger.info("Received notification: '%s'", str(notif))

self._logger.debug("Started listening for keyword '%s'",
self.persona)
self._logger.debug("Started listening for keyword '%s'", self.persona)
threshold, transcribed = self.mic.passiveListen(self.persona)
self._logger.debug("Stopped listening for keyword '%s'",
self.persona)
self._logger.debug("Stopped listening for keyword '%s'", self.persona)

if not transcribed or not threshold:
self._logger.info("Nothing has been said or transcribed.")
continue
self._logger.info("Keyword '%s' has been said!", self.persona)

self._logger.debug("Started to listen actively with threshold: %r",
threshold)
self._logger.info("Keyword '%s' has been said!", self.persona)
self._logger.debug("Started to listen actively with threshold: %r", threshold)
input = self.mic.activeListenToAllOptions(threshold)
self._logger.debug("Stopped to listen actively with threshold: %r",
threshold)
self._logger.debug("Stopped to listen actively with threshold: %r", threshold)

if input:
self.brain.query(input)
Expand Down
9 changes: 6 additions & 3 deletions client/modules/Unclear.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ def handle(text, mic, profile):
number)
"""

messages = ["I'm sorry, could you repeat that?",
"My apologies, could you try saying that again?",
"Say that again?", "I beg your pardon?"]
messages = [
"I'm sorry, could you repeat that?",
"My apologies, could you try saying that again?",
"Say that again?",
"I beg your pardon?"
]

message = random.choice(messages)

Expand Down
139 changes: 138 additions & 1 deletion client/stt.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,143 @@ def is_available(cls):
return diagnose.check_network_connection()


class WatsonSTT(AbstractSTTEngine):
"""
Speech-To-Text implementation which relies on the IBM Watson Speech-To-Text
API. This requires an IBM Bluemix account, but the first 1000 minutes of
transcribing per month are free.

To obtain a login:
1. Register for IBM Bluemix here:
https://console.ng.bluemix.net/registration/
2. Once you've logged in, click the "Use Services & APIs" link on the
dashboard
3. Click the "Speech To Text" icon
4. In the form on the right, leave all options as defaults and click Create
5. You'll now have a new service listed on your dashboard. If you click
that service there will be a navigation option for "Service Credentials"
in the left hand nav. Find your username and password there.

Excerpt from sample profile.yml:

...
timezone: US/Pacific
stt_engine: watson
watson:
username: $YOUR_USERNAME_HERE
password: $YOUR_PASSWORD_HERE

"""

SLUG = 'watson'

def __init__(self, username=None, password=None, language='en-us'):
# FIXME: get init args from config
"""
Arguments:
username - the watson api username credential
password - the watson api password credential
"""
self._logger = logging.getLogger(__name__)
self._username = None
self._password = None
self._http = requests.Session()
self.username = username
self.password = password

@property
def request_url(self):
return self._request_url

@property
def username(self):
return self._username

@username.setter
def username(self, value):
self._username = value

@property
def password(self):
return self._password

@password.setter
def password(self, value):
self._password = value

@classmethod
def get_config(cls):
# FIXME: Replace this as soon as we have a config module
config = {}
# HMM dir
# Try to get hmm_dir from config
profile_path = jasperpath.config('profile.yml')
if os.path.exists(profile_path):
with open(profile_path, 'r') as f:
profile = yaml.safe_load(f)
if 'watson' in profile:
if 'username' in profile['watson']:
config['username'] = profile['watson']['username']
if 'password' in profile['watson']:
config['password'] = profile['watson']['password']
return config

def transcribe(self, fp):
"""
Performs STT via the Watson Speech-to-Text API, transcribing an audio
file and returning an English string.

Arguments:
fp -- the path to the .wav file to be transcribed
"""

if not self.username:
self._logger.critical('Username missing, transcription request aborted.')
return []
elif not self.password:
self._logger.critical('Password missing, transcription request aborted.')
return []

wav = wave.open(fp, 'rb')
frame_rate = wav.getframerate()
wav.close()
data = fp.read()

headers = {
'content-type': 'audio/l16; rate={0}; channels=1'.format(frame_rate)
}
r = self._http.post(
'https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true',
data=data, headers=headers, auth=(self.username, self.password)
)
try:
r.raise_for_status()
except requests.exceptions.HTTPError as e:
self._logger.critical('Request failed with http status %d',
r.status_code)
if r.status_code == requests.codes['forbidden']:
self._logger.warning('Status 403 is probably caused by invalid credentials.')
return []
r.encoding = 'utf-8'
results = []
try:
response = r.json()
if not response['results']:
raise ValueError('Nothing has been transcribed.')
results = tuple([alt['transcript'].strip().upper() for alt in response['results'][0]['alternatives']])
self._logger.info('Transcribed: %r', results)
except ValueError as e:
self._logger.critical('Empty response: %s', e.args[0])
except (KeyError, IndexError):
self._logger.critical('Cannot parse response.', exc_info=True)

return results

@classmethod
def is_available(cls):
return diagnose.check_network_connection()


class AttSTT(AbstractSTTEngine):
"""
Speech-To-Text implementation which relies on the AT&T Speech API.
Expand Down Expand Up @@ -587,7 +724,7 @@ def headers(self):

def transcribe(self, fp):
data = fp.read()
r = requests.post('https://api.wit.ai/speech?v=20150101',
r = requests.post('https://api.wit.ai/speech?v=20160526',
data=data,
headers=self.headers)
try:
Expand Down
9 changes: 4 additions & 5 deletions jasper.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,13 @@ def __init__(self):

def run(self):
if 'first_name' in self.config:
salutation = ("How can I be of service, %s?"
% self.config["first_name"])
salutation = "Hey, {0}. Glad to see you. How can I help you?".format(self.config["first_name"])
else:
salutation = "How can I be of service?"
salutation = "How can I help you?"
self.mic.say(salutation)

conversation = Conversation("JASPER", self.mic, self.config)
conversation.handleForever()
Conversation(self.config.get('persona', 'jasper').upper(),
self.mic, self.config).handleForever()

if __name__ == "__main__":

Expand Down
34 changes: 34 additions & 0 deletions jessy-notes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Updated URLs

OpenFST:
https://github.com/AdolfVonKleist/Phonetisaurus/tree/openfst-1.5.3

MITLM:
https://github.com/mitlm/mitlm

sudo wget https://m2m-aligner.googlecode.com/files/m2m-aligner-1.2.tar.gz
sudo wget https://www.dropbox.com/s/154q9yt3xenj2gr/phonetisaurus-0.8a.tgz
sudo wget https://phonetisaurus.googlecode.com/files/is2013-conversion.tgz


Installing stuff:
-----------------------------------------
1. sudo su -c "echo 'deb http://cognomen.co.uk/apt/debian jessie main' > /etc/apt/sources.list.d/cognomen.list"

2. gpg --keyserver keyserver.ubuntu.com --recv FC88E181D61C9391C4A49682CF36B219807AA92B && gpg --export --armor [email protected] | sudo apt-key add -

3. sudo apt-get update

4. sudo apt-get install phonetisaurus m2m-aligner mitlm libfst-tools libfst1-plugins-base libfst-dev

5. sudo apt-get install pocketsphinx-hmm-en-hub4wsj



Configure: .jasper/profile.yml:

stt_passive_engine: sphinx
pocketsphinx:
hmm_dir: /usr/share/pocketsphinx/model/hmm/en_US/hub4wsj_sc_8k

--------------------------
Binary file added static/audio/rd2d/begin/R2D2-do.wav
Binary file not shown.
Binary file added static/audio/rd2d/begin/qr2_d2w2.wav
Binary file not shown.
Binary file added static/audio/rd2d/begin/qsntnc1.wav
Binary file not shown.
Binary file added static/audio/rd2d/begin/qword1.wav
Binary file not shown.
Binary file added static/audio/rd2d/begin/qword4.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qr2_d2w1.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qr2_d2w3.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qsntnc10.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qsntnc18.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qsntnc6.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qword16.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qword8.wav
Binary file not shown.
Binary file added static/audio/rd2d/end/qword9.wav
Binary file not shown.
Binary file added static/audio/rd2d/error/qsntnc13.wav
Binary file not shown.
Binary file added static/audio/rd2d/error/qsntnc20.wav
Binary file not shown.
Binary file added static/audio/rd2d/error/qsntnc4.wav
Binary file not shown.
Binary file added static/audio/rd2d/error/qsntnc7.wav
Binary file not shown.
Binary file added static/audio/rd2d/error/qsntnc9.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/R2D2-yeah.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qr2_d2s1.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qr2_d2s2.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qr2_d2s3.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qscaning.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qsntnc16.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qsntnc2.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qsntnc8.wav
Binary file not shown.
Binary file added static/audio/rd2d/idle/qword22.wav
Binary file not shown.