mirror of
https://github.com/howelljiang/baidu-voice.git
synced 2026-07-27 17:43:56 +08:00
根据官网代码规范优化结构,精简代码。使用reconfigure模式支持重设参数。增加多实例支持。去掉debug信息。
This commit is contained in:
@@ -20,18 +20,17 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""设置百度语音配置项."""
|
"""设置百度语音配置项."""
|
||||||
# 存储配置数据
|
|
||||||
hass.data.setdefault(DOMAIN, {})
|
|
||||||
hass.data[DOMAIN] = entry.data.copy() # 保存所有配置数据
|
|
||||||
|
|
||||||
# 加载平台
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
hass.data[DOMAIN] = entry.data.copy()
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""卸载百度语音配置项."""
|
"""卸载百度语音配置项."""
|
||||||
# 卸载平台
|
|
||||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||||
|
|
||||||
if unload_ok:
|
if unload_ok:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Config flow for Baidu TTS integration."""
|
"""Config flow for Baidu Voice integration."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -7,13 +7,12 @@ from typing import Any
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
ConfigEntry,
|
from homeassistant.helpers.selector import (
|
||||||
ConfigFlow,
|
SelectSelector,
|
||||||
ConfigFlowResult,
|
SelectSelectorConfig,
|
||||||
OptionsFlow,
|
SelectSelectorMode,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
@@ -62,6 +61,9 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(TTS_CONF_VOICE, default=TTS_DEFAULT_VOICE): vol.In(
|
vol.Optional(TTS_CONF_VOICE, default=TTS_DEFAULT_VOICE): vol.In(
|
||||||
TTS_SUPPORTED_VOICES
|
TTS_SUPPORTED_VOICES
|
||||||
),
|
),
|
||||||
|
vol.Optional(TTS_CONF_FILEFORMAT, default=TTS_DEFAULT_FILEFORMAT): vol.In(
|
||||||
|
TTS_FILEFORMAT_MAP
|
||||||
|
),
|
||||||
vol.Optional(STT_CONF_LANGUAGE, default=STT_DEFAULT_LANGUAGE): vol.In(
|
vol.Optional(STT_CONF_LANGUAGE, default=STT_DEFAULT_LANGUAGE): vol.In(
|
||||||
STT_LANGUAGES
|
STT_LANGUAGES
|
||||||
),
|
),
|
||||||
@@ -69,102 +71,46 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaiduTTSConfigFlow(ConfigFlow, domain=DOMAIN):
|
class BaiduVoiceConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a config flow for Baidu TTS."""
|
"""Handle a config flow for Baidu Voice."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 1
|
||||||
|
|
||||||
|
async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None):
|
||||||
|
"""Handle reconfiguration of the integration."""
|
||||||
|
if user_input is not None:
|
||||||
|
return self.async_update_reload_and_abort(
|
||||||
|
self._get_reconfigure_entry(),
|
||||||
|
data_updates=user_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
schema = self.add_suggested_values_to_schema(
|
||||||
|
STEP_USER_DATA_SCHEMA, self._get_reconfigure_entry().data
|
||||||
|
)
|
||||||
|
schema = schema.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_APP_ID): SelectSelector(
|
||||||
|
SelectSelectorConfig(
|
||||||
|
options=[self._get_reconfigure_entry().data[CONF_APP_ID]],
|
||||||
|
mode=SelectSelectorMode.DROPDOWN,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="reconfigure",
|
||||||
|
data_schema=schema,
|
||||||
|
)
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
"""Handle the initial step."""
|
"""Handle the initial step."""
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
# Provide unique ID to prevent duplicate entries
|
|
||||||
app_id = user_input[CONF_APP_ID]
|
app_id = user_input[CONF_APP_ID]
|
||||||
await self.async_set_unique_id(f"baidu_tts_{app_id}")
|
await self.async_set_unique_id(f"baidu_voice_{app_id}")
|
||||||
self._abort_if_unique_id_configured()
|
self._abort_if_unique_id_configured()
|
||||||
|
return self.async_create_entry(title="Baidu Voice", data=user_input)
|
||||||
return self.async_create_entry(title="百度语音合成", data=user_input)
|
|
||||||
|
|
||||||
return self.async_show_form(step_id="user", data_schema=STEP_USER_DATA_SCHEMA)
|
return self.async_show_form(step_id="user", data_schema=STEP_USER_DATA_SCHEMA)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
@callback
|
|
||||||
def async_get_options_flow(cls, config_entry: ConfigEntry) -> BaiduTTSOptionsFlow:
|
|
||||||
"""Get the options flow for this handler."""
|
|
||||||
return BaiduTTSOptionsFlow()
|
|
||||||
|
|
||||||
|
|
||||||
class BaiduTTSOptionsFlow(OptionsFlow):
|
|
||||||
"""Baidu TTS integration options handler."""
|
|
||||||
|
|
||||||
async def async_step_init(
|
|
||||||
self, user_input: dict[str, Any] | None = None
|
|
||||||
) -> ConfigFlowResult:
|
|
||||||
"""Manage the options."""
|
|
||||||
if user_input is not None:
|
|
||||||
return self.async_create_entry(title="", data=user_input)
|
|
||||||
|
|
||||||
options = self.config_entry.options
|
|
||||||
data = self.config_entry.data
|
|
||||||
|
|
||||||
schema = {
|
|
||||||
vol.Required(
|
|
||||||
CONF_APP_ID,
|
|
||||||
default=options.get(CONF_APP_ID, data.get(CONF_APP_ID)),
|
|
||||||
): str,
|
|
||||||
vol.Required(
|
|
||||||
CONF_API_KEY,
|
|
||||||
default=options.get(CONF_API_KEY, data.get(CONF_API_KEY)),
|
|
||||||
): str,
|
|
||||||
vol.Required(
|
|
||||||
CONF_SECRET_KEY,
|
|
||||||
default=options.get(CONF_SECRET_KEY, data.get(CONF_SECRET_KEY)),
|
|
||||||
): str,
|
|
||||||
vol.Required(
|
|
||||||
TTS_CONF_LANGUAGE,
|
|
||||||
default=options.get(TTS_CONF_LANGUAGE, data.get(TTS_CONF_LANGUAGE)),
|
|
||||||
): vol.In(TTS_LANGUAGES),
|
|
||||||
vol.Optional(
|
|
||||||
TTS_CONF_SPEED,
|
|
||||||
default=options.get(
|
|
||||||
TTS_CONF_SPEED, data.get(TTS_CONF_SPEED, TTS_DEFAULT_SPEED)
|
|
||||||
),
|
|
||||||
): vol.All(vol.Coerce(int), vol.Range(min=0, max=9)),
|
|
||||||
vol.Optional(
|
|
||||||
TTS_CONF_PITCH,
|
|
||||||
default=options.get(
|
|
||||||
TTS_CONF_PITCH, data.get(TTS_CONF_PITCH, TTS_DEFAULT_PITCH)
|
|
||||||
),
|
|
||||||
): vol.All(vol.Coerce(int), vol.Range(min=0, max=9)),
|
|
||||||
vol.Optional(
|
|
||||||
TTS_CONF_VOLUME,
|
|
||||||
default=options.get(
|
|
||||||
TTS_CONF_VOLUME, data.get(TTS_CONF_VOLUME, TTS_DEFAULT_VOLUME)
|
|
||||||
),
|
|
||||||
): vol.All(vol.Coerce(int), vol.Range(min=0, max=15)),
|
|
||||||
vol.Optional(
|
|
||||||
TTS_CONF_VOICE,
|
|
||||||
default=options.get(
|
|
||||||
TTS_CONF_VOICE, data.get(TTS_CONF_VOICE, TTS_DEFAULT_VOICE)
|
|
||||||
),
|
|
||||||
): vol.In(TTS_SUPPORTED_VOICES),
|
|
||||||
vol.Optional(
|
|
||||||
TTS_CONF_FILEFORMAT,
|
|
||||||
default=options.get(
|
|
||||||
TTS_CONF_FILEFORMAT,
|
|
||||||
data.get(TTS_CONF_FILEFORMAT, TTS_DEFAULT_FILEFORMAT),
|
|
||||||
),
|
|
||||||
): vol.In(TTS_FILEFORMAT_MAP),
|
|
||||||
vol.Optional(
|
|
||||||
STT_CONF_LANGUAGE,
|
|
||||||
default=options.get(
|
|
||||||
STT_CONF_LANGUAGE, data.get(STT_CONF_LANGUAGE, STT_DEFAULT_LANGUAGE)
|
|
||||||
),
|
|
||||||
): vol.In(STT_LANGUAGES),
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.async_show_form(
|
|
||||||
step_id="init",
|
|
||||||
data_schema=vol.Schema(schema),
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
DOMAIN: Final = "baidu_voice"
|
DOMAIN: Final = "baidu_voice"
|
||||||
|
ENDPOINT: Final = "http://vop.baidu.com/server_api"
|
||||||
# 配置项
|
# 配置项
|
||||||
CONF_APP_ID: Final = "app_id"
|
CONF_APP_ID: Final = "app_id"
|
||||||
CONF_API_KEY: Final = "api_key"
|
CONF_API_KEY: Final = "api_key"
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "Baidu Voice",
|
|
||||||
"domains": ["tts", "stt"],
|
|
||||||
"homeassistant": "2023.1.0",
|
|
||||||
"render_readme": true
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
@@ -12,6 +12,5 @@
|
|||||||
"requirements": [
|
"requirements": [
|
||||||
"baidu-aip == 4.16.10", "chardet==5.2.0"
|
"baidu-aip == 4.16.10", "chardet==5.2.0"
|
||||||
],
|
],
|
||||||
"version": "0.0.1",
|
"version": "0.0.1"
|
||||||
"issue_tracker": "https://github.com/howelljiang/baidu-voice/issues"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,57 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"step": {
|
"step": {
|
||||||
"user": {
|
"user": {
|
||||||
|
"title": "[%key:common::config_flow::title::setup%] Baidu Voice",
|
||||||
|
"description": "[%key:common::config_flow::description::enter_credentials%]",
|
||||||
"data": {
|
"data": {
|
||||||
"host": "[%key:common::config_flow::data::host%]",
|
"app_id": "[%key:common::config_flow::data::app_id%]",
|
||||||
"username": "[%key:common::config_flow::data::username%]",
|
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||||
"password": "[%key:common::config_flow::data::password%]"
|
"secret_key": "[%key:common::config_flow::data::secret_key%]",
|
||||||
|
"language": "[%key:common::config_flow::data::language%]",
|
||||||
|
"stt_language": "[%key:common::config_flow::data::stt_language%]",
|
||||||
|
"volume": "[%key:common::config_flow::data::volume%]",
|
||||||
|
"speed": "[%key:common::config_flow::data::speed%]",
|
||||||
|
"pitch": "[%key:common::config_flow::data::pitch%]",
|
||||||
|
"voice": "[%key:common::config_flow::data::voice%]",
|
||||||
|
"fileformat": "[%key:common::config_flow::data::fileformat%]",
|
||||||
|
"test_connection": "[%key:common::config_flow::data::test_connection%]"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
|
||||||
"unknown": "[%key:common::config_flow::error::unknown%]"
|
"unknown": "[%key:common::config_flow::error::unknown%]",
|
||||||
|
"auth": "[%key:common::config_flow::error::auth%]",
|
||||||
|
"test_success": "[%key:common::config_flow::error::test_success%]"
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"step": {
|
||||||
|
"init": {
|
||||||
|
"title": "[%key:common::config_flow::options::title%]",
|
||||||
|
"description": "[%key:common::config_flow::options::description%]",
|
||||||
|
"data": {
|
||||||
|
"app_id": "[%key:common::config_flow::data::app_id%]",
|
||||||
|
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||||
|
"secret_key": "[%key:common::config_flow::data::secret_key%]",
|
||||||
|
"language": "[%key:common::config_flow::data::language%]",
|
||||||
|
"stt_language": "[%key:common::config_flow::data::stt_language%]",
|
||||||
|
"volume": "[%key:common::config_flow::data::volume%]",
|
||||||
|
"speed": "[%key:common::config_flow::data::speed%]",
|
||||||
|
"pitch": "[%key:common::config_flow::data::pitch%]",
|
||||||
|
"voice": "[%key:common::config_flow::data::voice%]",
|
||||||
|
"fileformat": "[%key:common::config_flow::data::fileformat%]",
|
||||||
|
"test_connection": "[%key:common::config_flow::data::test_connection%]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"auth": "[%key:common::config_flow::error::auth%]",
|
||||||
|
"test_success": "[%key:common::config_flow::error::test_success%]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ class BaiduSTTEntity(stt.SpeechToTextEntity):
|
|||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, config: dict[str, Any]) -> None:
|
def __init__(self, hass: HomeAssistant, config: dict[str, Any]) -> None:
|
||||||
"""Initialize Baidu speech-to-text entity."""
|
"""Initialize Baidu speech-to-text entity."""
|
||||||
super().__init__()
|
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._config = config
|
self._config = config
|
||||||
self._client = AipSpeech(
|
self._client = AipSpeech(
|
||||||
@@ -62,7 +61,7 @@ class BaiduSTTEntity(stt.SpeechToTextEntity):
|
|||||||
@property
|
@property
|
||||||
def supported_languages(self) -> list[str]:
|
def supported_languages(self) -> list[str]:
|
||||||
"""Return list of supported languages."""
|
"""Return list of supported languages."""
|
||||||
return ["zh-CN", "en-US", "yue-CN", "sichuan-CN"]
|
return ["zh-CN", "en-US", "zh-HK", "zh-TW"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_formats(self) -> list[str]:
|
def supported_formats(self) -> list[str]:
|
||||||
@@ -118,7 +117,7 @@ class BaiduSTTEntity(stt.SpeechToTextEntity):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if "err_no" in result and result["err_no"] != 0:
|
if "err_no" in result and result["err_no"] != 0:
|
||||||
_LOGGER.debug(
|
_LOGGER.error(
|
||||||
"Error from Baidu API: %s - %s",
|
"Error from Baidu API: %s - %s",
|
||||||
result.get("err_msg", "Unknown error"),
|
result.get("err_msg", "Unknown error"),
|
||||||
result.get("err_detail", "No details"),
|
result.get("err_detail", "No details"),
|
||||||
@@ -139,7 +138,7 @@ class BaiduSTTEntity(stt.SpeechToTextEntity):
|
|||||||
result=stt.SpeechResultState.SUCCESS,
|
result=stt.SpeechResultState.SUCCESS,
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception: # pylint: disable=broad-except
|
except Exception:
|
||||||
_LOGGER.exception("Error processing Baidu STT")
|
_LOGGER.exception("Error processing Baidu STT")
|
||||||
return stt.SpeechResult(
|
return stt.SpeechResult(
|
||||||
text=None,
|
text=None,
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
"""Provide info to system health."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from homeassistant.components import system_health
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
|
from .const import DOMAIN, ENDPOINT
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_register(
|
||||||
|
hass: HomeAssistant, register: system_health.SystemHealthRegistration
|
||||||
|
) -> None:
|
||||||
|
"""Register system health callbacks."""
|
||||||
|
register.async_register_info(system_health_info)
|
||||||
|
|
||||||
|
|
||||||
|
async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
|
||||||
|
"""Get info for the info page."""
|
||||||
|
config_entry: ConfigEntry = hass.config_entries.async_entries(DOMAIN)[0]
|
||||||
|
quota_info = await config_entry.runtime_data.async_get_quota_info()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"consumed_requests": quota_info.consumed_requests,
|
||||||
|
"remaining_requests": quota_info.requests_remaining,
|
||||||
|
# checking the url can take a while, so set the coroutine in the info dict
|
||||||
|
"can_reach_server": system_health.async_check_can_reach_url(hass, ENDPOINT),
|
||||||
|
}
|
||||||
@@ -27,12 +27,8 @@
|
|||||||
"fileformat": "Audio Format",
|
"fileformat": "Audio Format",
|
||||||
"test_connection": "Test Connection"
|
"test_connection": "Test Connection"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"reconfigure": {
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"step": {
|
|
||||||
"init": {
|
|
||||||
"title": "Update Baidu Voice Settings",
|
"title": "Update Baidu Voice Settings",
|
||||||
"description": "Modify Baidu Voice settings",
|
"description": "Modify Baidu Voice settings",
|
||||||
"data": {
|
"data": {
|
||||||
@@ -49,10 +45,6 @@
|
|||||||
"test_connection": "Test Connection"
|
"test_connection": "Test Connection"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"auth": "Authentication failed",
|
|
||||||
"test_success": "Connection test successful"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,12 +27,8 @@
|
|||||||
"fileformat": "音频格式",
|
"fileformat": "音频格式",
|
||||||
"test_connection": "测试连接"
|
"test_connection": "测试连接"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"reconfigure": {
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"step": {
|
|
||||||
"init": {
|
|
||||||
"title": "更新百度语音设置",
|
"title": "更新百度语音设置",
|
||||||
"description": "修改百度语音设置",
|
"description": "修改百度语音设置",
|
||||||
"data": {
|
"data": {
|
||||||
@@ -49,10 +45,6 @@
|
|||||||
"test_connection": "测试连接"
|
"test_connection": "测试连接"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"auth": "认证失败",
|
|
||||||
"test_success": "连接测试成功"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,13 +16,11 @@ from homeassistant.components.tts import (
|
|||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_API_KEY,
|
CONF_API_KEY,
|
||||||
CONF_APP_ID,
|
CONF_APP_ID,
|
||||||
CONF_SECRET_KEY,
|
CONF_SECRET_KEY,
|
||||||
DOMAIN,
|
|
||||||
TTS_DEFAULT_FILEFORMAT,
|
TTS_DEFAULT_FILEFORMAT,
|
||||||
TTS_DEFAULT_LANGUAGE,
|
TTS_DEFAULT_LANGUAGE,
|
||||||
TTS_DEFAULT_PITCH,
|
TTS_DEFAULT_PITCH,
|
||||||
@@ -53,29 +51,11 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
|
|
||||||
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||||
"""Initialize the Baidu TTS entity."""
|
"""Initialize the Baidu TTS entity."""
|
||||||
self.hass = hass
|
|
||||||
self._config_entry = config_entry
|
|
||||||
|
|
||||||
# Generate unique ID and set name
|
# Generate unique ID and set name
|
||||||
app_id = config_entry.data[CONF_APP_ID]
|
app_id = config_entry.data[CONF_APP_ID]
|
||||||
self._attr_unique_id = f"baidu_tts_{app_id}"
|
self._attr_unique_id = f"baidu_tts_{app_id}"
|
||||||
self._attr_name = "百度语音合成"
|
self._attr_name = "Baidu TTS"
|
||||||
|
|
||||||
# Add device info
|
|
||||||
self._attr_device_info = DeviceInfo(
|
|
||||||
identifiers={(DOMAIN, app_id)},
|
|
||||||
name="百度语音",
|
|
||||||
manufacturer="百度",
|
|
||||||
model="语音合成服务",
|
|
||||||
entry_type=DeviceEntryType.SERVICE,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Initializing Baidu TTS entity with app_id: %s, unique_id: %s, name: %s",
|
|
||||||
app_id,
|
|
||||||
self._attr_unique_id,
|
|
||||||
self._attr_name,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Initialize the TTS client
|
# Initialize the TTS client
|
||||||
self._client = AipSpeech(
|
self._client = AipSpeech(
|
||||||
@@ -87,28 +67,23 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
@property
|
@property
|
||||||
def default_language(self) -> str:
|
def default_language(self) -> str:
|
||||||
"""Return the default language."""
|
"""Return the default language."""
|
||||||
_LOGGER.debug("Getting default language: %s", TTS_DEFAULT_LANGUAGE)
|
|
||||||
return TTS_DEFAULT_LANGUAGE
|
return TTS_DEFAULT_LANGUAGE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_languages(self) -> list[str]:
|
def supported_languages(self) -> list[str]:
|
||||||
"""Return a list of supported languages."""
|
"""Return a list of supported languages."""
|
||||||
languages = list(TTS_LANGUAGES.keys())
|
return list(TTS_LANGUAGES.keys())
|
||||||
_LOGGER.debug("Getting supported languages: %s", languages)
|
|
||||||
return languages
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_options(self) -> list[str]:
|
def supported_options(self) -> list[str]:
|
||||||
"""Return list of supported options."""
|
"""Return list of supported options."""
|
||||||
options = ["speed", "pitch", "volume", "voice", "fileformat"]
|
return ["speed", "pitch", "volume", "voice", "fileformat"]
|
||||||
_LOGGER.debug("Getting supported options: %s", options)
|
|
||||||
return options
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def default_options(self) -> dict[str, Any]:
|
def default_options(self) -> dict[str, Any]:
|
||||||
"""Return a dict of default options."""
|
"""Return a dict of default options."""
|
||||||
# Get current values from config_entry.options first, then data, then fall back to defaults
|
# Get current values from config_entry.options first, then data, then fall back to defaults
|
||||||
options = {
|
return {
|
||||||
"speed": self._config_entry.options.get(
|
"speed": self._config_entry.options.get(
|
||||||
"speed", self._config_entry.data.get("speed", TTS_DEFAULT_SPEED)
|
"speed", self._config_entry.data.get("speed", TTS_DEFAULT_SPEED)
|
||||||
),
|
),
|
||||||
@@ -126,8 +101,6 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
self._config_entry.data.get("fileformat", TTS_DEFAULT_FILEFORMAT),
|
self._config_entry.data.get("fileformat", TTS_DEFAULT_FILEFORMAT),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
_LOGGER.debug("Getting default options: %s", options)
|
|
||||||
return options
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
|
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
|
||||||
@@ -135,77 +108,48 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
voices = []
|
voices = []
|
||||||
for voice_id, voice_name in TTS_SUPPORTED_VOICES.items():
|
for voice_id, voice_name in TTS_SUPPORTED_VOICES.items():
|
||||||
voices.append(Voice(str(voice_id), voice_name))
|
voices.append(Voice(str(voice_id), voice_name))
|
||||||
_LOGGER.debug("Getting supported voices for language %s: %s", language, voices)
|
|
||||||
return voices
|
return voices
|
||||||
|
|
||||||
def get_tts_audio(
|
def get_tts_audio(
|
||||||
self, message: str, language: str, options: dict[str, Any]
|
self, message: str, language: str, options: dict[str, Any]
|
||||||
) -> TtsAudioType:
|
) -> TtsAudioType:
|
||||||
"""Get TTS audio from Baidu."""
|
"""Get TTS audio from Baidu."""
|
||||||
_LOGGER.debug("=================== TTS Debug Info Start ===================")
|
|
||||||
_LOGGER.debug("Message: %s", message)
|
|
||||||
_LOGGER.debug("Language: %s", language)
|
|
||||||
_LOGGER.debug("Raw options dict: %s", options)
|
|
||||||
_LOGGER.debug("Config entry data: %s", self._config_entry.data)
|
|
||||||
_LOGGER.debug("Config entry options: %s", self._config_entry.options)
|
|
||||||
|
|
||||||
# 获取配置值,优先级:options > config_entry.options > config_entry.data > 默认值
|
# options > config_entry.data > default
|
||||||
try:
|
try:
|
||||||
speed = int(
|
speed = int(
|
||||||
options.get("speed")
|
options.get("speed")
|
||||||
or self._config_entry.options.get("speed")
|
|
||||||
or self._config_entry.data.get("speed")
|
or self._config_entry.data.get("speed")
|
||||||
or TTS_DEFAULT_SPEED
|
or TTS_DEFAULT_SPEED
|
||||||
)
|
)
|
||||||
pitch = int(
|
pitch = int(
|
||||||
options.get("pitch")
|
options.get("pitch")
|
||||||
or self._config_entry.options.get("pitch")
|
|
||||||
or self._config_entry.data.get("pitch")
|
or self._config_entry.data.get("pitch")
|
||||||
or TTS_DEFAULT_PITCH
|
or TTS_DEFAULT_PITCH
|
||||||
)
|
)
|
||||||
volume = int(
|
volume = int(
|
||||||
options.get("volume")
|
options.get("volume")
|
||||||
or self._config_entry.options.get("volume")
|
|
||||||
or self._config_entry.data.get("volume")
|
or self._config_entry.data.get("volume")
|
||||||
or TTS_DEFAULT_VOLUME
|
or TTS_DEFAULT_VOLUME
|
||||||
)
|
)
|
||||||
voice = int(
|
voice = int(
|
||||||
options.get("voice")
|
options.get("voice")
|
||||||
or self._config_entry.options.get("voice")
|
|
||||||
or self._config_entry.data.get("voice")
|
or self._config_entry.data.get("voice")
|
||||||
or TTS_DEFAULT_VOICE
|
or TTS_DEFAULT_VOICE
|
||||||
)
|
)
|
||||||
fileformat = int(
|
fileformat = int(
|
||||||
options.get("fileformat")
|
options.get("fileformat")
|
||||||
or self._config_entry.options.get("fileformat")
|
|
||||||
or self._config_entry.data.get("fileformat")
|
or self._config_entry.data.get("fileformat")
|
||||||
or TTS_DEFAULT_FILEFORMAT
|
or TTS_DEFAULT_FILEFORMAT
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Parsed values - speed: %s(%s), pitch: %s(%s), volume: %s(%s), "
|
|
||||||
"voice: %s(%s), fileformat: %s(%s)",
|
|
||||||
speed,
|
|
||||||
type(speed),
|
|
||||||
pitch,
|
|
||||||
type(pitch),
|
|
||||||
volume,
|
|
||||||
type(volume),
|
|
||||||
voice,
|
|
||||||
type(voice),
|
|
||||||
fileformat,
|
|
||||||
type(fileformat),
|
|
||||||
)
|
|
||||||
|
|
||||||
except ValueError as ex:
|
except ValueError as ex:
|
||||||
_LOGGER.error("Error parsing options: %s", ex)
|
_LOGGER.error("Error parsing options: %s", ex)
|
||||||
raise HomeAssistantError(f"Invalid option value: {ex}") from ex
|
raise HomeAssistantError(f"Invalid option value: {ex}") from ex
|
||||||
|
|
||||||
# 获取音频格式
|
|
||||||
format_config = TTS_FILEFORMAT_MAP.get(fileformat, TTS_FILEFORMAT_MAP[6])
|
format_config = TTS_FILEFORMAT_MAP.get(fileformat, TTS_FILEFORMAT_MAP[6])
|
||||||
_LOGGER.debug("Using audio format: %s", format_config)
|
_LOGGER.debug("Using audio format: %s", format_config)
|
||||||
|
|
||||||
# 准备API参数
|
|
||||||
api_params = {
|
api_params = {
|
||||||
"spd": speed,
|
"spd": speed,
|
||||||
"pit": pitch,
|
"pit": pitch,
|
||||||
@@ -216,7 +160,6 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
_LOGGER.debug("API parameters: %s", api_params)
|
_LOGGER.debug("API parameters: %s", api_params)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_LOGGER.debug("Calling Baidu TTS API")
|
|
||||||
result = self._client.synthesis(
|
result = self._client.synthesis(
|
||||||
message,
|
message,
|
||||||
language,
|
language,
|
||||||
@@ -244,6 +187,4 @@ class BaiduTTSEntity(TextToSpeechEntity):
|
|||||||
type(ex).__name__,
|
type(ex).__name__,
|
||||||
)
|
)
|
||||||
raise HomeAssistantError("Failed to generate TTS audio") from ex
|
raise HomeAssistantError("Failed to generate TTS audio") from ex
|
||||||
|
|
||||||
_LOGGER.debug("=================== TTS Debug Info End ===================")
|
|
||||||
return format_config, result
|
return format_config, result
|
||||||
|
|||||||
Reference in New Issue
Block a user