mirror of
https://github.com/deunix-educ/voice-assistant.git
synced 2026-10-13 00:11:57 +02:00
correction agent
This commit is contained in:
@@ -105,6 +105,29 @@ def test_someone_else_cannot_confirm(policy: AccessPolicy) -> None:
|
||||
assert resolution.answer.startswith("Seul Denis")
|
||||
|
||||
|
||||
def test_short_yes_is_accepted_when_the_requester_stays_the_closest_voice(policy: AccessPolicy) -> None:
|
||||
"""Essai réel du 2026-10-06 : « OUI » de Denis à 0,35, sous le seuil d'identification."""
|
||||
policy.ask("esp32-01", DOOR_OPEN, "Denis")
|
||||
resolution = policy.resolve("esp32-01", "OUI", None, closest="Denis", score=0.35)
|
||||
assert resolution is not None and resolution.command == DOOR_OPEN
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("speaker", "closest", "score"),
|
||||
[
|
||||
(None, "Denis", 0.12), # trop loin de Denis : n'importe qui
|
||||
(None, "Jessica", 0.40), # plus proche de quelqu'un d'autre
|
||||
(None, None, None), # pas d'empreinte du tout
|
||||
("Jessica", "Jessica", 0.8), # reconnue comme quelqu'un d'autre
|
||||
],
|
||||
)
|
||||
def test_short_yes_from_someone_else_is_refused(policy: AccessPolicy, speaker: str | None,
|
||||
closest: str | None, score: float | None) -> None:
|
||||
policy.ask("esp32-01", DOOR_OPEN, "Denis")
|
||||
resolution = policy.resolve("esp32-01", "oui", speaker, closest=closest, score=score)
|
||||
assert resolution is not None and resolution.command is None
|
||||
|
||||
|
||||
def test_confirmation_expires(policy: AccessPolicy, clock: Clock) -> None:
|
||||
policy.ask("esp32-01", DOOR_OPEN, "Denis")
|
||||
clock.now += 16
|
||||
|
||||
@@ -57,6 +57,10 @@ def with_mac(mac: str = MAC) -> MachinesSettings:
|
||||
("Éteins le P.C. du bureau.", "shutdown"),
|
||||
("Tu peux redémarrer l'ordinateur du bureau ?", "reboot"),
|
||||
("Verrouille le PC du bureau", "lock"),
|
||||
# Mots anglais, tels que Whisper les a écrits à l'essai réel du 2026-10-06.
|
||||
("Locke le PC du bureau", "lock"),
|
||||
("Reboot le PC du bureau", "reboot"),
|
||||
("Shut down le PC du bureau", "shutdown"),
|
||||
("Allume le PC du bureau", "wake"),
|
||||
("Le PC du bureau", None),
|
||||
],
|
||||
|
||||
@@ -131,7 +131,7 @@ def session(duration_s: float = 1.5, peak_dbfs: float = -12.0) -> SessionResult:
|
||||
|
||||
|
||||
def pipeline(stt: FakeStt, tts: FakeTts, player: FakePlayer, vad: FakeVad | None = None,
|
||||
diarizer: FakeDiarizer | None = None, identifier: FakeIdentifier | None = None,
|
||||
diarizer: FakeDiarizer | None = None, identifier: FakeIdentifier | ShortYesIdentifier | None = None,
|
||||
publisher: FakePublisher | None = None, assistant: EchoAssistant | None = None,
|
||||
controller: FakeController | None = None, policy: AccessPolicy | None = None) -> VoicePipeline:
|
||||
ticks = iter([10.0, 11.2]) # début, puis réponse prête 1,2 s plus tard
|
||||
@@ -324,3 +324,34 @@ def test_sensitive_command_waits_for_yes() -> None:
|
||||
controller=controller, policy=policy).handle(session())
|
||||
assert second is not None and second.command == door
|
||||
assert [call[1] for call in controller.calls] == [door]
|
||||
|
||||
|
||||
class ShortYesIdentifier:
|
||||
"""Un « oui » de 0,7 s : sous le seuil, mais Denis reste le profil le plus proche (ou non)."""
|
||||
|
||||
def __init__(self, closest: str, score: float) -> None:
|
||||
self._verdict = Identification(name=None, score=score, closest=closest)
|
||||
|
||||
def identify(self, embedding: np.ndarray) -> Identification:
|
||||
return self._verdict
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("closest", "score", "executed"), [("Denis", 0.35, True), ("Jessica", 0.35, False),
|
||||
("Denis", 0.10, False)])
|
||||
def test_short_yes_confirms_only_from_the_closest_voice(closest: str, score: float, executed: bool) -> None:
|
||||
"""Essai réel du 2026-10-06 : « OUI » de Denis à 0,35 refusé comme « voix inconnue »."""
|
||||
events: list[str] = []
|
||||
controller = FakeController(events)
|
||||
policy = AccessPolicy(ACCESS, HOME)
|
||||
door = DeviceCommand("open", "door", "salon")
|
||||
pipeline(FakeStt("ouvre la porte", words=DENIS_WORDS), FakeTts(), FakePlayer(events),
|
||||
diarizer=FakeDiarizer(), identifier=FakeIdentifier(), assistant=EchoAssistant(door),
|
||||
controller=controller, policy=policy).handle(session())
|
||||
|
||||
second = pipeline(FakeStt("oui", words=(Word(" oui", 0.0, 0.1),)), FakeTts(), FakePlayer(events),
|
||||
diarizer=FakeDiarizer(), identifier=ShortYesIdentifier(closest, score),
|
||||
assistant=EchoAssistant(), controller=controller, policy=policy).handle(session())
|
||||
|
||||
assert second is not None
|
||||
assert [call[1] for call in controller.calls] == ([door] if executed else [])
|
||||
assert second.answer == ("J'ouvre la porte du salon." if executed else "Seul Denis peut confirmer. J'annule.")
|
||||
|
||||
Reference in New Issue
Block a user