From ccd2588cf7f97335b9ea8dc3016af20db14a9ec3 Mon Sep 17 00:00:00 2001 From: Lupin Demid Date: Sat, 21 Jan 2017 11:36:28 +0400 Subject: [PATCH] added speed and emotion to Yandex tts (#5431) * Added speed and emotion parameters. Refactored test's * Fixed float point arfs in url and added test for float point values --- homeassistant/components/tts/yandextts.py | 21 ++- tests/components/tts/test_yandextts.py | 184 +++++++++++++++++++--- 2 files changed, 186 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/tts/yandextts.py b/homeassistant/components/tts/yandextts.py index 4dc8618f0d0..824ca6ca38f 100644 --- a/homeassistant/components/tts/yandextts.py +++ b/homeassistant/components/tts/yandextts.py @@ -33,19 +33,34 @@ SUPPORT_VOICES = [ 'jane', 'oksana', 'alyss', 'omazh', 'zahar', 'ermil' ] + +SUPPORTED_EMOTION = [ + 'good', 'evil', 'neutral' +] + +MIN_SPEED = 0.1 +MAX_SPEED = 3 + CONF_CODEC = 'codec' CONF_VOICE = 'voice' +CONF_EMOTION = 'emotion' +CONF_SPEED = 'speed' DEFAULT_LANG = 'en-US' DEFAULT_CODEC = 'mp3' DEFAULT_VOICE = 'zahar' - +DEFAULT_EMOTION = 'neutral' +DEFAULT_SPEED = 1 PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_API_KEY): cv.string, vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES), vol.Optional(CONF_CODEC, default=DEFAULT_CODEC): vol.In(SUPPORT_CODECS), vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): vol.In(SUPPORT_VOICES), + vol.Optional(CONF_EMOTION, default=DEFAULT_EMOTION): + vol.In(SUPPORTED_EMOTION), + vol.Optional(CONF_SPEED, default=DEFAULT_SPEED): + vol.Range(min=MIN_SPEED, max=MAX_SPEED) }) @@ -65,6 +80,8 @@ class YandexSpeechKitProvider(Provider): self._key = conf.get(CONF_API_KEY) self._speaker = conf.get(CONF_VOICE) self._language = conf.get(CONF_LANG) + self._emotion = conf.get(CONF_EMOTION) + self._speed = str(conf.get(CONF_SPEED)) @property def default_language(self): @@ -92,6 +109,8 @@ class YandexSpeechKitProvider(Provider): 'key': self._key, 'speaker': self._speaker, 'format': self._codec, + 'emotion': self._emotion, + 'speed': self._speed } request = yield from websession.get(YANDEX_API_URL, diff --git a/tests/components/tts/test_yandextts.py b/tests/components/tts/test_yandextts.py index f0c6eb85200..2baa94ae2b8 100644 --- a/tests/components/tts/test_yandextts.py +++ b/tests/components/tts/test_yandextts.py @@ -54,10 +54,17 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=200, content=b'test') + self._base_url, status=200, content=b'test', params=url_param) config = { tts.DOMAIN: { @@ -81,10 +88,17 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=ru-RU" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'ru-RU', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=200, content=b'test') + self._base_url, status=200, content=b'test', params=url_param) config = { tts.DOMAIN: { @@ -109,10 +123,17 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=ru-RU" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'ru-RU', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=200, content=b'test') + self._base_url, status=200, content=b'test', params=url_param) config = { tts.DOMAIN: { @@ -137,10 +158,18 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=200, exc=asyncio.TimeoutError()) + self._base_url, status=200, + exc=asyncio.TimeoutError(), params=url_param) config = { tts.DOMAIN: { @@ -164,10 +193,17 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=403, content=b'test') + self._base_url, status=403, content=b'test', params=url_param) config = { tts.DOMAIN: { @@ -190,10 +226,17 @@ class TestTTSYandexPlatform(object): """Test service call say.""" calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) - url = "https://tts.voicetech.yandex.net/generate?format=mp3" \ - "&speaker=alyss&key=1234567xx&text=HomeAssistant&lang=en-US" + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'alyss', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 1 + } aioclient_mock.get( - url, status=200, content=b'test') + self._base_url, status=200, content=b'test', params=url_param) config = { tts.DOMAIN: { @@ -213,3 +256,108 @@ class TestTTSYandexPlatform(object): assert len(aioclient_mock.mock_calls) == 1 assert len(calls) == 1 + + def test_service_say_specifed_emotion(self, aioclient_mock): + """Test service call say.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'evil', + 'speed': 1 + } + aioclient_mock.get( + self._base_url, status=200, content=b'test', params=url_param) + + config = { + tts.DOMAIN: { + 'platform': 'yandextts', + 'api_key': '1234567xx', + 'emotion': 'evil' + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'yandextts_say', { + tts.ATTR_MESSAGE: "HomeAssistant", + }) + self.hass.block_till_done() + + assert len(aioclient_mock.mock_calls) == 1 + assert len(calls) == 1 + + def test_service_say_specified_low_speed(self, aioclient_mock): + """Test service call say.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': '0.1' + } + aioclient_mock.get( + self._base_url, status=200, content=b'test', params=url_param) + + config = { + tts.DOMAIN: { + 'platform': 'yandextts', + 'api_key': '1234567xx', + 'speed': 0.1 + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'yandextts_say', { + tts.ATTR_MESSAGE: "HomeAssistant", + }) + self.hass.block_till_done() + + assert len(aioclient_mock.mock_calls) == 1 + assert len(calls) == 1 + + def test_service_say_specified_speed(self, aioclient_mock): + """Test service call say.""" + calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA) + + url_param = { + 'text': 'HomeAssistant', + 'lang': 'en-US', + 'key': '1234567xx', + 'speaker': 'zahar', + 'format': 'mp3', + 'emotion': 'neutral', + 'speed': 2 + } + aioclient_mock.get( + self._base_url, status=200, content=b'test', params=url_param) + + config = { + tts.DOMAIN: { + 'platform': 'yandextts', + 'api_key': '1234567xx', + 'speed': 2 + } + } + + with assert_setup_component(1, tts.DOMAIN): + setup_component(self.hass, tts.DOMAIN, config) + + self.hass.services.call(tts.DOMAIN, 'yandextts_say', { + tts.ATTR_MESSAGE: "HomeAssistant", + }) + self.hass.block_till_done() + + assert len(aioclient_mock.mock_calls) == 1 + assert len(calls) == 1