This commit is contained in:
Howell Jiang
2025-04-13 12:04:30 +08:00
parent a7437f27cc
commit 0b3b26eeda
11 changed files with 889 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
"""百度语音集成."""
import logging
from typing import Any, Dict, Optional
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.discovery import async_load_platform
from aip import AipSpeech
from .const import (
DOMAIN,
CONF_APP_ID,
CONF_API_KEY,
CONF_SECRET_KEY,
SERVICE_TTS,
SERVICE_STT,
ATTR_MESSAGE,
ATTR_LANGUAGE,
ATTR_VOLUME,
ATTR_SPEED,
ATTR_PITCH,
ATTR_PERSON,
ATTR_AUDIO,
ATTR_FORMAT,
ATTR_SAMPLE_RATE,
)
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.deprecated(DOMAIN)
async def async_setup(hass: HomeAssistant, config: Dict[str, Any]) -> bool:
"""设置百度语音集成."""
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""设置百度语音配置项."""
# 存储配置数据
hass.data[DOMAIN] = {
CONF_APP_ID: entry.data[CONF_APP_ID],
CONF_API_KEY: entry.data[CONF_API_KEY],
CONF_SECRET_KEY: entry.data[CONF_SECRET_KEY],
}
# 创建语音识别客户端
client = AipSpeech(
entry.data[CONF_APP_ID],
entry.data[CONF_API_KEY],
entry.data[CONF_SECRET_KEY],
)
# 加载TTS平台
await async_load_platform(hass, "tts", DOMAIN, {}, entry.data)
# 加载STT平台
await async_load_platform(hass, "stt", DOMAIN, {}, entry.data)
# 注册服务
async def async_tts_service(service):
"""处理TTS服务调用."""
message = service.data.get(ATTR_MESSAGE)
language = service.data.get(ATTR_LANGUAGE, "zh")
volume = service.data.get(ATTR_VOLUME, 5)
speed = service.data.get(ATTR_SPEED, 5)
pitch = service.data.get(ATTR_PITCH, 5)
person = service.data.get(ATTR_PERSON, 0)
try:
result = await hass.async_add_executor_job(
client.synthesis,
message,
language,
1, # 1表示mp3格式
{
"vol": volume,
"per": person,
"spd": speed,
"pit": pitch,
}
)
if isinstance(result, dict):
_LOGGER.error("TTS失败: %s", result.get('err_msg'))
return
# 保存音频文件
with open('tts_output.mp3', 'wb') as f:
f.write(result)
_LOGGER.info("TTS成功")
except Exception as ex:
_LOGGER.error("TTS异常: %s", ex)
async def async_stt_service(service):
"""处理STT服务调用."""
audio = service.data.get(ATTR_AUDIO)
format = service.data.get(ATTR_FORMAT, "pcm")
sample_rate = service.data.get(ATTR_SAMPLE_RATE, 16000)
try:
result = await hass.async_add_executor_job(
client.asr,
audio,
format,
sample_rate,
{
"dev_pid": 1537, # 普通话(支持简单的英文识别)
}
)
if result.get("err_no") != 0:
_LOGGER.error("STT失败: %s", result.get('err_msg'))
return
# 返回识别结果
recognized_text = result.get("result", [""])[0]
_LOGGER.info("STT识别结果: %s", recognized_text)
except Exception as ex:
_LOGGER.error("STT异常: %s", ex)
# 注册服务
hass.services.async_register(
DOMAIN,
SERVICE_TTS,
async_tts_service,
)
hass.services.async_register(
DOMAIN,
SERVICE_STT,
async_stt_service,
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""卸载百度语音配置项."""
hass.services.async_remove(DOMAIN, SERVICE_TTS)
hass.services.async_remove(DOMAIN, SERVICE_STT)
hass.data.pop(DOMAIN)
return True
+178
View File
@@ -0,0 +1,178 @@
"""百度语音配置流程."""
import logging
import os
import asyncio
import voluptuous as vol
from typing import Any, Dict, Optional
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import config_validation as cv
from aip import AipSpeech
from .const import (
DOMAIN,
CONF_APP_ID,
CONF_API_KEY,
CONF_SECRET_KEY,
)
_LOGGER = logging.getLogger(__name__)
# 测试音频文件路径
TEST_AUDIO_PATH = os.path.join(os.path.dirname(__file__), "text2audio.pcm")
async def async_read_file(file_path: str) -> bytes:
"""异步读取文件内容."""
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, lambda: open(file_path, "rb").read())
async def async_validate_api(
app_id: str,
api_key: str,
secret_key: str,
) -> bool:
"""验证百度API配置."""
try:
# 创建语音识别客户端
client = AipSpeech(app_id, api_key, secret_key)
# 测试TTS
result = await asyncio.get_event_loop().run_in_executor(
None,
client.synthesis,
"测试语音合成",
"zh",
1, # 1表示mp3格式
{
"vol": 5, # 音量,取值0-15,默认为5中音量
"per": 0, # 发音人选择,0为女声,1为男声,3为情感合成-度逍遥,4为情感合成-度丫丫
"spd": 5, # 语速,取值0-9,默认为5中语速
"pit": 5, # 音调,取值0-9,默认为5中语调
}
)
if isinstance(result, dict):
_LOGGER.error("TTS测试失败: %s", result.get('err_msg'))
return False
# 测试STT
try:
audio_data = await async_read_file(TEST_AUDIO_PATH)
except Exception as ex:
_LOGGER.error("无法读取测试音频文件: %s", ex)
return False
result = await asyncio.get_event_loop().run_in_executor(
None,
client.asr,
audio_data,
"pcm", # PCM格式
16000, # 采样率
{
"dev_pid": 1537, # 普通话(支持简单的英文识别)
}
)
if result.get("err_no") != 0:
_LOGGER.error("STT测试失败: %s", result.get('err_msg'))
return False
return True
except Exception as ex:
_LOGGER.error("API验证异常: %s", ex)
return False
class BaiduVoiceConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""处理百度语音配置流程."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH
async def async_step_user(
self, user_input: Optional[Dict[str, Any]] = None
) -> FlowResult:
"""处理用户初始步骤."""
errors: Dict[str, str] = {}
if user_input is not None:
# 验证API配置
if await async_validate_api(
user_input[CONF_APP_ID],
user_input[CONF_API_KEY],
user_input[CONF_SECRET_KEY],
):
return self.async_create_entry(
title="百度语音",
data=user_input,
)
errors["base"] = "invalid_auth"
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_APP_ID): str,
vol.Required(CONF_API_KEY): str,
vol.Required(CONF_SECRET_KEY): str,
}
),
errors=errors,
)
@staticmethod
@callback
def async_get_options_flow(
config_entry: config_entries.ConfigEntry,
) -> config_entries.OptionsFlow:
"""创建选项流."""
return BaiduVoiceOptionsFlow(config_entry)
class BaiduVoiceOptionsFlow(config_entries.OptionsFlow):
"""处理百度语音选项."""
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
"""初始化选项流."""
self._config_entry = config_entry
async def async_step_init(
self, user_input: Optional[Dict[str, Any]] = None
) -> FlowResult:
"""管理百度语音选项."""
errors: Dict[str, str] = {}
if user_input is not None:
# 验证API配置
if await async_validate_api(
user_input[CONF_APP_ID],
user_input[CONF_API_KEY],
user_input[CONF_SECRET_KEY],
):
return self.async_create_entry(
title="",
data=user_input,
)
errors["base"] = "invalid_auth"
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Required(
CONF_APP_ID,
default=self._config_entry.data.get(CONF_APP_ID),
): str,
vol.Required(
CONF_API_KEY,
default=self._config_entry.data.get(CONF_API_KEY),
): str,
vol.Required(
CONF_SECRET_KEY,
default=self._config_entry.data.get(CONF_SECRET_KEY),
): str,
}
),
errors=errors,
)
+45
View File
@@ -0,0 +1,45 @@
"""百度语音常量."""
from typing import Final
DOMAIN: Final = "baidu_voice"
# 配置项
CONF_APP_ID: Final = "app_id"
CONF_API_KEY: Final = "api_key"
CONF_SECRET_KEY: Final = "secret_key"
# 服务
SERVICE_TTS: Final = "tts"
SERVICE_STT: Final = "stt"
# 服务属性
ATTR_MESSAGE: Final = "message"
ATTR_LANGUAGE: Final = "language"
ATTR_VOLUME: Final = "volume"
ATTR_SPEED: Final = "speed"
ATTR_PITCH: Final = "pitch"
ATTR_PERSON: Final = "person"
ATTR_AUDIO: Final = "audio"
ATTR_FORMAT: Final = "format"
ATTR_SAMPLE_RATE: Final = "sample_rate"
# 语音参数
DEFAULT_SPEED: Final = 5
DEFAULT_PITCH: Final = 5
DEFAULT_VOLUME: Final = 5
DEFAULT_PERSON: Final = 0 # 0: 女声, 1: 男声, 3: 情感男声, 4: 情感女声
# 音频格式
SUPPORTED_AUDIO_FORMATS: Final = ["mp3", "wav", "pcm"]
SUPPORTED_SAMPLE_RATES: Final = [8000, 16000]
SUPPORTED_CHANNELS: Final = [1] # 单声道
SUPPORTED_CODECS: Final = ["pcm", "mp3", "wav"]
# 语言支持
SUPPORTED_LANGUAGES: Final = ["zh"] # 目前只支持中文
# 错误码
ERROR_INVALID_AUTH: Final = "invalid_auth"
ERROR_UNKNOWN: Final = "unknown"
ERROR_NOT_SUPPORTED: Final = "not_supported"
ERROR_SERVICE_UNAVAILABLE: Final = "service_unavailable"
+12
View File
@@ -0,0 +1,12 @@
{
"domain": "baidu_voice",
"name": "Baidu Voice",
"documentation": "https://github.com/howelljiang/baidu_voice",
"dependencies": [],
"codeowners": ["@howelljiang"],
"requirements": ["baidu-aip>=4.16.10"],
"version": "0.1.0",
"iot_class": "cloud_push",
"config_flow": true,
"platforms": ["tts", "stt"]
}
+173
View File
@@ -0,0 +1,173 @@
"""Baidu Speech-to-Text integration."""
import logging
from typing import Any, Optional
from aip import AipSpeech
from homeassistant.components.stt import (
AudioBitRates,
AudioChannels,
AudioCodecs,
AudioFormats,
AudioSampleRates,
SpeechToTextEntity,
SpeechMetadata,
SpeechResult,
SpeechResultState,
Provider,
async_get_provider,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
class BaiduSTTBase:
"""Base class for Baidu STT functionality."""
@property
def supported_languages(self) -> list[str]:
"""Return a list of supported languages."""
return ["zh-CN"]
@property
def supported_formats(self) -> list[AudioFormats]:
"""Return a list of supported formats."""
return [AudioFormats.WAV, AudioFormats.OGG]
@property
def supported_codecs(self) -> list[AudioCodecs]:
"""Return a list of supported codecs."""
return [AudioCodecs.PCM, AudioCodecs.OPUS]
@property
def supported_bit_rates(self) -> list[AudioBitRates]:
"""Return a list of supported bit rates."""
return [AudioBitRates.BITRATE_16]
@property
def supported_sample_rates(self) -> list[AudioSampleRates]:
"""Return a list of supported sample rates."""
return [AudioSampleRates.SAMPLERATE_16000]
@property
def supported_channels(self) -> list[AudioChannels]:
"""Return a list of supported channels."""
return [AudioChannels.CHANNEL_MONO]
async def _process_audio(self, audio_data: bytes, client: AipSpeech) -> SpeechResult:
"""Process audio data using Baidu STT API."""
try:
if not audio_data:
_LOGGER.warning("No audio data received")
return SpeechResult("", SpeechResultState.ERROR)
_LOGGER.debug("Total audio data size: %d bytes", len(audio_data))
# 使用百度语音识别API
result = await self.hass.async_add_executor_job(
client.asr,
audio_data,
'pcm',
16000,
{
'dev_pid': 1537, # 普通话(支持简单的英文识别)
}
)
_LOGGER.debug("Baidu STT response: %s", result)
if result.get('err_no') == 0:
text = result.get('result', [""])[0]
return SpeechResult(text, SpeechResultState.SUCCESS)
else:
_LOGGER.error("Baidu STT error: %s", result.get('err_msg'))
return SpeechResult("", SpeechResultState.ERROR)
except Exception as ex:
_LOGGER.error("Error during Baidu STT: %s", ex, exc_info=True)
return SpeechResult("", SpeechResultState.ERROR)
async def async_get_engine(
hass: HomeAssistant,
config: dict,
discovery_info: Optional[dict] = None
) -> Provider:
"""Set up Baidu STT component."""
_LOGGER.debug("Setting up Baidu STT engine")
return BaiduSTTProvider(hass)
class BaiduSTTProvider(BaiduSTTBase, Provider):
"""Baidu STT api provider."""
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize Baidu STT provider."""
self.hass = hass
self._app_id = hass.data[DOMAIN]["app_id"]
self._api_key = hass.data[DOMAIN]["api_key"]
self._secret_key = hass.data[DOMAIN]["secret_key"]
self._client = AipSpeech(self._app_id, self._api_key, self._secret_key)
self.name = "Baidu STT"
self._language = "zh-CN"
_LOGGER.debug("Initialized Baidu STT provider with language: %s", self._language)
@property
def default_language(self) -> str:
"""Return the default language."""
return self._language
async def async_process_audio_stream(
self, metadata: SpeechMetadata, stream: Any
) -> SpeechResult:
"""Process an audio stream to STT service."""
_LOGGER.debug("Processing audio stream with metadata: %s", metadata)
# 读取音频数据
audio_data = b""
async for chunk in stream:
audio_data += chunk
return await self._process_audio(audio_data, self._client)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Baidu STT from a config entry."""
provider = await async_get_provider(hass, DOMAIN)
if provider:
async_add_entities([BaiduSTTEntity(provider, config_entry)])
class BaiduSTTEntity(BaiduSTTBase, SpeechToTextEntity):
"""Baidu Speech-to-Text entity."""
def __init__(self, provider: Provider, config_entry: ConfigEntry) -> None:
"""Initialize Baidu STT entity."""
self._provider = provider
self._config_entry = config_entry
self._attr_name = "Baidu Speech-to-Text"
self._attr_unique_id = f"{DOMAIN}_stt"
self.hass = provider.hass
# 初始化百度语音识别客户端
self._client = AipSpeech(
config_entry.data["app_id"],
config_entry.data["api_key"],
config_entry.data["secret_key"]
)
async def async_process_audio_stream(
self, metadata: SpeechMetadata, stream: Any
) -> SpeechResult:
"""Process an audio stream to STT service."""
_LOGGER.debug("Processing audio stream with metadata: %s", metadata)
# 读取音频数据
audio_data = b""
async for chunk in stream:
audio_data += chunk
return await self._process_audio(audio_data, self._client)
BIN
View File
Binary file not shown.
+111
View File
@@ -0,0 +1,111 @@
"""测试百度语音API."""
import asyncio
import logging
from aip import AipSpeech
# 配置日志
logging.basicConfig(level=logging.DEBUG)
_LOGGER = logging.getLogger(__name__)
# 百度API配置
APP_ID = "118461597"
API_KEY = "BZk7p3B0DurJuRLrN1cx9iHF"
SECRET_KEY = "sn0i6jtJNPcGI2V13P3MKiGCQYoz9xzf"
# 测试音频文件路径
TEST_AUDIO_PATH = "text2audio.pcm" # 修正文件名
async def test_tts():
"""测试语音合成."""
try:
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 测试TTS
result = await asyncio.get_event_loop().run_in_executor(
None,
client.synthesis,
"测试语音合成",
"zh",
1, # 1表示mp3格式
{
"vol": 5, # 音量,取值0-15,默认为5中音量
"per": 0, # 发音人选择,0为女声,1为男声,3为情感合成-度逍遥,4为情感合成-度丫丫
"spd": 5, # 语速,取值0-9,默认为5中语速
"pit": 5, # 音调,取值0-9,默认为5中语调
}
)
if isinstance(result, dict):
_LOGGER.error("TTS测试失败: %s", result.get('err_msg'))
return False
# 保存音频文件
with open('tts_test.mp3', 'wb') as f:
f.write(result)
_LOGGER.info("TTS测试成功")
return True
except Exception as ex:
_LOGGER.error("TTS测试异常: %s", ex)
return False
async def test_stt():
"""测试语音识别."""
try:
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 读取测试音频
with open(TEST_AUDIO_PATH, 'rb') as f:
audio_data = f.read()
# 测试STT
result = await asyncio.get_event_loop().run_in_executor(
None,
client.asr,
audio_data,
"pcm", # PCM格式
16000, # 采样率
{
"dev_pid": 1537, # 普通话(支持简单的英文识别)
}
)
if result.get("err_no") != 0:
_LOGGER.error("STT测试失败: %s", result.get('err_msg'))
return False
# 验证识别结果
recognized_text = result.get("result", [""])[0]
_LOGGER.info("STT识别结果: %s", recognized_text)
if not recognized_text or "测试" not in recognized_text:
_LOGGER.error("STT识别结果不准确: %s", recognized_text)
return False
_LOGGER.info("STT测试成功")
return True
except Exception as ex:
_LOGGER.error("STT测试异常: %s", ex)
return False
async def main():
"""主测试函数."""
_LOGGER.info("开始测试百度语音API...")
# 测试TTS
tts_result = await test_tts()
_LOGGER.info("TTS测试结果: %s", "成功" if tts_result else "失败")
# 等待1秒
await asyncio.sleep(1)
# 测试STT
stt_result = await test_stt()
_LOGGER.info("STT测试结果: %s", "成功" if stt_result else "失败")
_LOGGER.info("测试完成")
if __name__ == "__main__":
asyncio.run(main())
BIN
View File
Binary file not shown.
+91
View File
@@ -0,0 +1,91 @@
"""Support for Baidu TTS."""
import logging
import asyncio
from aip import AipSpeech
import voluptuous as vol
from homeassistant.components.tts import Provider, PLATFORM_SCHEMA
from homeassistant.const import CONF_API_KEY
import homeassistant.helpers.config_validation as cv
from .const import (
DOMAIN,
CONF_APP_ID,
CONF_API_KEY,
CONF_SECRET_KEY,
DEFAULT_SPEED,
DEFAULT_PITCH,
DEFAULT_VOLUME,
DEFAULT_PERSON,
)
_LOGGER = logging.getLogger(__name__)
SUPPORT_LANGUAGES = ["zh", "en"]
DEFAULT_LANG = "zh"
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_APP_ID): cv.string,
vol.Required(CONF_API_KEY): cv.string,
vol.Required(CONF_SECRET_KEY): cv.string,
}
)
async def async_get_engine(hass, config, discovery_info=None):
"""Set up Baidu TTS component."""
return BaiduTTSProvider(hass)
class BaiduTTSProvider(Provider):
"""Baidu TTS api provider."""
def __init__(self, hass):
"""Initialize Baidu TTS provider."""
self.hass = hass
self._app_id = hass.data[DOMAIN][CONF_APP_ID]
self._api_key = hass.data[DOMAIN][CONF_API_KEY]
self._secret_key = hass.data[DOMAIN][CONF_SECRET_KEY]
self._client = AipSpeech(self._app_id, self._api_key, self._secret_key)
self.name = "Baidu TTS"
@property
def default_language(self):
"""Return the default language."""
return DEFAULT_LANG
@property
def supported_languages(self):
"""Return list of supported languages."""
return SUPPORT_LANGUAGES
async def async_get_tts_audio(self, message, language, options=None):
"""Load TTS from Baidu."""
options = options or {}
speed = options.get("speed", DEFAULT_SPEED)
pitch = options.get("pitch", DEFAULT_PITCH)
volume = options.get("volume", DEFAULT_VOLUME)
person = options.get("person", DEFAULT_PERSON)
def _get_tts():
result = self._client.synthesis(
message,
language,
1, # 1: mp3
{
"spd": speed,
"pit": pitch,
"vol": volume,
"per": person,
},
)
if isinstance(result, dict):
_LOGGER.error("Baidu TTS error: %s", result)
return None, None
return "mp3", result
try:
audio_type, audio_data = await self.hass.async_add_executor_job(_get_tts)
return audio_type, audio_data
except Exception as ex:
_LOGGER.error("Error during Baidu TTS: %s", ex)
return None, None
BIN
View File
Binary file not shown.
+134
View File
@@ -0,0 +1,134 @@
"""Support for Baidu Wake Word Detection."""
import logging
import asyncio
from aip import AipSpeech
import voluptuous as vol
from homeassistant.components.wake_word import (
WakeWordDetectionResult,
WakeWordDetectionResultState,
WakeWordProvider,
)
from homeassistant.const import CONF_API_KEY
import homeassistant.helpers.config_validation as cv
from .const import (
DOMAIN,
CONF_APP_ID,
CONF_API_KEY,
CONF_SECRET_KEY,
CONF_WAKE_WORD,
DEFAULT_WAKE_WORD,
)
_LOGGER = logging.getLogger(__name__)
SUPPORT_LANGUAGES = ["zh", "en"]
DEFAULT_LANG = "zh"
async def async_get_engine(hass, config, discovery_info=None):
"""Set up Baidu Wake Word component."""
_LOGGER.debug("Setting up Baidu Wake Word engine")
return BaiduWakeWordProvider(hass)
class BaiduWakeWordProvider(WakeWordProvider):
"""Baidu Wake Word api provider."""
def __init__(self, hass):
"""Initialize Baidu Wake Word provider."""
self.hass = hass
self._app_id = hass.data[DOMAIN][CONF_APP_ID]
self._api_key = hass.data[DOMAIN][CONF_API_KEY]
self._secret_key = hass.data[DOMAIN][CONF_SECRET_KEY]
self._wake_word = hass.data[DOMAIN][CONF_WAKE_WORD]
self._client = AipSpeech(self._app_id, self._api_key, self._secret_key)
self.name = "Baidu Wake Word"
self._language = hass.config.language or DEFAULT_LANG
_LOGGER.debug("Initialized Baidu Wake Word provider with language: %s", self._language)
@property
def supported_languages(self):
"""Return list of supported languages."""
return SUPPORT_LANGUAGES
@property
def supported_formats(self):
"""Return list of supported formats."""
return ["wav", "pcm"]
@property
def supported_sample_rates(self):
"""Return list of supported sample rates."""
return [16000]
@property
def supported_channels(self):
"""Return list of supported channels."""
return [1]
async def async_process_audio_stream(self, stream, options=None):
"""Process an audio stream to wake word service."""
_LOGGER.debug("Processing audio stream for wake word detection")
options = options or {}
language = options.get("language", self._language)
_LOGGER.debug("Using language: %s", language)
try:
# 读取音频流
audio_data = b""
async for chunk in stream:
if chunk:
audio_data += chunk
_LOGGER.debug("Received audio chunk of size: %d", len(chunk))
if not audio_data:
_LOGGER.warning("No audio data received")
return WakeWordDetectionResult(
state=WakeWordDetectionResultState.ERROR,
wake_word=None,
)
_LOGGER.debug("Total audio data size: %d bytes", len(audio_data))
def _process_audio():
try:
# 使用百度语音识别API进行唤醒词检测
result = self._client.asr(audio_data, 'pcm', 16000, {
'dev_pid': 1536 if language == 'zh' else 1737, # 1536: 普通话, 1737: 英语
})
_LOGGER.debug("ASR result: %s", result)
if result.get('err_no') == 0:
text = result.get('result')[0]
_LOGGER.debug("Recognized text: %s", text)
# 检查是否包含唤醒词
if self._wake_word in text:
_LOGGER.debug("Wake word detected: %s", self._wake_word)
return self._wake_word
_LOGGER.debug("No wake word detected")
return None
_LOGGER.warning("ASR error: %s", result)
return None
except Exception as ex:
_LOGGER.error("Error during Baidu Wake Word processing: %s", ex, exc_info=True)
return None
wake_word = await self.hass.async_add_executor_job(_process_audio)
if wake_word is None:
_LOGGER.debug("No wake word detected")
return WakeWordDetectionResult(
state=WakeWordDetectionResultState.ERROR,
wake_word=None,
)
_LOGGER.debug("Successfully detected wake word: %s", wake_word)
return WakeWordDetectionResult(
state=WakeWordDetectionResultState.SUCCESS,
wake_word=wake_word,
)
except Exception as ex:
_LOGGER.error("Error during Baidu Wake Word: %s", ex, exc_info=True)
return WakeWordDetectionResult(
state=WakeWordDetectionResultState.ERROR,
wake_word=None,
)