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 readability
pull/120226/head
Jakob Schlyter 2024-08-22 15:36:11 +02:00 committed by GitHub
parent df82567356
commit c541cb5cba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 221 additions and 115 deletions

View File

@ -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"

View File

@ -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__)

View File

@ -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",
}

70
script/amazon_polly.py Normal file
View File

@ -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",
)
)