00001
00002
00003
00004
00005 import urllib
00006 import urllib2
00007 import json
00008 import socket
00009 import traceback
00010 import ssl
00011
00012
00013 import rospeex_core.exceptions as ext
00014 from rospeex_core import logging_util
00015 from rospeex_core.validators import accepts, check_wave_data, check_language
00016 from rospeex_core.sr.base.client import IClient
00017 from rospeex_core.sr.nict import Client
00018
00019
00020 logger = logging_util.get_logger(__name__)
00021
00022
00023 class SyncClient(IClient):
00024 """ SpeechRecognitionClient_Google class """
00025 AUDIO_LENGTH = 16000
00026 FRAMERATE = 16000
00027 CHANNELS = 1
00028 SAMPWIDTH = 2
00029 LANGUAGES = ['ja', 'en']
00030 URL = 'https://www.google.com/speech-api/v2/recognize?'
00031
00032 def __init__(self, google_api_key=None, *args, **kwargs):
00033 """ initialize function """
00034 self._api_key = google_api_key
00035
00036 @accepts(data=str, languate=str, timeout=int)
00037 def request(
00038 self,
00039 data,
00040 language='ja',
00041 timeout=socket._GLOBAL_DEFAULT_TIMEOUT
00042 ):
00043 """ send speech recognition request to server
00044 @param data: speech binary data
00045 @type data: str
00046 @param language: speech data language
00047 @type language: str
00048 @param timeout: time out time[ms]
00049 @type timeout: int
00050 """
00051 check_wave_data(
00052 data,
00053 self.FRAMERATE,
00054 self.CHANNELS,
00055 self.SAMPWIDTH,
00056 self.AUDIO_LENGTH
00057 )
00058 check_language(language, self.LANGUAGES)
00059 self._check_api_key()
00060
00061
00062 nict_result = ''
00063 try:
00064 client = Client()
00065 nict_result = client.request(data, language, 10)
00066
00067 except Exception:
00068 pass
00069
00070
00071 result_text = None
00072 try:
00073 result_text = self._request_google_server(
00074 self._api_key,
00075 language,
00076 data,
00077 timeout
00078 )
00079
00080 except ext.InvalidResponseException:
00081 logger.info(
00082 'google speech api connection failed. thus use nict api.'
00083 )
00084 result_text = nict_result
00085
00086 return result_text
00087
00088 def _check_api_key(self):
00089 """ check api key """
00090 if not self._api_key:
00091 msg = 'argment failed. if you want to use google engine,'\
00092 'you MUST set api key for google speech api v2.'
00093 raise ext.ParameterException(msg)
00094
00095 def _request_google_server(self, access_key, language, data, timeout):
00096 """ speech recognition request to google server (use speech api v2)
00097 @param access_key: google speech api key
00098 @type access_key: str
00099 @param language: speech data language
00100 @type language: str
00101 @param data: speech binary data
00102 @type data: str
00103 @param timeout: timeout time [s]
00104 @type timeout: int
00105 @raise SpeechRecognitionException:
00106 """
00107 try:
00108
00109 req = self._create_request(access_key, language, data)
00110 res = urllib2.urlopen(req, timeout=timeout)
00111 res_read = res.read()
00112 google_result_text = self._process_data(res_read)
00113
00114 except urllib2.URLError as err:
00115 if isinstance(err.reason, socket.timeout):
00116 raise ext.RequestTimeoutException(
00117 'request time out. Exception: %s',
00118 str(err)
00119 )
00120 raise ext.InvalidRequestException(
00121 'request url error. Exception:%s',
00122 str(err)
00123 )
00124
00125 except urllib2.HTTPError as err:
00126 raise ext.InvalidResponseException(
00127 'http error. %s Exception:%s',
00128 err.code,
00129 err.msg
00130 )
00131
00132 except (ssl.SSLError, socket.timeout) as err:
00133 raise ext.RequestTimeoutException(str(err))
00134
00135 except Exception as err:
00136 msg = 'unknown exception. Traceback: {}'.format(
00137 traceback.format_exc()
00138 )
00139 raise ext.SpeechRecognitionException(msg)
00140
00141 return google_result_text
00142
00143 def _create_request(self, access_key, language, data):
00144 """ create http request data for google speech api v2
00145 @param access_key: google speech api key
00146 @type access_key: str
00147 @param language: speech data language
00148 @type language: str
00149 @param data: speech binary data
00150 @type data: str
00151 """
00152 header = {'Content-Type': 'audio/l16; rate=16000;'}
00153 values = {
00154 'output': 'json',
00155 'lang': language,
00156 'key': access_key
00157 }
00158 url_req = self.URL + urllib.urlencode(values)
00159 request = urllib2.Request(url_req, data, header)
00160 return request
00161
00162 def _process_data(self, input_str):
00163 result_list = input_str.split('\n')
00164 json_result_list = []
00165 for result in result_list:
00166 try:
00167 json_result_list.append(json.loads(result))
00168 except:
00169 pass
00170
00171
00172 result_data = self._extract_result_key_data(json_result_list)
00173 if result_data != '':
00174 result_data = self._extract_alternative_final_key_data(result_data)
00175 result_data = self._extract_final_data(result_data)
00176 result_data = self._extract_transcript_data(result_data)
00177
00178
00179 result_text = result_data[0] if len(result_data) else ''
00180 return result_text
00181
00182 @classmethod
00183 def _extract_result_key_data(cls, input_data):
00184 """ extract result data from server response
00185 @param input_data:
00186 @type input_data: dict()
00187 """
00188
00189 result_data = [
00190 result['result'] for result in input_data if 'result' in result
00191 ]
00192 if len(result_data) is 0:
00193 raise ext.InvalidResponseException(
00194 'result key is not found. Input: %s',
00195 input_data
00196 )
00197
00198 result_data = filter(lambda x: len(x), result_data)
00199 if len(result_data) is 0:
00200 return ''
00201
00202 result_data = reduce(lambda a, b: a+b, result_data)
00203 return result_data
00204
00205 @classmethod
00206 def _extract_alternative_final_key_data(cls, input_data):
00207 """ extract alternative key data
00208 @param input_data:
00209 @type input_data: dict()
00210 """
00211
00212 result_data = filter(
00213 lambda x: 'alternative' in x and 'final' in x, input_data
00214 )
00215 if len(result_data) is 0:
00216 raise ext.InvalidResponseException(
00217 'alternative key is not found. Input: %s',
00218 input_data
00219 )
00220 return result_data
00221
00222 @classmethod
00223 def _extract_final_data(cls, intput_data):
00224 """ extract final data from server response
00225 @param input_data:
00226 @type input_data: dict()
00227 """
00228
00229 result_data = [
00230 result['alternative'] for result in intput_data
00231 if len(result['alternative']) > 0 and result['final'] is True
00232 ]
00233 if len(result_data) is 0:
00234 raise ext.InvalidResponseException(
00235 'final key is not found. Input: %s',
00236 intput_data
00237 )
00238 return result_data
00239
00240 @classmethod
00241 def _extract_transcript_data(cls, input_data):
00242 """ extract transcript data from server response
00243 @param input_data:
00244 @type input_data: dict()
00245 """
00246
00247 result_data = reduce(lambda a, b: a+b, input_data)
00248 result_data = [
00249 result['transcript'] for result in result_data
00250 if 'transcript' in result
00251 ]
00252 if len(result_data) is 0:
00253 raise ext.InvalidResponseException(
00254 'transcript key is not found. Input: %s',
00255 input_data
00256 )
00257 return result_data
00258
00259 def support_streaming(self):
00260 """
00261 check support streaming
00262 @returns: True for support streaming / False for NOT support streaming
00263 """
00264 return False
00265
00266 def add_streaming_packet(self, packet_type, packet_data):
00267 """
00268 add streaming packet
00269 @param packet_type:
00270 @type packet_type: int
00271 @param packet_data:
00272 @param packet_data: str
00273 """
00274 pass
00275
00276 def register_streaming_cb(self, cb):
00277 """
00278 register streaming result callback
00279 @param cb:
00280 @type cb:
00281 """
00282 pass
00283
00284 def unregister_streaming_cb(self, cb):
00285 """
00286 unregister streaming result callback
00287 @param cb:
00288 @type cb:
00289 """
00290 pass
00291
00292 def set_streaming_config(self, language):
00293 """ set streaming config
00294 @param language:
00295 """
00296 pass
00297
00298 def join(self, timeout=None):
00299 """
00300 join streaming client
00301 @param timeout:
00302 @type timeout:
00303 """
00304 pass