Files

80 lines
3.2 KiB
Python

import json
import os
import tempfile
import unittest
from pathlib import Path
from friday_voice.authorization import classify_voice_authorization
from friday_voice.config import Settings
from friday_voice.hermes_client import build_cli_command
from friday_voice.speaker_store import SpeakerStore, cosine_similarity
class SpeakerMathTests(unittest.TestCase):
def test_cosine_similarity_handles_identical_orthogonal_and_zero_vectors(self):
self.assertAlmostEqual(cosine_similarity([1, 2, 3], [1, 2, 3]), 1.0)
self.assertAlmostEqual(cosine_similarity([1, 0], [0, 1]), 0.0)
self.assertEqual(cosine_similarity([0, 0], [1, 2]), 0.0)
def test_speaker_store_identifies_best_matching_profile(self):
with tempfile.TemporaryDirectory() as tmp:
store = SpeakerStore(Path(tmp) / "speakers.json")
store.add_embedding("jeremy", [1.0, 0.0, 0.0], source="office")
store.add_embedding("other", [0.0, 1.0, 0.0], source="test")
match = store.identify([0.98, 0.02, 0.0])
self.assertEqual(match.speaker_id, "jeremy")
self.assertGreater(match.confidence, 0.95)
def test_speaker_store_persists_profiles(self):
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "speakers.json"
SpeakerStore(path).add_embedding("jeremy", [0.1, 0.2, 0.3], source="phone")
reloaded = SpeakerStore(path)
self.assertEqual(len(reloaded.profiles["jeremy"].embeddings), 1)
self.assertEqual(reloaded.profiles["jeremy"].embeddings[0].source, "phone")
class AuthorizationTests(unittest.TestCase):
def test_authorization_thresholds_map_voice_confidence_to_risk_level(self):
self.assertEqual(classify_voice_authorization("jeremy", 0.88).level, "confirmed")
self.assertEqual(classify_voice_authorization("jeremy", 0.75).level, "probable")
self.assertEqual(classify_voice_authorization("jeremy", 0.50).level, "unknown")
self.assertEqual(classify_voice_authorization(None, 0.99).level, "unknown")
def test_unknown_speaker_is_read_only(self):
decision = classify_voice_authorization(None, 0.0)
self.assertTrue(decision.read_only)
self.assertTrue(decision.requires_confirmation)
class ConfigAndHermesTests(unittest.TestCase):
def test_settings_defaults_match_residence_services(self):
settings = Settings()
self.assertEqual(settings.speaches_url, "http://192.168.86.150:8000")
self.assertEqual(settings.hermes_command, "hermes")
self.assertEqual(settings.speaker_confirmed_threshold, 0.85)
def test_settings_from_env_uses_defaults_when_env_is_empty(self):
settings = Settings.from_env({})
self.assertEqual(settings.speaches_url, "http://192.168.86.150:8000")
self.assertEqual(settings.speaker_confirmed_threshold, 0.85)
def test_hermes_cli_command_uses_single_query_mode_and_source(self):
command = build_cli_command("status please", Settings(hermes_command="hermes"))
self.assertEqual(command[:3], ["hermes", "chat", "-q"])
self.assertIn("status please", command)
self.assertIn("--source", command)
self.assertIn("friday-voice", command)
if __name__ == "__main__":
unittest.main()