first release 0.0.0.2
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
"""
|
||||
ARIA Betriebsmodi — steuern wann und wie ARIA spricht.
|
||||
|
||||
Jeder Modus definiert, ob ARIA Audio ausgeben darf,
|
||||
ob sie proaktiv sprechen darf und ob Unterbrechungen erlaubt sind.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ModeConfig:
|
||||
"""Konfiguration eines Betriebsmodus."""
|
||||
|
||||
name: str
|
||||
emoji: str
|
||||
activation_phrase: str
|
||||
can_speak: bool
|
||||
can_interrupt: bool
|
||||
audio_output: bool
|
||||
proactive: bool
|
||||
|
||||
|
||||
class Mode(Enum):
|
||||
"""ARIAs Betriebsmodi mit zugehoeriger Konfiguration."""
|
||||
|
||||
NORMAL = ModeConfig(
|
||||
name="Normal",
|
||||
emoji="\U0001f7e2", # Gruener Kreis
|
||||
activation_phrase="ARIA, Normal-Modus",
|
||||
can_speak=True,
|
||||
can_interrupt=True,
|
||||
audio_output=True,
|
||||
proactive=True,
|
||||
)
|
||||
|
||||
DND = ModeConfig(
|
||||
name="Nicht stoeren",
|
||||
emoji="\U0001f534", # Roter Kreis
|
||||
activation_phrase="ARIA, nicht stoeren",
|
||||
can_speak=False,
|
||||
can_interrupt=False,
|
||||
audio_output=False,
|
||||
proactive=False,
|
||||
)
|
||||
|
||||
WHISPER = ModeConfig(
|
||||
name="Fluester",
|
||||
emoji="\U0001f7e1", # Gelber Kreis
|
||||
activation_phrase="ARIA, leise bitte",
|
||||
can_speak=False,
|
||||
can_interrupt=False,
|
||||
audio_output=False,
|
||||
proactive=True,
|
||||
)
|
||||
|
||||
HANGAR = ModeConfig(
|
||||
name="Hangar",
|
||||
emoji="\u2708\ufe0f", # Flugzeug
|
||||
activation_phrase="ARIA, ich arbeite",
|
||||
can_speak=True,
|
||||
can_interrupt=False,
|
||||
audio_output=True,
|
||||
proactive=False,
|
||||
)
|
||||
|
||||
GAMING = ModeConfig(
|
||||
name="Gaming",
|
||||
emoji="\U0001f3ae", # Gamepad
|
||||
activation_phrase="ARIA, Gaming-Modus",
|
||||
can_speak=True,
|
||||
can_interrupt=False,
|
||||
audio_output=True,
|
||||
proactive=False,
|
||||
)
|
||||
|
||||
@property
|
||||
def config(self) -> ModeConfig:
|
||||
return self.value
|
||||
|
||||
|
||||
# Aktivierungsphrasen auf Modi mappen (lowercase fuer Vergleich)
|
||||
_ACTIVATION_MAP: dict[str, Mode] = {
|
||||
mode.config.activation_phrase.lower(): mode for mode in Mode
|
||||
}
|
||||
|
||||
|
||||
def detect_mode_switch(text: str) -> Optional[Mode]:
|
||||
"""Erkennt ob ein Text eine Modus-Umschaltung enthaelt.
|
||||
|
||||
Vergleicht den Text (case-insensitive) mit den Aktivierungsphrasen
|
||||
aller Modi. Gibt den neuen Modus zurueck oder None.
|
||||
|
||||
Args:
|
||||
text: Eingabetext vom Benutzer.
|
||||
|
||||
Returns:
|
||||
Der erkannte Modus oder None wenn kein Wechsel erkannt wurde.
|
||||
"""
|
||||
text_lower = text.strip().lower()
|
||||
|
||||
for phrase, mode in _ACTIVATION_MAP.items():
|
||||
if phrase in text_lower:
|
||||
logger.info(
|
||||
"Modus-Wechsel erkannt: %s %s",
|
||||
mode.config.emoji,
|
||||
mode.config.name,
|
||||
)
|
||||
return mode
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def should_speak(mode: Mode, is_critical: bool = False) -> bool:
|
||||
"""Prueft ob eine Nachricht im aktuellen Modus gesprochen werden soll.
|
||||
|
||||
Im DND-Modus wird nur bei kritischen Alarmen gesprochen.
|
||||
Alle anderen Modi respektieren ihre can_speak / audio_output Flags.
|
||||
|
||||
Args:
|
||||
mode: Aktueller Betriebsmodus.
|
||||
is_critical: True wenn es sich um einen kritischen Alarm handelt.
|
||||
|
||||
Returns:
|
||||
True wenn die Nachricht gesprochen werden soll.
|
||||
"""
|
||||
# Kritische Alarme durchbrechen den DND-Modus
|
||||
if is_critical and mode == Mode.DND:
|
||||
logger.warning("Kritischer Alarm im DND-Modus — Sprachausgabe erzwungen")
|
||||
return True
|
||||
|
||||
return mode.config.can_speak and mode.config.audio_output
|
||||
Reference in New Issue
Block a user