0

I am trying to get a web-socket connection open for a Speech to text recognition on Watson using Python v2.7

My code uses an API key plus a url. I have tried several ways to open a socket using this but I get a web socket error with a stream error as follows:

Failed to open WebSocket.
Failed to open WebSocket.
Traceback (most recent call last): File "jasmineV3.py", line 78, in <module>
    SpeechToTextClient().close() File "jasmineV3.py", line 68, in close
    self.stream_audio_thread.join()
AttributeError: 'SpeechToTextClient' object has no attribute 'stream_audio_thread'

Here is my code that I am attempting to make work:

#import os
#import time
#import json
import watson_developer_cloud
import speech_recognition as sr
from gtts import gTTS
from time import ctime
#from __future__ import print_function

from os.path import join, dirname
from watson_developer_cloud import SpeechToTextV1
from watson_developer_cloud.websocket import RecognizeCallback
from ws4py.client.threadedclient import WebSocketClient
import base64, json, ssl, subprocess, threading, time

class SpeechToTextClient(WebSocketClient):
    def __init__(self):

        speech_to_text = SpeechToTextV1(iam_api_key = 'xxxxxxxx', url = 'xxxxxxx')

        self.listening = False

        try:
            WebSocketClient.__init__(self, speech_to_text)
            self.connect()
        except: print "Failed to open WebSocket."

    def opened(self):
        self.send('{"action": "start", "content-type": "audio/l16;rate=16000"}')
        self.stream_audio_thread = threading.Thread(target=self.stream_audio)
        self.stream_audio_thread.start()

    def received_message(self, message):
        message = json.loads(str(message))
        if "state" in message:
            if message["state"] == "listening":
                self.listening = True
        print "Message received: " + str(message)

    def stream_audio(self):
        while not self.listening:
            time.sleep(0.1)

        reccmd = ["arecord", "-f", "S16_LE", "-r", "16000", "-t", "raw"]
        p = subprocess.Popen(reccmd, stdout=subprocess.PIPE)

        while self.listening:
            data = p.stdout.read(1024)

            try: self.send(bytearray(data), binary=True)
            except ssl.SSLError: pass

        p.kill()

    def close(self):
        self.listening = False
        self.stream_audio_thread.join()
        WebSocketClient.close(self)

try:
    stt_client = SpeechToTextClient()
    #raw_input()
    speech_to_text = SpeechToTextV1(
        iam_api_key = 'xxxxxxxxx',
        url = 'xxxxxxxx')
finally:
    SpeechToTextClient().close()

I am a little lost as to what my mistake is. How can I resolve it?

Update

So after taking feedback in the answers that were posted below, I came up with the following code:

from watson_developer_cloud import SpeechToTextV1
from watson_developer_cloud.websocket import RecognizeCallback
from os.path import join, dirname

import watson_developer_cloud
import speech_recognition as sr
from gtts import gTTS
from time import ctime
from os.path import join, dirname
from watson_developer_cloud import SpeechToTextV1
from ws4py.client.threadedclient import WebSocketClient
import base64, json, ssl, subprocess, threading, time
import os
import json

speech_to_text = SpeechToTextV1(
    username='{username}',
    password='{password}',
    iam_api_key = 'B5AmAyElAbvr6Z6dvW-CufLPwYsmKndNtAiGp4btg6s3',
    url = 'https://gateway-wdc.watsonplatform.net/speech-to-text/api/v1/recognize')

class MyRecognizeCallback(RecognizeCallback):
    def __init__(self):
        RecognizeCallback.__init__(self)

    def on_data(self, data):
        print(json.dumps(data, indent=2))

    def on_error(self, error):
        print('Error received: {}'.format(error))

    def on_inactivity_timeout(self, error):
        print('Inactivity timeout: {}'.format(error))

myRecognizeCallback = MyRecognizeCallback()

