| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- # -*- coding: utf-8 -*-
- """
- Loudest-Strategie für Arbitration.
- Wählt den Satellite mit dem höchsten Audio-Level.
- Dies ist die Standard-Strategie und entspricht dem Prinzip
- "wer am lautesten gehört wird, ist am nächsten".
- """
- from typing import Any
- from trixy_core.arbitration.candidate import ArbitrationCandidate
- from trixy_core.arbitration.strategies.base import ArbitrationStrategy
- class LoudestStrategy(ArbitrationStrategy):
- """
- Strategie: Höchstes Audio-Level gewinnt.
- Diese Strategie wählt den Satellite aus, bei dem das Wakeword
- am lautesten erkannt wurde. Dies ist typischerweise der Satellite,
- der dem Sprecher am nächsten ist.
- Beispiel:
- ```python
- strategy = LoudestStrategy()
- candidates = [
- ArbitrationCandidate(satellite_id="kitchen", audio_level=0.7),
- ArbitrationCandidate(satellite_id="living_room", audio_level=0.85),
- ]
- winner = strategy.select(candidates)
- # winner.satellite_id == "living_room"
- ```
- """
- def __init__(self, min_audio_level: float = 0.1) -> None:
- """
- Initialisiert die Strategie.
- Args:
- min_audio_level: Minimales Audio-Level für Gültigkeit
- """
- self.min_audio_level = min_audio_level
- @property
- def name(self) -> str:
- return "loudest"
- @property
- def description(self) -> str:
- return "Wählt den Satellite mit dem höchsten Audio-Level"
- def calculate_score(
- self,
- candidate: ArbitrationCandidate,
- context: dict[str, Any] | None = None,
- ) -> float:
- """
- Score basiert nur auf Audio-Level.
- Args:
- candidate: Der Kandidat
- context: Nicht verwendet
- Returns:
- Audio-Level als Score (0.0-1.0)
- """
- candidate.score_details = {
- "audio_level": candidate.audio_level,
- }
- return candidate.audio_level
- def select(
- self,
- candidates: list[ArbitrationCandidate],
- context: dict[str, Any] | None = None,
- ) -> ArbitrationCandidate | None:
- """
- Wählt Kandidaten mit höchstem Audio-Level.
- Args:
- candidates: Liste der Kandidaten
- context: Nicht verwendet
- Returns:
- Kandidat mit höchstem audio_level oder None
- """
- valid = self.filter_valid(candidates)
- if not valid:
- return None
- # Scores berechnen
- for candidate in valid:
- candidate.score = self.calculate_score(candidate, context)
- # Höchsten Score auswählen
- winner = max(valid, key=lambda c: c.score)
- return winner
- def validate_candidate(self, candidate: ArbitrationCandidate) -> bool:
- """Prüft ob Audio-Level über Minimum liegt."""
- base_valid = super().validate_candidate(candidate)
- return base_valid and candidate.audio_level >= self.min_audio_level
|