Files
baidu-voice/wake_word.py
T

134 lines
4.9 KiB
Python
Raw Normal View History

2025-04-13 12:04:30 +08:00
"""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,
)