recognition_engine.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. """
  2. Voice Recognition Engine with real-time processing and confidence scoring.
  3. This module provides the core voice recognition engine that integrates all
  4. components for real-time speaker identification and verification.
  5. """
  6. import logging
  7. import time
  8. import threading
  9. from typing import Dict, List, Optional, Tuple, Union, Any, Callable
  10. from dataclasses import dataclass, field
  11. from collections import deque
  12. from datetime import datetime
  13. import numpy as np
  14. import torch
  15. from .config import VoiceRecognitionConfig
  16. from .audio_features import VRAudioFeatureExtractor
  17. from .vad import VoiceActivityDetector, VADResult
  18. from .speaker_manager import SpeakerManager, VerificationResult
  19. from .speaker_embeddings import SpeakerEmbeddingExtractor, EmbeddingComparator
  20. # Configure logging
  21. logger = logging.getLogger(__name__)
  22. @dataclass
  23. class RecognitionResult:
  24. """Result of voice recognition process."""
  25. # Speaker identification
  26. speaker_id: Optional[str]
  27. speaker_name: Optional[str]
  28. confidence: float
  29. similarity_score: float
  30. # Processing information
  31. is_speech: bool
  32. vad_confidence: float
  33. processing_time_ms: float
  34. audio_quality: float
  35. # Temporal information
  36. start_time: float
  37. end_time: float
  38. timestamp: str = field(default_factory=lambda: datetime.now().isoformat())
  39. # Additional details
  40. threshold_used: float = 0.0
  41. alternative_speakers: List[Tuple[str, float]] = field(default_factory=list)
  42. debug_info: Dict[str, Any] = field(default_factory=dict)
  43. def to_dict(self) -> Dict[str, Any]:
  44. """Convert result to dictionary."""
  45. return {
  46. 'speaker_id': self.speaker_id,
  47. 'speaker_name': self.speaker_name,
  48. 'confidence': self.confidence,
  49. 'similarity_score': self.similarity_score,
  50. 'is_speech': self.is_speech,
  51. 'vad_confidence': self.vad_confidence,
  52. 'processing_time_ms': self.processing_time_ms,
  53. 'audio_quality': self.audio_quality,
  54. 'start_time': self.start_time,
  55. 'end_time': self.end_time,
  56. 'timestamp': self.timestamp,
  57. 'threshold_used': self.threshold_used,
  58. 'alternative_speakers': self.alternative_speakers,
  59. 'debug_info': self.debug_info
  60. }
  61. @dataclass
  62. class IdentificationResult(RecognitionResult):
  63. """Result specifically for speaker identification (who is speaking)."""
  64. pass
  65. @dataclass
  66. class VerificationResult(RecognitionResult):
  67. """Result specifically for speaker verification (is this person X)."""
  68. expected_speaker_id: Optional[str] = None
  69. verification_success: bool = False
  70. class ConfidenceCalibrator:
  71. """Calibrate confidence scores for better reliability."""
  72. def __init__(self,
  73. temperature: float = 1.0,
  74. use_platt_scaling: bool = True):
  75. """
  76. Initialize confidence calibrator.
  77. Args:
  78. temperature: Temperature scaling parameter
  79. use_platt_scaling: Whether to use Platt scaling
  80. """
  81. self.temperature = temperature
  82. self.use_platt_scaling = use_platt_scaling
  83. # Platt scaling parameters (will be learned)
  84. self.platt_a = 1.0
  85. self.platt_b = 0.0
  86. # Statistics for calibration
  87. self.score_history = deque(maxlen=1000)
  88. self.label_history = deque(maxlen=1000)
  89. def calibrate_confidence(self, raw_score: float, additional_info: Dict[str, Any] = None) -> float:
  90. """
  91. Calibrate raw similarity score to confidence.
  92. Args:
  93. raw_score: Raw similarity score
  94. additional_info: Additional information for calibration
  95. Returns:
  96. Calibrated confidence score
  97. """
  98. # Temperature scaling
  99. scaled_score = raw_score / self.temperature
  100. # Platt scaling if enabled
  101. if self.use_platt_scaling:
  102. # Sigmoid function: 1 / (1 + exp(A * score + B))
  103. calibrated = 1.0 / (1.0 + np.exp(self.platt_a * scaled_score + self.platt_b))
  104. else:
  105. # Simple clipping to [0, 1]
  106. calibrated = np.clip(scaled_score, 0.0, 1.0)
  107. # Additional adjustments based on context
  108. if additional_info:
  109. # Adjust based on VAD confidence
  110. vad_confidence = additional_info.get('vad_confidence', 1.0)
  111. calibrated *= vad_confidence
  112. # Adjust based on audio quality
  113. audio_quality = additional_info.get('audio_quality', 1.0)
  114. calibrated *= (0.5 + 0.5 * audio_quality) # Don't penalize too much
  115. # Adjust based on temporal consistency
  116. temporal_consistency = additional_info.get('temporal_consistency', 1.0)
  117. calibrated *= (0.8 + 0.2 * temporal_consistency)
  118. return float(np.clip(calibrated, 0.0, 1.0))
  119. def update_calibration(self, score: float, is_correct: bool):
  120. """Update calibration parameters based on feedback."""
  121. self.score_history.append(score)
  122. self.label_history.append(1.0 if is_correct else 0.0)
  123. # Simple adaptation of temperature
  124. if len(self.score_history) >= 50:
  125. scores = np.array(list(self.score_history))
  126. labels = np.array(list(self.label_history))
  127. # Compute accuracy at different temperature values
  128. temperatures = np.linspace(0.5, 2.0, 20)
  129. best_temp = 1.0
  130. best_accuracy = 0.0
  131. for temp in temperatures:
  132. calibrated_scores = scores / temp
  133. predictions = calibrated_scores > 0.5
  134. accuracy = np.mean(predictions == labels)
  135. if accuracy > best_accuracy:
  136. best_accuracy = accuracy
  137. best_temp = temp
  138. # Update temperature with momentum
  139. self.temperature = 0.9 * self.temperature + 0.1 * best_temp
  140. class VoiceRecognitionEngine:
  141. """
  142. Core voice recognition engine with real-time processing capabilities.
  143. Integrates VAD, feature extraction, speaker recognition, and confidence scoring
  144. for robust real-time speaker identification and verification.
  145. """
  146. def __init__(self,
  147. config: VoiceRecognitionConfig,
  148. feature_extractor: VRAudioFeatureExtractor,
  149. vad_detector: VoiceActivityDetector,
  150. speaker_manager: SpeakerManager,
  151. embedding_extractor: SpeakerEmbeddingExtractor):
  152. """
  153. Initialize voice recognition engine.
  154. Args:
  155. config: Voice recognition configuration
  156. feature_extractor: Audio feature extractor
  157. vad_detector: Voice activity detector
  158. speaker_manager: Speaker management system
  159. embedding_extractor: Speaker embedding extractor
  160. """
  161. self.config = config
  162. self.feature_extractor = feature_extractor
  163. self.vad_detector = vad_detector
  164. self.speaker_manager = speaker_manager
  165. self.embedding_extractor = embedding_extractor
  166. # Initialize confidence calibrator
  167. self.calibrator = ConfidenceCalibrator()
  168. # Temporal smoothing
  169. self.temporal_window_size = config.recognition_config.smoothing_window_size
  170. self.confidence_decay = config.recognition_config.confidence_decay_factor
  171. self.recent_results = deque(maxlen=self.temporal_window_size)
  172. # Performance monitoring
  173. self.processing_times = deque(maxlen=100)
  174. self.quality_scores = deque(maxlen=100)
  175. # Thread safety
  176. self._lock = threading.Lock()
  177. # Statistics
  178. self.stats = {
  179. 'total_processed': 0,
  180. 'speech_detected': 0,
  181. 'speakers_identified': 0,
  182. 'average_processing_time_ms': 0.0,
  183. 'average_confidence': 0.0
  184. }
  185. logger.info("Voice recognition engine initialized")
  186. def process_audio(self, audio_data: np.ndarray, sample_rate: int = None) -> RecognitionResult:
  187. """
  188. Process audio data for speaker recognition.
  189. Args:
  190. audio_data: Raw audio data
  191. sample_rate: Audio sample rate (uses config default if None)
  192. Returns:
  193. Recognition result
  194. """
  195. start_time = time.time()
  196. try:
  197. with self._lock:
  198. # Convert to torch tensor
  199. if isinstance(audio_data, np.ndarray):
  200. audio_tensor = torch.from_numpy(audio_data).float()
  201. else:
  202. audio_tensor = audio_data.float()
  203. # Ensure correct sample rate
  204. if sample_rate is None:
  205. sample_rate = self.config.audio_config.sample_rate
  206. # Step 1: Voice Activity Detection
  207. vad_result = self._perform_vad(audio_tensor, sample_rate)
  208. if not vad_result.is_speech:
  209. # No speech detected
  210. processing_time = (time.time() - start_time) * 1000
  211. return self._create_no_speech_result(vad_result, processing_time)
  212. # Step 2: Feature Extraction
  213. features = self._extract_features(audio_tensor)
  214. # Step 3: Speaker Recognition
  215. recognition_result = self._recognize_speaker(features, vad_result)
  216. # Step 4: Temporal Smoothing
  217. smoothed_result = self._apply_temporal_smoothing(recognition_result)
  218. # Step 5: Final Processing
  219. final_result = self._finalize_result(smoothed_result, start_time, len(audio_data) / sample_rate)
  220. # Update statistics
  221. self._update_statistics(final_result)
  222. return final_result
  223. except Exception as e:
  224. logger.error(f"Error processing audio: {e}")
  225. processing_time = (time.time() - start_time) * 1000
  226. return RecognitionResult(
  227. speaker_id=None,
  228. speaker_name=None,
  229. confidence=0.0,
  230. similarity_score=0.0,
  231. is_speech=False,
  232. vad_confidence=0.0,
  233. processing_time_ms=processing_time,
  234. audio_quality=0.0,
  235. start_time=0.0,
  236. end_time=len(audio_data) / (sample_rate or 16000),
  237. debug_info={'error': str(e)}
  238. )
  239. def identify_speaker(self, audio_data: np.ndarray, sample_rate: int = None) -> IdentificationResult:
  240. """
  241. Identify who is speaking in the audio.
  242. Args:
  243. audio_data: Raw audio data
  244. sample_rate: Audio sample rate
  245. Returns:
  246. Identification result
  247. """
  248. base_result = self.process_audio(audio_data, sample_rate)
  249. return IdentificationResult(
  250. speaker_id=base_result.speaker_id,
  251. speaker_name=base_result.speaker_name,
  252. confidence=base_result.confidence,
  253. similarity_score=base_result.similarity_score,
  254. is_speech=base_result.is_speech,
  255. vad_confidence=base_result.vad_confidence,
  256. processing_time_ms=base_result.processing_time_ms,
  257. audio_quality=base_result.audio_quality,
  258. start_time=base_result.start_time,
  259. end_time=base_result.end_time,
  260. timestamp=base_result.timestamp,
  261. threshold_used=base_result.threshold_used,
  262. alternative_speakers=base_result.alternative_speakers,
  263. debug_info=base_result.debug_info
  264. )
  265. def verify_speaker(self,
  266. audio_data: np.ndarray,
  267. expected_speaker_id: str,
  268. sample_rate: int = None) -> VerificationResult:
  269. """
  270. Verify if the speaker in audio matches expected speaker.
  271. Args:
  272. audio_data: Raw audio data
  273. expected_speaker_id: Expected speaker ID
  274. sample_rate: Audio sample rate
  275. Returns:
  276. Verification result
  277. """
  278. base_result = self.process_audio(audio_data, sample_rate)
  279. # Check if identified speaker matches expected
  280. verification_success = (
  281. base_result.speaker_id == expected_speaker_id and
  282. base_result.confidence >= self.config.recognition_config.verification_threshold
  283. )
  284. return VerificationResult(
  285. speaker_id=base_result.speaker_id,
  286. speaker_name=base_result.speaker_name,
  287. confidence=base_result.confidence,
  288. similarity_score=base_result.similarity_score,
  289. is_speech=base_result.is_speech,
  290. vad_confidence=base_result.vad_confidence,
  291. processing_time_ms=base_result.processing_time_ms,
  292. audio_quality=base_result.audio_quality,
  293. start_time=base_result.start_time,
  294. end_time=base_result.end_time,
  295. timestamp=base_result.timestamp,
  296. threshold_used=base_result.threshold_used,
  297. alternative_speakers=base_result.alternative_speakers,
  298. debug_info=base_result.debug_info,
  299. expected_speaker_id=expected_speaker_id,
  300. verification_success=verification_success
  301. )
  302. def _perform_vad(self, audio_tensor: torch.Tensor, sample_rate: int) -> VADResult:
  303. """Perform voice activity detection."""
  304. # Convert to numpy for VAD
  305. audio_np = audio_tensor.numpy()
  306. # Ensure correct sample rate for VAD
  307. if sample_rate != self.config.audio_config.sample_rate:
  308. # Simple resampling (in production, use proper resampling)
  309. target_length = int(len(audio_np) * self.config.audio_config.sample_rate / sample_rate)
  310. audio_np = np.interp(
  311. np.linspace(0, len(audio_np), target_length),
  312. np.arange(len(audio_np)),
  313. audio_np
  314. )
  315. return self.vad_detector.detect(audio_np)
  316. def _extract_features(self, audio_tensor: torch.Tensor) -> torch.Tensor:
  317. """Extract audio features."""
  318. return self.feature_extractor(audio_tensor)
  319. def _recognize_speaker(self, features: torch.Tensor, vad_result: VADResult) -> RecognitionResult:
  320. """Perform speaker recognition on features."""
  321. # Extract speaker embedding
  322. embedding = self.embedding_extractor.extract_embedding(features)
  323. # Compute audio quality
  324. audio_quality = self._compute_audio_quality(features, embedding)
  325. # Get all speaker embeddings for comparison
  326. speaker_embeddings = self.speaker_manager.database.get_all_speaker_embeddings("weighted_mean")
  327. if not speaker_embeddings:
  328. return RecognitionResult(
  329. speaker_id=None,
  330. speaker_name=None,
  331. confidence=0.0,
  332. similarity_score=0.0,
  333. is_speech=vad_result.is_speech,
  334. vad_confidence=vad_result.confidence,
  335. processing_time_ms=0.0,
  336. audio_quality=audio_quality,
  337. start_time=vad_result.start_time,
  338. end_time=vad_result.end_time
  339. )
  340. # Compute similarities to all speakers
  341. similarities = {}
  342. comparator = self.speaker_manager.comparator
  343. for speaker_id, speaker_embedding in speaker_embeddings.items():
  344. similarity = comparator.compute_similarity(embedding, speaker_embedding)
  345. similarities[speaker_id] = similarity
  346. # Find best match
  347. best_speaker_id = max(similarities, key=similarities.get)
  348. best_similarity = similarities[best_speaker_id]
  349. # Get speaker name
  350. speaker_profile = self.speaker_manager.database.get_speaker_by_id(best_speaker_id)
  351. speaker_name = speaker_profile.speaker_name if speaker_profile else "Unknown"
  352. # Calibrate confidence
  353. calibration_info = {
  354. 'vad_confidence': vad_result.confidence,
  355. 'audio_quality': audio_quality,
  356. 'temporal_consistency': self._compute_temporal_consistency(best_speaker_id)
  357. }
  358. confidence = self.calibrator.calibrate_confidence(best_similarity, calibration_info)
  359. # Get alternative speakers (top 3)
  360. sorted_similarities = sorted(similarities.items(), key=lambda x: x[1], reverse=True)
  361. alternative_speakers = [(spk_id, sim) for spk_id, sim in sorted_similarities[1:4]]
  362. return RecognitionResult(
  363. speaker_id=best_speaker_id,
  364. speaker_name=speaker_name,
  365. confidence=confidence,
  366. similarity_score=best_similarity,
  367. is_speech=vad_result.is_speech,
  368. vad_confidence=vad_result.confidence,
  369. processing_time_ms=0.0, # Will be set later
  370. audio_quality=audio_quality,
  371. start_time=vad_result.start_time,
  372. end_time=vad_result.end_time,
  373. threshold_used=self.config.recognition_config.identification_threshold,
  374. alternative_speakers=alternative_speakers,
  375. debug_info={
  376. 'all_similarities': similarities,
  377. 'embedding_norm': float(np.linalg.norm(embedding))
  378. }
  379. )
  380. def _compute_audio_quality(self, features: torch.Tensor, embedding: np.ndarray) -> float:
  381. """Compute overall audio quality score."""
  382. quality_factors = []
  383. # Feature-based quality
  384. feature_energy = torch.mean(features ** 2).item()
  385. energy_quality = min(1.0, feature_energy * 5) # Scale appropriately
  386. quality_factors.append(energy_quality)
  387. # Feature variance (too low might indicate poor audio)
  388. feature_var = torch.var(features).item()
  389. var_quality = min(1.0, feature_var * 10)
  390. quality_factors.append(var_quality)
  391. # Embedding quality (from extractor)
  392. embedding_quality = self.embedding_extractor.compute_embedding_quality(features, embedding)
  393. quality_factors.append(embedding_quality)
  394. # Signal-to-noise ratio estimate
  395. signal_power = torch.mean(features ** 2, dim=-1)
  396. noise_estimate = torch.min(signal_power)
  397. snr_estimate = torch.mean(signal_power) / (noise_estimate + 1e-8)
  398. snr_quality = min(1.0, snr_estimate.item() / 10)
  399. quality_factors.append(snr_quality)
  400. return float(np.mean(quality_factors))
  401. def _compute_temporal_consistency(self, speaker_id: str) -> float:
  402. """Compute temporal consistency with recent predictions."""
  403. if not self.recent_results:
  404. return 1.0
  405. # Count recent predictions for this speaker
  406. recent_count = sum(1 for result in self.recent_results if result.speaker_id == speaker_id)
  407. consistency = recent_count / len(self.recent_results)
  408. return consistency
  409. def _apply_temporal_smoothing(self, current_result: RecognitionResult) -> RecognitionResult:
  410. """Apply temporal smoothing to recognition results."""
  411. if not self.config.recognition_config.use_temporal_smoothing:
  412. return current_result
  413. # Add current result to history
  414. self.recent_results.append(current_result)
  415. if len(self.recent_results) < 2:
  416. return current_result
  417. # Compute weighted average of recent confidences for same speaker
  418. same_speaker_results = [r for r in self.recent_results if r.speaker_id == current_result.speaker_id]
  419. if same_speaker_results:
  420. # Apply exponential decay to weights
  421. weights = [self.confidence_decay ** i for i in range(len(same_speaker_results))]
  422. weights.reverse() # Most recent gets highest weight
  423. weighted_confidence = sum(w * r.confidence for w, r in zip(weights, same_speaker_results))
  424. total_weight = sum(weights)
  425. smoothed_confidence = weighted_confidence / total_weight
  426. # Update current result
  427. current_result.confidence = smoothed_confidence
  428. return current_result
  429. def _finalize_result(self, result: RecognitionResult, start_time: float, audio_duration: float) -> RecognitionResult:
  430. """Finalize recognition result with timing and quality checks."""
  431. # Set processing time
  432. processing_time = (time.time() - start_time) * 1000
  433. result.processing_time_ms = processing_time
  434. # Apply final confidence thresholding
  435. if result.confidence < self.config.recognition_config.identification_threshold:
  436. result.speaker_id = None
  437. result.speaker_name = None
  438. result.confidence = 0.0
  439. # Set audio timing
  440. if result.start_time == 0.0 and result.end_time == 0.0:
  441. result.start_time = 0.0
  442. result.end_time = audio_duration
  443. return result
  444. def _create_no_speech_result(self, vad_result: VADResult, processing_time: float) -> RecognitionResult:
  445. """Create result for when no speech is detected."""
  446. return RecognitionResult(
  447. speaker_id=None,
  448. speaker_name=None,
  449. confidence=0.0,
  450. similarity_score=0.0,
  451. is_speech=False,
  452. vad_confidence=vad_result.confidence,
  453. processing_time_ms=processing_time,
  454. audio_quality=0.0,
  455. start_time=vad_result.start_time,
  456. end_time=vad_result.end_time,
  457. debug_info={'vad_reason': 'No speech detected'}
  458. )
  459. def _update_statistics(self, result: RecognitionResult):
  460. """Update engine statistics."""
  461. self.stats['total_processed'] += 1
  462. if result.is_speech:
  463. self.stats['speech_detected'] += 1
  464. if result.speaker_id:
  465. self.stats['speakers_identified'] += 1
  466. # Update rolling averages
  467. self.processing_times.append(result.processing_time_ms)
  468. if result.is_speech:
  469. self.quality_scores.append(result.audio_quality)
  470. self.stats['average_processing_time_ms'] = np.mean(list(self.processing_times))
  471. if self.quality_scores:
  472. self.stats['average_confidence'] = np.mean([r.confidence for r in self.recent_results if r.is_speech])
  473. def get_statistics(self) -> Dict[str, Any]:
  474. """Get engine statistics."""
  475. stats = self.stats.copy()
  476. if stats['speech_detected'] > 0:
  477. stats['identification_rate'] = stats['speakers_identified'] / stats['speech_detected']
  478. else:
  479. stats['identification_rate'] = 0.0
  480. if stats['total_processed'] > 0:
  481. stats['speech_detection_rate'] = stats['speech_detected'] / stats['total_processed']
  482. else:
  483. stats['speech_detection_rate'] = 0.0
  484. return stats
  485. def reset_statistics(self):
  486. """Reset engine statistics."""
  487. self.stats = {
  488. 'total_processed': 0,
  489. 'speech_detected': 0,
  490. 'speakers_identified': 0,
  491. 'average_processing_time_ms': 0.0,
  492. 'average_confidence': 0.0
  493. }
  494. self.processing_times.clear()
  495. self.quality_scores.clear()
  496. self.recent_results.clear()
  497. def create_recognition_engine(config: VoiceRecognitionConfig,
  498. feature_extractor: VRAudioFeatureExtractor,
  499. vad_detector: VoiceActivityDetector,
  500. speaker_manager: SpeakerManager,
  501. embedding_extractor: SpeakerEmbeddingExtractor) -> VoiceRecognitionEngine:
  502. """
  503. Factory function to create voice recognition engine.
  504. Args:
  505. config: Voice recognition configuration
  506. feature_extractor: Audio feature extractor
  507. vad_detector: Voice activity detector
  508. speaker_manager: Speaker management system
  509. embedding_extractor: Speaker embedding extractor
  510. Returns:
  511. Configured voice recognition engine
  512. """
  513. return VoiceRecognitionEngine(
  514. config, feature_extractor, vad_detector, speaker_manager, embedding_extractor
  515. )
  516. # Example usage and testing
  517. def test_recognition_engine():
  518. """Test voice recognition engine functionality."""
  519. from .config import create_default_config
  520. from .audio_features import create_feature_extractor
  521. from .vad import create_vad_detector, VADConfig
  522. from .model_architectures import ECADATDNNModel
  523. from .speaker_embeddings import SpeakerEmbeddingExtractor
  524. from .speaker_manager import create_speaker_manager
  525. # Create components
  526. config = create_default_config("/tmp/test_model.pth")
  527. feature_extractor = create_feature_extractor("log_mel", sample_rate=16000)
  528. vad_config = VADConfig()
  529. vad_detector = create_vad_detector("energy", vad_config)
  530. model = ECADATDNNModel(input_dim=40, embedding_dim=192, num_speakers=4)
  531. embedding_extractor = SpeakerEmbeddingExtractor(model, "cpu")
  532. speaker_manager = create_speaker_manager("/tmp/test_speakers.pkl", embedding_extractor)
  533. # Create recognition engine
  534. engine = create_recognition_engine(
  535. config, feature_extractor, vad_detector, speaker_manager, embedding_extractor
  536. )
  537. # Test with mock audio
  538. print("Testing voice recognition engine...")
  539. # Generate test audio (sine wave + noise)
  540. sample_rate = 16000
  541. duration = 3.0
  542. t = np.linspace(0, duration, int(sample_rate * duration))
  543. audio = np.sin(2 * np.pi * 440 * t) + 0.1 * np.random.randn(len(t))
  544. # Test identification
  545. result = engine.identify_speaker(audio, sample_rate)
  546. print(f"Identification result: {result.speaker_name}, confidence: {result.confidence:.3f}")
  547. print(f"Processing time: {result.processing_time_ms:.1f}ms")
  548. print(f"Audio quality: {result.audio_quality:.3f}")
  549. # Test verification (will fail since no speakers enrolled)
  550. verification = engine.verify_speaker(audio, "test_speaker", sample_rate)
  551. print(f"Verification result: {verification.verification_success}, confidence: {verification.confidence:.3f}")
  552. # Get statistics
  553. stats = engine.get_statistics()
  554. print(f"Engine statistics: {stats}")
  555. if __name__ == "__main__":
  556. test_recognition_engine()