mirror of
https://github.com/howelljiang/baidu-voice.git
synced 2026-07-21 22:53:57 +08:00
按照ha推荐的插件初始化方式进行重构
This commit is contained in:
@@ -1,5 +1,26 @@
|
||||
需要在百度云里面创建应用。开通语音服务里面的 短语音识别和短文本在线合成两个服务 。
|
||||
# 百度语音服务集成
|
||||
|
||||
在集成里面添加baidu_voice服务即可。
|
||||
这是一个 Home Assistant 集成,用于接入百度语音服务,提供文本转语音(TTS)和语音转文本(STT)功能。
|
||||
|
||||
不会python,cursor帮忙写了一个初始版本,有空再来完善。
|
||||
## 配置要求
|
||||
|
||||
1. 需要在百度云创建应用
|
||||
2. 开通以下服务:
|
||||
- 短语音识别服务
|
||||
- 短文本在线合成服务
|
||||
|
||||
## 配置步骤
|
||||
|
||||
1. 在百度云控制台创建应用并获取 API Key 和 Secret Key
|
||||
2. 在 Home Assistant 中添加 baidu_voice 集成
|
||||
3. 输入您的 API Key 和 Secret Key
|
||||
|
||||
## 配置截图
|
||||
|
||||

|
||||

|
||||
|
||||
## 注意事项
|
||||
|
||||
- 本集成需要互联网连接
|
||||
- 使用百度语音服务可能会产生费用,请参考百度云官方计费标准
|
||||
|
||||
+12
-108
@@ -1,11 +1,10 @@
|
||||
"""百度语音集成."""
|
||||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any, Dict
|
||||
|
||||
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 (
|
||||
@@ -13,23 +12,14 @@ from .const import (
|
||||
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)
|
||||
|
||||
PLATFORMS = ["tts", "stt"]
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: Dict[str, Any]) -> bool:
|
||||
"""设置百度语音集成."""
|
||||
return True
|
||||
@@ -37,109 +27,23 @@ async def async_setup(hass: HomeAssistant, config: Dict[str, Any]) -> bool:
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""设置百度语音配置项."""
|
||||
# 存储配置数据
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
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,
|
||||
)
|
||||
|
||||
# 加载平台
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
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)
|
||||
# 卸载平台
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
if unload_ok:
|
||||
hass.data.pop(DOMAIN)
|
||||
|
||||
return unload_ok
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
+2
-2
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"domain": "baidu_voice",
|
||||
"name": "Baidu Voice",
|
||||
"documentation": "https://github.com/howelljiang/baidu_voice",
|
||||
"documentation": "https://github.com/howelljiang/baidu-voice",
|
||||
"dependencies": [],
|
||||
"codeowners": ["@howelljiang"],
|
||||
"requirements": ["baidu-aip>=4.16.10"],
|
||||
"requirements": ["baidu-aip>=4.16.10", "chardet>=5.2.0"],
|
||||
"version": "0.1.0",
|
||||
"iot_class": "cloud_push",
|
||||
"config_flow": true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Baidu Speech-to-Text integration."""
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
from typing import Any
|
||||
|
||||
from aip import AipSpeech
|
||||
from homeassistant.components.stt import (
|
||||
@@ -13,8 +13,6 @@ from homeassistant.components.stt import (
|
||||
SpeechMetadata,
|
||||
SpeechResult,
|
||||
SpeechResultState,
|
||||
Provider,
|
||||
async_get_provider,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@@ -24,8 +22,31 @@ from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class BaiduSTTBase:
|
||||
"""Base class for Baidu STT functionality."""
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> bool:
|
||||
"""Set up Baidu STT from a config entry."""
|
||||
async_add_entities([BaiduSTTEntity(hass, config_entry)])
|
||||
return True
|
||||
|
||||
class BaiduSTTEntity(SpeechToTextEntity):
|
||||
"""Baidu Speech-to-Text entity."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
"""Initialize Baidu STT entity."""
|
||||
self.hass = hass
|
||||
self._config_entry = config_entry
|
||||
self._attr_name = "Baidu STT"
|
||||
self._attr_unique_id = f"{DOMAIN}_stt"
|
||||
|
||||
# 初始化百度语音识别客户端
|
||||
self._client = AipSpeech(
|
||||
config_entry.data["app_id"],
|
||||
config_entry.data["api_key"],
|
||||
config_entry.data["secret_key"]
|
||||
)
|
||||
|
||||
@property
|
||||
def supported_languages(self) -> list[str]:
|
||||
@@ -57,18 +78,26 @@ class BaiduSTTBase:
|
||||
"""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."""
|
||||
async def async_process_audio_stream(
|
||||
self, metadata: SpeechMetadata, stream: Any
|
||||
) -> SpeechResult:
|
||||
"""Process an audio stream to STT service."""
|
||||
try:
|
||||
# 读取音频数据
|
||||
audio_data = b""
|
||||
async for chunk in stream:
|
||||
audio_data += chunk
|
||||
|
||||
if not audio_data:
|
||||
_LOGGER.warning("No audio data received")
|
||||
return SpeechResult("", SpeechResultState.ERROR)
|
||||
|
||||
_LOGGER.debug("Processing audio stream with metadata: %s", metadata)
|
||||
_LOGGER.debug("Total audio data size: %d bytes", len(audio_data))
|
||||
|
||||
# 使用百度语音识别API
|
||||
result = await self.hass.async_add_executor_job(
|
||||
client.asr,
|
||||
self._client.asr,
|
||||
audio_data,
|
||||
'pcm',
|
||||
16000,
|
||||
@@ -88,86 +117,4 @@ class BaiduSTTBase:
|
||||
|
||||
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)
|
||||
return SpeechResult("", SpeechResultState.ERROR)
|
||||
@@ -1,18 +1,18 @@
|
||||
"""Support for Baidu TTS."""
|
||||
import logging
|
||||
import asyncio
|
||||
from aip import AipSpeech
|
||||
import voluptuous as vol
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.components.tts import Provider, PLATFORM_SCHEMA
|
||||
from homeassistant.const import CONF_API_KEY
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from aip import AipSpeech
|
||||
from homeassistant.components.tts import (
|
||||
TextToSpeechEntity,
|
||||
PLATFORM_SCHEMA,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
CONF_APP_ID,
|
||||
CONF_API_KEY,
|
||||
CONF_SECRET_KEY,
|
||||
DEFAULT_SPEED,
|
||||
DEFAULT_PITCH,
|
||||
DEFAULT_VOLUME,
|
||||
@@ -24,41 +24,43 @@ _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_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> bool:
|
||||
"""Set up Baidu TTS from a config entry."""
|
||||
async_add_entities([BaiduTTSEntity(hass, config_entry)])
|
||||
return True
|
||||
|
||||
async def async_get_engine(hass, config, discovery_info=None):
|
||||
"""Set up Baidu TTS component."""
|
||||
return BaiduTTSProvider(hass)
|
||||
class BaiduTTSEntity(TextToSpeechEntity):
|
||||
"""Baidu TTS Entity."""
|
||||
|
||||
class BaiduTTSProvider(Provider):
|
||||
"""Baidu TTS api provider."""
|
||||
|
||||
def __init__(self, hass):
|
||||
"""Initialize Baidu TTS provider."""
|
||||
def __init__(self, hass: HomeAssistant, config_entry: ConfigEntry) -> None:
|
||||
"""Initialize Baidu TTS entity."""
|
||||
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"
|
||||
self._config_entry = config_entry
|
||||
self._attr_name = "Baidu TTS"
|
||||
self._attr_unique_id = f"{DOMAIN}_tts"
|
||||
|
||||
# 初始化百度语音合成客户端
|
||||
self._client = AipSpeech(
|
||||
config_entry.data["app_id"],
|
||||
config_entry.data["api_key"],
|
||||
config_entry.data["secret_key"]
|
||||
)
|
||||
|
||||
@property
|
||||
def default_language(self):
|
||||
def default_language(self) -> str:
|
||||
"""Return the default language."""
|
||||
return DEFAULT_LANG
|
||||
|
||||
@property
|
||||
def supported_languages(self):
|
||||
def supported_languages(self) -> list[str]:
|
||||
"""Return list of supported languages."""
|
||||
return SUPPORT_LANGUAGES
|
||||
|
||||
async def async_get_tts_audio(self, message, language, options=None):
|
||||
async def async_get_tts_audio(self, message: str, language: str, options: dict = None) -> tuple[str, bytes]:
|
||||
"""Load TTS from Baidu."""
|
||||
options = options or {}
|
||||
speed = options.get("speed", DEFAULT_SPEED)
|
||||
@@ -66,8 +68,9 @@ class BaiduTTSProvider(Provider):
|
||||
volume = options.get("volume", DEFAULT_VOLUME)
|
||||
person = options.get("person", DEFAULT_PERSON)
|
||||
|
||||
def _get_tts():
|
||||
result = self._client.synthesis(
|
||||
try:
|
||||
result = await self.hass.async_add_executor_job(
|
||||
self._client.synthesis,
|
||||
message,
|
||||
language,
|
||||
1, # 1: mp3
|
||||
@@ -76,16 +79,15 @@ class BaiduTTSProvider(Provider):
|
||||
"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
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
"""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,
|
||||
)
|
||||
Reference in New Issue
Block a user