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
This commit is contained in:
parent
2fff8a5a11
commit
ccd2588cf7
2 changed files with 186 additions and 19 deletions
|
@ -33,19 +33,34 @@ SUPPORT_VOICES = [
|
||||||
'jane', 'oksana', 'alyss', 'omazh',
|
'jane', 'oksana', 'alyss', 'omazh',
|
||||||
'zahar', 'ermil'
|
'zahar', 'ermil'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SUPPORTED_EMOTION = [
|
||||||
|
'good', 'evil', 'neutral'
|
||||||
|
]
|
||||||
|
|
||||||
|
MIN_SPEED = 0.1
|
||||||
|
MAX_SPEED = 3
|
||||||
|
|
||||||
CONF_CODEC = 'codec'
|
CONF_CODEC = 'codec'
|
||||||
CONF_VOICE = 'voice'
|
CONF_VOICE = 'voice'
|
||||||
|
CONF_EMOTION = 'emotion'
|
||||||
|
CONF_SPEED = 'speed'
|
||||||
|
|
||||||
DEFAULT_LANG = 'en-US'
|
DEFAULT_LANG = 'en-US'
|
||||||
DEFAULT_CODEC = 'mp3'
|
DEFAULT_CODEC = 'mp3'
|
||||||
DEFAULT_VOICE = 'zahar'
|
DEFAULT_VOICE = 'zahar'
|
||||||
|
DEFAULT_EMOTION = 'neutral'
|
||||||
|
DEFAULT_SPEED = 1
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||||
vol.Required(CONF_API_KEY): cv.string,
|
vol.Required(CONF_API_KEY): cv.string,
|
||||||
vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES),
|
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_CODEC, default=DEFAULT_CODEC): vol.In(SUPPORT_CODECS),
|
||||||
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): vol.In(SUPPORT_VOICES),
|
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._key = conf.get(CONF_API_KEY)
|
||||||
self._speaker = conf.get(CONF_VOICE)
|
self._speaker = conf.get(CONF_VOICE)
|
||||||
self._language = conf.get(CONF_LANG)
|
self._language = conf.get(CONF_LANG)
|
||||||
|
self._emotion = conf.get(CONF_EMOTION)
|
||||||
|
self._speed = str(conf.get(CONF_SPEED))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default_language(self):
|
def default_language(self):
|
||||||
|
@ -92,6 +109,8 @@ class YandexSpeechKitProvider(Provider):
|
||||||
'key': self._key,
|
'key': self._key,
|
||||||
'speaker': self._speaker,
|
'speaker': self._speaker,
|
||||||
'format': self._codec,
|
'format': self._codec,
|
||||||
|
'emotion': self._emotion,
|
||||||
|
'speed': self._speed
|
||||||
}
|
}
|
||||||
|
|
||||||
request = yield from websession.get(YANDEX_API_URL,
|
request = yield from websession.get(YANDEX_API_URL,
|
||||||
|
|
|
@ -54,10 +54,17 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'en-US',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'zahar',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=200, content=b'test')
|
self._base_url, status=200, content=b'test', params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -81,10 +88,17 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=ru-RU"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'ru-RU',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'zahar',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=200, content=b'test')
|
self._base_url, status=200, content=b'test', params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -109,10 +123,17 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=ru-RU"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'ru-RU',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'zahar',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=200, content=b'test')
|
self._base_url, status=200, content=b'test', params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -137,10 +158,18 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'en-US',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'zahar',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=200, exc=asyncio.TimeoutError())
|
self._base_url, status=200,
|
||||||
|
exc=asyncio.TimeoutError(), params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -164,10 +193,17 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=zahar&key=1234567xx&text=HomeAssistant&lang=en-US"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'en-US',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'zahar',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=403, content=b'test')
|
self._base_url, status=403, content=b'test', params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -190,10 +226,17 @@ class TestTTSYandexPlatform(object):
|
||||||
"""Test service call say."""
|
"""Test service call say."""
|
||||||
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
calls = mock_service(self.hass, DOMAIN_MP, SERVICE_PLAY_MEDIA)
|
||||||
|
|
||||||
url = "https://tts.voicetech.yandex.net/generate?format=mp3" \
|
url_param = {
|
||||||
"&speaker=alyss&key=1234567xx&text=HomeAssistant&lang=en-US"
|
'text': 'HomeAssistant',
|
||||||
|
'lang': 'en-US',
|
||||||
|
'key': '1234567xx',
|
||||||
|
'speaker': 'alyss',
|
||||||
|
'format': 'mp3',
|
||||||
|
'emotion': 'neutral',
|
||||||
|
'speed': 1
|
||||||
|
}
|
||||||
aioclient_mock.get(
|
aioclient_mock.get(
|
||||||
url, status=200, content=b'test')
|
self._base_url, status=200, content=b'test', params=url_param)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
tts.DOMAIN: {
|
tts.DOMAIN: {
|
||||||
|
@ -213,3 +256,108 @@ class TestTTSYandexPlatform(object):
|
||||||
|
|
||||||
assert len(aioclient_mock.mock_calls) == 1
|
assert len(aioclient_mock.mock_calls) == 1
|
||||||
assert len(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
|
||||||
|
|
Loading…
Add table
Reference in a new issue