rex/wakeword_catalog.py
Rama master · réplica de lectura del repositorio original.
"""Dependency-free wake-word catalog and selection helpers."""
from __future__ import annotations
from collections.abc import Iterable
DEFAULT_OPENWAKEWORD_KEYWORDS = (
"hey jarvis",
"hey mycroft",
"hey rhasspy",
"ok nabu",
"alexa",
)
def has_text(value: str | None) -> bool:
return bool(value and value.strip())
def normalize_keyword(value: str) -> str:
return " ".join(value.strip().lower().split())
def split_keywords(value: str | None) -> list[str]:
if not has_text(value):
return []
return [part.strip().replace("_", " ") for part in value.split(",") if part.strip()] # type: ignore[union-attr]
def resolve_keyword(
keyword: str | None,
wakeword: str | None,
*,
default: str | None = None,
) -> str | None:
for candidate in (keyword, wakeword, default):
if has_text(candidate):
return candidate.strip() # type: ignore[union-attr]
return None
def list_openwakeword_keywords(openwakeword_module: object | None) -> list[str]:
if openwakeword_module is None:
return []
models = getattr(openwakeword_module, "MODELS", None)
if isinstance(models, dict):
keys = list(models.keys())
elif isinstance(models, Iterable):
keys = list(models)
else:
return []
return [str(item).replace("_", " ") for item in keys if item]
def select_fallback_keyword(
available: list[str],
*,
preferred: str = "hey jarvis",
fallback_keyword: str | None = None,
) -> str:
if not available:
raise RuntimeError("No openwakeword models available.")
normalized_map = {normalize_keyword(item): item for item in available}
if has_text(fallback_keyword):
selected = normalized_map.get(normalize_keyword(fallback_keyword)) # type: ignore[arg-type]
if selected:
return selected
preferred_match = normalized_map.get(normalize_keyword(preferred))
if preferred_match:
return preferred_match
return available[0]