with open(join(dirname(__file__), '/home/ironmantis7x/Documents/MaverickAITech/JasmineAI', 'audio.mp3'),
              'rb') as audio_file:
    speech_to_text.recognize_using_websocket(
        audio=audio_file,
        content_type='audio/mp3',
        model='en-US_BroadbandModel',
        recognize_callback=myRecognizeCallback,
        interim_results=False,
        keywords=['hello', 'hi', 'turn on', 'directions'],
        keywords_threshold=0.5,
        max_alternatives=3) 

But now I get the following error:

Traceback (most recent call last):
  File "jasmineV7.py", line 37, in <module>
    speech_to_text.recognize_using_websocket(
AttributeError: 'SpeechToTextV1' object has no attribute 'recognize_using_websocket'

I tried a web search on the error and it's not straightforward what the issue is, nor how to properly fix it.

halfer
  • 19,824
  • 17
  • 99
  • 186
ironmantis7x
  • 807
  • 2
  • 23
  • 58

2 Answers2

0

Your method opened hasn't been called, so when you call close self.stream_audio_thread does not exist.

All probably because your web socket creation has failed. Make your close method safe by checking on the existence of self.stream_audio_thread before running a method on in, and determine why your socket creation is failing.

def close(self):
    self.listening = False
    if self.stream_audio_thread:
        self.stream_audio_thread.join()
    WebSocketClient.close(self)
chughts
  • 4,210
  • 2
  • 14
  • 27
  • thank you. I hate to ask, but can you show me in my code how to fix this? – ironmantis7x Aug 15 '18 at 11:54
  • You are still getting AttributeError: 'SpeechToTextClient' object has no attribute 'stream_audio_thread' ? – chughts Aug 20 '18 at 08:29
  • yes I am sir. And I need to solve this issue. DO you have a working example in python that uses iam_api_key and url instead of username and password? – ironmantis7x Aug 21 '18 at 19:14
  • That is really odd because if you do check for existence before using it, then the no attribute shouldn't be hit, and you should only see the error relating to your line of code `WebSocketClient.__init__(self, speech_to_text)` where it isn't clear why you are passing and instance of speech to text into a web socket client constructor. – chughts Aug 23 '18 at 10:36
  • To help you, in the python sdk for watson-developer-cloud https://github.com/watson-developer-cloud/python-sdk/tree/master/watson_developer_cloud which you are already using is a web socket client library that you could either use or model your class on https://github.com/watson-developer-cloud/python-sdk/blob/master/watson_developer_cloud/websocket/speech_to_text_websocket_listener.py – chughts Aug 23 '18 at 10:36
  • Thanks. I can't figure it out. I have to use wesockets and iam_api_key. The links you gave show clearly how to do that? – ironmantis7x Aug 23 '18 at 12:55
  • It depends on what you are trying to achieve in your python app. Is it 1. Stream audio in to your python app though a web socket from an audio source, or 2. Stream audio from your python app through a web socket to Watson STT, or 3 Both with your python app in the middle? – chughts Aug 24 '18 at 14:49
  • Normally when you initialise a `WebSocketClient` you pass in a `wss://server` address, but you are passing in `SpeechToTextV1`which isn't. So I think you are trying to do option (2), in which case the code you should be modelling on is https://www.ibm.com/watson/developercloud/speech-to-text/api/v1/python.html?python#websocket_methods where the web socket address is given as `wss://{base-url}/speech-to-text/api/v1/recognize` which is what you should really be passing into `WebSocketClient.__init__` – chughts Aug 24 '18 at 14:49
  • i am trying to stream audio into the python app to send to IBM Watson, convert the stream to text, send that to my conversation bot, have it respond and sent the text back to python and convert that to an audio (and play it). That's what I am aiming for. – ironmantis7x Aug 25 '18 at 20:36
0

I ended up redoing the code that employs a different approach to achieve what I need.

That solution is here: Trouble passing string variable to return data from python function to be used globally anywhere in a python script or program - EDITED for clarity

Thanks.

ironmantis7x
  • 807
  • 2
  • 23
  • 58