00001
00002
00003 import urllib2
00004 import json
00005 import base64
00006 import socket
00007 import traceback
00008 import logging
00009
00010
00011
00012 from rospeex_core.validators import accepts
00013 from rospeex_core.validators import check_language
00014 from rospeex_core import exceptions as ext
00015 from rospeex_core.ss.base import IClient
00016
00017
00018 logger = logging.getLogger(__name__)
00019
00020
00021 class Client(IClient):
00022 """ SpeechSynthesisCient_NICT class """
00023 URL = 'http://rospeex.nict.go.jp/nauth_json/jsServices/VoiceTraSS'
00024 FORMAT = 'x-wav'
00025 LANGUAGES = ['ja', 'en', 'zh', 'ko', 'id', 'my', 'th', 'vi']
00026 VOICEFONT_DICT = {
00027 'ja': ['F128', 'F117', '*'],
00028 'en': ['EF007', '*'],
00029 'zh': ['CJF101', '*'],
00030 'ko': ['KF001', '*'],
00031 'zh': ['CJF101', '*'],
00032 'id': ['*'],
00033 'my': ['*'],
00034 'th': ['*'],
00035 'vi': ['*']
00036 }
00037
00038 def __init__(self):
00039 """ initialize function """
00040 pass
00041
00042 @accepts(message=basestring, language=str, voice_font=str, timeout=int)
00043 def request(
00044 self,
00045 message,
00046 language='ja',
00047 voice_font='*',
00048 timeout=socket._GLOBAL_DEFAULT_TIMEOUT
00049 ):
00050 """
00051 Send speech synthesis request to server,
00052 and get speech synthesis result.
00053 @param message: message
00054 @type message: str
00055 @param language: speech synthesis language
00056 @type language: str
00057 @param voice_font: taraget voice font
00058 @type voice_font: str
00059 @param timeout: request timeout time (second)
00060 @type timeout: float
00061 @return: voice data (wav format binary)
00062 @rtype: str
00063 @raise InvalidResponseException:
00064 @raise InvalidRequestException: send invalid request.
00065 @raise InvalidResponseException: server error.
00066 @raise RequestTimeoutException: timeout error.
00067 """
00068 check_language(language, self.LANGUAGES)
00069 self._check_voice_font(voice_font, language)
00070
00071
00072 decorded_data = self._request_tts(
00073 message,
00074 language,
00075 voice_font,
00076 timeout
00077 )
00078
00079
00080 ret_code = self._check_decorded_data(decorded_data)
00081
00082
00083 voice = None
00084 if not ret_code:
00085 if decorded_data['error']['faultCode'] == 'Server.userException':
00086 msg = 'the format is not supported.'
00087 raise ext.InvalidResponseException(msg)
00088 msg = 'server response error. msg:%s' % decorded_data['error']
00089 raise ext.InvalidResponseException(msg)
00090 else:
00091 voice = base64.b64decode(decorded_data['result']['audio'])
00092 return voice
00093
00094 def _check_voice_font(self, voice_font, language):
00095 """ check voice font
00096 @param voice_font:
00097 @type voice_font:
00098 @param language:
00099 @type language:
00100 @raise ParameterException
00101 """
00102 if voice_font not in self.VOICEFONT_DICT[language]:
00103 msg = 'invalid voice font [{voice_font}].'\
00104 ' Expect: {voice_font_list}'.format(
00105 voice_font=voice_font,
00106 voice_font_list=str(self.VOICEFONT_DICT[language])
00107 )
00108 raise ext.ParameterException(msg)
00109
00110 def _check_decorded_data(self, decorded_data):
00111 """
00112 @param decorded_data:
00113 @type decorded_data:
00114 @return: True to success / False to failture
00115 @rtype: bool
00116 @raise InvalidResponseException:
00117 """
00118
00119 if not decorded_data:
00120 msg = 'invalid server response. response has no data.'
00121 raise ext.InvalidResponseException(msg)
00122
00123 ret_code = False
00124 if 'result' in decorded_data:
00125 if decorded_data['result'] is not None:
00126 if 'audio' in decorded_data['result']:
00127 ret_code = True
00128 else:
00129 msg = 'invalid server response.'\
00130 ' response has no audio data.'
00131 raise ext.InvalidResponseException(msg)
00132
00133
00134 if 'error' in decorded_data:
00135 if decorded_data['error'] is not None:
00136 if 'faultCode' in decorded_data['error']:
00137 ret_code = False
00138 else:
00139 msg = 'invalid server response. response has no faultcode.'
00140 raise ext.InvalidResponseException(msg)
00141
00142 return ret_code
00143
00144 def _request_tts(self, message, language, voice_font, timeout):
00145 """
00146 request tts to NICT server
00147 @param message: message
00148 @type message: str
00149 @param language: speech synthesis language
00150 @type language: str
00151 @param voice_font: taraget voice font
00152 @type voice_font: str
00153 @param timeout: request timeout time (second)
00154 @type timeout: float
00155 @return: voice data (wav format binary)
00156 @rtype: str
00157 @raise InvalidRequestException: send invalid request.
00158 @raise InvalidResponseException: server error.
00159 @raise RequestTimeoutException: timeout error.
00160 """
00161
00162 data = {
00163 'method': 'speak',
00164 'params': [
00165 '1.1',
00166 {
00167 'language': language,
00168 'text': message,
00169 'voiceType': voice_font,
00170 'audioType': 'audio/%s' % self.FORMAT,
00171 'applicationType': 'rospeex'
00172 }
00173 ]
00174 }
00175
00176
00177 decorded_data = None
00178 request = urllib2.Request(self.URL)
00179 request.add_header('Content-Type', 'application/json')
00180
00181
00182 try:
00183 response = urllib2.urlopen(
00184 request,
00185 json.dumps(data),
00186 timeout=timeout
00187 )
00188 decorded_data = json.loads(response.read())
00189
00190 except urllib2.URLError as err:
00191 if isinstance(err.reason, socket.timeout):
00192 msg = 'request time out. Exception: %s' % str(err)
00193 raise ext.RequestTimeoutException(msg)
00194
00195 msg = 'request url error. Exception: %s' % str(err)
00196 raise ext.InvalidRequestException(msg)
00197
00198 except urllib2.HTTPError as err:
00199 msg = 'http error. %s Exception:%s' % (err.code, err.msg)
00200 raise ext.InvalidResponseException(msg)
00201
00202 except socket.timeout as err:
00203 msg = 'request time out. Exception: %s' % str(err)
00204 raise ext.RequestTimeoutException(msg)
00205
00206 except:
00207 msg = 'unknown exception. Traceback: %s' % traceback.format_exc()
00208 raise ext.SpeechSynthesisException(msg)
00209
00210 return decorded_data