Automatically generate Amazon Polly list of voices and regions (#119198)
* Automatically generate list of voices and regions. Requires AWS credentials. * add missing commit * replace pydantic with dataclass * dictionary values are strings or list of strings * also generated set of supported engines * use sets for amazon polly parameters * move default for readabilitypull/120226/head
parent
df82567356
commit
c541cb5cba
|
@ -8,128 +8,23 @@ CONF_REGION: Final = "region_name"
|
|||
CONF_ACCESS_KEY_ID: Final = "aws_access_key_id"
|
||||
CONF_SECRET_ACCESS_KEY: Final = "aws_secret_access_key"
|
||||
|
||||
DEFAULT_REGION: Final = "us-east-1"
|
||||
SUPPORTED_REGIONS: Final[list[str]] = [
|
||||
"us-east-1",
|
||||
"us-east-2",
|
||||
"us-west-1",
|
||||
"us-west-2",
|
||||
"ca-central-1",
|
||||
"eu-west-1",
|
||||
"eu-central-1",
|
||||
"eu-west-2",
|
||||
"eu-west-3",
|
||||
"ap-southeast-1",
|
||||
"ap-southeast-2",
|
||||
"ap-northeast-2",
|
||||
"ap-northeast-1",
|
||||
"ap-south-1",
|
||||
"sa-east-1",
|
||||
]
|
||||
|
||||
CONF_ENGINE: Final = "engine"
|
||||
CONF_VOICE: Final = "voice"
|
||||
CONF_OUTPUT_FORMAT: Final = "output_format"
|
||||
CONF_SAMPLE_RATE: Final = "sample_rate"
|
||||
CONF_TEXT_TYPE: Final = "text_type"
|
||||
|
||||
SUPPORTED_VOICES: Final[list[str]] = [
|
||||
"Aditi", # Hindi
|
||||
"Amy", # English (British)
|
||||
"Aria", # English (New Zealand), Neural
|
||||
"Arlet", # Catalan, Neural
|
||||
"Arthur", # English, Neural
|
||||
"Astrid", # Swedish
|
||||
"Ayanda", # English (South African), Neural
|
||||
"Bianca", # Italian
|
||||
"Brian", # English (British)
|
||||
"Camila", # Portuguese, Brazilian
|
||||
"Carla", # Italian
|
||||
"Carmen", # Romanian
|
||||
"Celine", # French
|
||||
"Chantal", # French Canadian
|
||||
"Conchita", # Spanish (European)
|
||||
"Cristiano", # Portuguese (European)
|
||||
"Daniel", # German, Neural
|
||||
"Dora", # Icelandic
|
||||
"Elin", # Swedish, Neural
|
||||
"Emma", # English
|
||||
"Enrique", # Spanish (European)
|
||||
"Ewa", # Polish
|
||||
"Filiz", # Turkish
|
||||
"Gabrielle", # French (Canadian)
|
||||
"Geraint", # English Welsh
|
||||
"Giorgio", # Italian
|
||||
"Gwyneth", # Welsh
|
||||
"Hala", # Arabic (Gulf), Neural
|
||||
"Hannah", # German (Austrian), Neural
|
||||
"Hans", # German
|
||||
"Hiujin", # Chinese (Cantonese), Neural
|
||||
"Ida", # Norwegian, Neural
|
||||
"Ines", # Portuguese, European # codespell:ignore ines
|
||||
"Ivy", # English
|
||||
"Jacek", # Polish
|
||||
"Jan", # Polish
|
||||
"Joanna", # English
|
||||
"Joey", # English
|
||||
"Justin", # English
|
||||
"Kajal", # English (Indian)/Hindi (Bilingual ), Neural
|
||||
"Karl", # Icelandic
|
||||
"Kendra", # English
|
||||
"Kevin", # English, Neural
|
||||
"Kimberly", # English
|
||||
"Laura", # Dutch, Neural
|
||||
"Lea", # French
|
||||
"Liam", # Canadian French, Neural
|
||||
"Liv", # Norwegian
|
||||
"Lotte", # Dutch
|
||||
"Lucia", # Spanish European
|
||||
"Lupe", # Spanish US
|
||||
"Mads", # Danish
|
||||
"Maja", # Polish
|
||||
"Marlene", # German
|
||||
"Mathieu", # French
|
||||
"Matthew", # English
|
||||
"Maxim", # Russian
|
||||
"Mia", # Spanish Mexican
|
||||
"Miguel", # Spanish US
|
||||
"Mizuki", # Japanese
|
||||
"Naja", # Danish
|
||||
"Nicole", # English Australian
|
||||
"Ola", # Polish, Neural
|
||||
"Olivia", # Female, Australian, Neural
|
||||
"Penelope", # Spanish US
|
||||
"Pedro", # Spanish US, Neural
|
||||
"Raveena", # English, Indian
|
||||
"Ricardo", # Portuguese (Brazilian)
|
||||
"Ruben", # Dutch
|
||||
"Russell", # English (Australian)
|
||||
"Ruth", # English, Neural
|
||||
"Salli", # English
|
||||
"Seoyeon", # Korean
|
||||
"Stephen", # English, Neural
|
||||
"Suvi", # Finnish
|
||||
"Takumi", # Japanese
|
||||
"Tatyana", # Russian
|
||||
"Vicki", # German
|
||||
"Vitoria", # Portuguese, Brazilian
|
||||
"Zeina", # Arabic
|
||||
"Zhiyu", # Chinese
|
||||
]
|
||||
SUPPORTED_OUTPUT_FORMATS: Final[set[str]] = {"mp3", "ogg_vorbis", "pcm"}
|
||||
|
||||
SUPPORTED_OUTPUT_FORMATS: Final[list[str]] = ["mp3", "ogg_vorbis", "pcm"]
|
||||
SUPPORTED_SAMPLE_RATES: Final[set[str]] = {"8000", "16000", "22050", "24000"}
|
||||
|
||||
SUPPORTED_ENGINES: Final[list[str]] = ["neural", "standard"]
|
||||
|
||||
SUPPORTED_SAMPLE_RATES: Final[list[str]] = ["8000", "16000", "22050", "24000"]
|
||||
|
||||
SUPPORTED_SAMPLE_RATES_MAP: Final[dict[str, list[str]]] = {
|
||||
"mp3": ["8000", "16000", "22050", "24000"],
|
||||
"ogg_vorbis": ["8000", "16000", "22050"],
|
||||
"pcm": ["8000", "16000"],
|
||||
SUPPORTED_SAMPLE_RATES_MAP: Final[dict[str, set[str]]] = {
|
||||
"mp3": {"8000", "16000", "22050", "24000"},
|
||||
"ogg_vorbis": {"8000", "16000", "22050"},
|
||||
"pcm": {"8000", "16000"},
|
||||
}
|
||||
|
||||
SUPPORTED_TEXT_TYPES: Final[list[str]] = ["text", "ssml"]
|
||||
SUPPORTED_TEXT_TYPES: Final[set[str]] = {"text", "ssml"}
|
||||
|
||||
CONTENT_TYPE_EXTENSIONS: Final[dict[str, str]] = {
|
||||
"audio/mpeg": "mp3",
|
||||
|
@ -137,6 +32,8 @@ CONTENT_TYPE_EXTENSIONS: Final[dict[str, str]] = {
|
|||
"audio/pcm": "pcm",
|
||||
}
|
||||
|
||||
DEFAULT_REGION: Final = "us-east-1"
|
||||
|
||||
DEFAULT_ENGINE: Final = "standard"
|
||||
DEFAULT_VOICE: Final = "Joanna"
|
||||
DEFAULT_OUTPUT_FORMAT: Final = "mp3"
|
||||
|
|
|
@ -16,6 +16,11 @@ from homeassistant.components.tts import (
|
|||
)
|
||||
from homeassistant.const import ATTR_CREDENTIALS, CONF_PROFILE_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.generated.amazon_polly import (
|
||||
SUPPORTED_ENGINES,
|
||||
SUPPORTED_REGIONS,
|
||||
SUPPORTED_VOICES,
|
||||
)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
|
@ -38,13 +43,10 @@ from .const import (
|
|||
DEFAULT_SAMPLE_RATES,
|
||||
DEFAULT_TEXT_TYPE,
|
||||
DEFAULT_VOICE,
|
||||
SUPPORTED_ENGINES,
|
||||
SUPPORTED_OUTPUT_FORMATS,
|
||||
SUPPORTED_REGIONS,
|
||||
SUPPORTED_SAMPLE_RATES,
|
||||
SUPPORTED_SAMPLE_RATES_MAP,
|
||||
SUPPORTED_TEXT_TYPES,
|
||||
SUPPORTED_VOICES,
|
||||
)
|
||||
|
||||
_LOGGER: Final = logging.getLogger(__name__)
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
"""Automatically generated file.
|
||||
|
||||
To update, run python3 -m script.amazon_polly
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
SUPPORTED_ENGINES: Final[set[str]] = {
|
||||
"generative",
|
||||
"long-form",
|
||||
"neural",
|
||||
"standard",
|
||||
}
|
||||
|
||||
SUPPORTED_REGIONS: Final[set[str]] = {
|
||||
"af-south-1",
|
||||
"ap-east-1",
|
||||
"ap-northeast-1",
|
||||
"ap-northeast-2",
|
||||
"ap-northeast-3",
|
||||
"ap-south-1",
|
||||
"ap-southeast-1",
|
||||
"ap-southeast-2",
|
||||
"ca-central-1",
|
||||
"eu-central-1",
|
||||
"eu-north-1",
|
||||
"eu-west-1",
|
||||
"eu-west-2",
|
||||
"eu-west-3",
|
||||
"me-south-1",
|
||||
"sa-east-1",
|
||||
"us-east-1",
|
||||
"us-east-2",
|
||||
"us-west-1",
|
||||
"us-west-2",
|
||||
}
|
||||
|
||||
SUPPORTED_VOICES: Final[set[str]] = {
|
||||
"Aditi",
|
||||
"Adriano",
|
||||
"Amy",
|
||||
"Andres",
|
||||
"Aria",
|
||||
"Arlet",
|
||||
"Arthur",
|
||||
"Astrid",
|
||||
"Ayanda",
|
||||
"Bianca",
|
||||
"Brian",
|
||||
"Burcu",
|
||||
"Camila",
|
||||
"Carla",
|
||||
"Carmen",
|
||||
"Celine",
|
||||
"Chantal",
|
||||
"Conchita",
|
||||
"Cristiano",
|
||||
"Daniel",
|
||||
"Danielle",
|
||||
"Dora",
|
||||
"Elin",
|
||||
"Emma",
|
||||
"Enrique",
|
||||
"Ewa",
|
||||
"Filiz",
|
||||
"Gabrielle",
|
||||
"Geraint",
|
||||
"Giorgio",
|
||||
"Gregory",
|
||||
"Gwyneth",
|
||||
"Hala",
|
||||
"Hannah",
|
||||
"Hans",
|
||||
"Hiujin",
|
||||
"Ida",
|
||||
"Ines",
|
||||
"Isabelle",
|
||||
"Ivy",
|
||||
"Jacek",
|
||||
"Jan",
|
||||
"Joanna",
|
||||
"Joey",
|
||||
"Justin",
|
||||
"Kajal",
|
||||
"Karl",
|
||||
"Kazuha",
|
||||
"Kendra",
|
||||
"Kevin",
|
||||
"Kimberly",
|
||||
"Laura",
|
||||
"Lea",
|
||||
"Liam",
|
||||
"Lisa",
|
||||
"Liv",
|
||||
"Lotte",
|
||||
"Lucia",
|
||||
"Lupe",
|
||||
"Mads",
|
||||
"Maja",
|
||||
"Marlene",
|
||||
"Mathieu",
|
||||
"Matthew",
|
||||
"Maxim",
|
||||
"Mia",
|
||||
"Miguel",
|
||||
"Mizuki",
|
||||
"Naja",
|
||||
"Niamh",
|
||||
"Nicole",
|
||||
"Ola",
|
||||
"Olivia",
|
||||
"Pedro",
|
||||
"Penelope",
|
||||
"Raveena",
|
||||
"Remi",
|
||||
"Ricardo",
|
||||
"Ruben",
|
||||
"Russell",
|
||||
"Ruth",
|
||||
"Salli",
|
||||
"Seoyeon",
|
||||
"Sergio",
|
||||
"Sofie",
|
||||
"Stephen",
|
||||
"Suvi",
|
||||
"Takumi",
|
||||
"Tatyana",
|
||||
"Thiago",
|
||||
"Tomoko",
|
||||
"Vicki",
|
||||
"Vitoria",
|
||||
"Zayd",
|
||||
"Zeina",
|
||||
"Zhiyu",
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
"""Helper script to update supported languages for Amazone Polly text-to-speech (TTS).
|
||||
|
||||
N.B. This script requires AWS credentials.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Self
|
||||
|
||||
import boto3
|
||||
|
||||
from .hassfest.serializer import format_python_namespace
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AmazonPollyVoice:
|
||||
"""Amazon Polly Voice."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
gender: str
|
||||
language_name: str
|
||||
language_code: str
|
||||
supported_engines: set[str]
|
||||
additional_language_codes: set[str]
|
||||
|
||||
@classmethod
|
||||
def validate(cls, model: dict[str, str | list[str]]) -> Self:
|
||||
"""Validate data model."""
|
||||
return cls(
|
||||
id=model["Id"],
|
||||
name=model["Name"],
|
||||
gender=model["Gender"],
|
||||
language_name=model["LanguageName"],
|
||||
language_code=model["LanguageCode"],
|
||||
supported_engines=set(model["SupportedEngines"]),
|
||||
additional_language_codes=set(model.get("AdditionalLanguageCodes", [])),
|
||||
)
|
||||
|
||||
|
||||
def get_all_voices(client: boto3.client) -> list[AmazonPollyVoice]:
|
||||
"""Get list of all supported voices from Amazon Polly."""
|
||||
response = client.describe_voices()
|
||||
return [AmazonPollyVoice.validate(voice) for voice in response["Voices"]]
|
||||
|
||||
|
||||
supported_regions = set(
|
||||
boto3.session.Session().get_available_regions(service_name="polly")
|
||||
)
|
||||
|
||||
polly_client = boto3.client(service_name="polly", region_name="us-east-1")
|
||||
voices = get_all_voices(polly_client)
|
||||
supported_voices = set({v.id for v in voices})
|
||||
supported_engines = set().union(*[v.supported_engines for v in voices])
|
||||
|
||||
Path("homeassistant/generated/amazon_polly.py").write_text(
|
||||
format_python_namespace(
|
||||
{
|
||||
"SUPPORTED_VOICES": supported_voices,
|
||||
"SUPPORTED_REGIONS": supported_regions,
|
||||
"SUPPORTED_ENGINES": supported_engines,
|
||||
},
|
||||
annotations={
|
||||
"SUPPORTED_VOICES": "Final[set[str]]",
|
||||
"SUPPORTED_REGIONS": "Final[set[str]]",
|
||||
"SUPPORTED_ENGINES": "Final[set[str]]",
|
||||
},
|
||||
generator="script.amazon_polly",
|
||||
)
|
||||
)
|
Loading…
Reference in New Issue