TwiSpeechModel / test_engine.py
ProvLeon's picture
Upload folder using huggingface_hub
6db3515 verified
Raw
History Blame Contribute Delete
13.8 kB
#!/usr/bin/env python3
"""
Test Suite for Optimized Twi Speech Recognition Engine
=====================================================
This module provides comprehensive tests for the optimized speech recognition
engine to ensure all components work correctly.
Author: AI Assistant
Date: 2025-11-05
"""
import os
import sys
import time
import tempfile
import logging
from pathlib import Path
import asyncio
# Add src to path
sys.path.insert(0, str(Path(__file__).parent / "src"))
import numpy as np
import soundfile as sf
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class EngineTestSuite:
"""Test suite for the optimized speech recognition engine."""
def __init__(self):
self.test_results = {}
self.temp_files = []
def cleanup(self):
"""Clean up temporary files."""
for file_path in self.temp_files:
try:
if Path(file_path).exists():
Path(file_path).unlink()
except Exception as e:
logger.warning(f"Failed to cleanup {file_path}: {e}")
def create_test_audio(self, duration=3.0, sample_rate=16000, frequency=440) -> str:
"""Create a test audio file."""
# Generate sine wave
t = np.linspace(0, duration, int(sample_rate * duration), False)
audio = np.sin(frequency * 2 * np.pi * t)
# Add some noise to make it more realistic
noise = np.random.normal(0, 0.01, audio.shape)
audio = audio + noise
# Save to temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as tmp_file:
sf.write(tmp_file.name, audio, sample_rate)
self.temp_files.append(tmp_file.name)
return tmp_file.name
def test_config_import(self) -> bool:
"""Test configuration import."""
try:
from config.config import OptimizedConfig
config = OptimizedConfig()
# Basic validation
assert hasattr(config, "WHISPER")
assert hasattr(config, "INTENTS")
assert len(config.INTENTS) > 0
logger.info(
f"βœ… Config test passed - {len(config.INTENTS)} intents configured"
)
return True
except Exception as e:
logger.error(f"❌ Config test failed: {e}")
return False
def test_speech_recognizer_import(self) -> bool:
"""Test speech recognizer import."""
try:
from speech_recognizer import (
OptimizedSpeechRecognizer,
create_speech_recognizer,
)
# Try to create recognizer
recognizer = create_speech_recognizer()
# Basic validation
assert recognizer is not None
assert hasattr(recognizer, "recognize")
assert hasattr(recognizer, "health_check")
logger.info("βœ… Speech recognizer import test passed")
return True
except Exception as e:
logger.error(f"❌ Speech recognizer import failed: {e}")
return False
def test_whisper_model_load(self) -> bool:
"""Test Whisper model loading."""
try:
import whisper
# Try to load a small model for testing
model = whisper.load_model("tiny")
assert model is not None
# Test basic transcription
test_audio = self.create_test_audio(duration=1.0)
result = model.transcribe(test_audio)
assert "text" in result
logger.info("βœ… Whisper model test passed")
return True
except Exception as e:
logger.error(f"❌ Whisper model test failed: {e}")
return False
def test_audio_processing(self) -> bool:
"""Test audio processing functionality."""
try:
from speech_recognizer import AudioProcessor
from config.config import OptimizedConfig
config = OptimizedConfig()
processor = AudioProcessor(config)
# Create test audio
test_audio = self.create_test_audio()
# Test audio loading
audio_data = processor.load_audio(test_audio)
assert audio_data is not None
assert len(audio_data) > 0
logger.info("βœ… Audio processing test passed")
return True
except Exception as e:
logger.error(f"❌ Audio processing test failed: {e}")
return False
def test_intent_classification(self) -> bool:
"""Test intent classification."""
try:
from speech_recognizer import TwiIntentClassifier
from config.config import OptimizedConfig
config = OptimizedConfig()
classifier = TwiIntentClassifier(config)
# Test classification with sample Twi text
test_texts = [
"KΙ” fie", # Go home
"KΙ” cart mu", # Go to cart
"HwehwΙ› nneΙ›ma", # Search items
"Boa me", # Help me
"Tua ka", # Make payment
]
for text in test_texts:
result = classifier.classify_intent(text)
assert "intent" in result
assert "confidence" in result
assert result["confidence"] >= 0.0
logger.info("βœ… Intent classification test passed")
return True
except Exception as e:
logger.error(f"❌ Intent classification test failed: {e}")
return False
def test_end_to_end_recognition(self) -> bool:
"""Test complete speech recognition pipeline."""
try:
from speech_recognizer import create_speech_recognizer
# Create recognizer with test configuration
config_overrides = {
"WHISPER": {"model_size": "tiny"} # Use tiny model for faster testing
}
recognizer = create_speech_recognizer(config_overrides)
# Create test audio
test_audio = self.create_test_audio(duration=2.0)
# Perform recognition
result = recognizer.recognize(test_audio)
# Validate result structure
assert "transcription" in result
assert "intent" in result
assert "status" in result
if result["status"] == "success":
assert "text" in result["transcription"]
assert "intent" in result["intent"]
logger.info(f"βœ… End-to-end test passed - Status: {result['status']}")
else:
logger.warning(
f"⚠️ End-to-end test completed with status: {result['status']}"
)
return True
except Exception as e:
logger.error(f"❌ End-to-end test failed: {e}")
return False
async def test_async_recognition(self) -> bool:
"""Test asynchronous recognition."""
try:
from speech_recognizer import create_speech_recognizer
recognizer = create_speech_recognizer()
test_audio = self.create_test_audio(duration=1.0)
# Test async recognition
result = await recognizer.recognize_async(test_audio)
assert "transcription" in result
assert "intent" in result
logger.info("βœ… Async recognition test passed")
return True
except Exception as e:
logger.error(f"❌ Async recognition test failed: {e}")
return False
def test_health_check(self) -> bool:
"""Test system health check."""
try:
from speech_recognizer import create_speech_recognizer
recognizer = create_speech_recognizer()
health = recognizer.health_check()
assert "status" in health
assert "components" in health
assert health["status"] in ["healthy", "degraded", "unhealthy"]
logger.info(f"βœ… Health check test passed - Status: {health['status']}")
return True
except Exception as e:
logger.error(f"❌ Health check test failed: {e}")
return False
def test_api_server_import(self) -> bool:
"""Test API server import."""
try:
from api_server import app
assert app is not None
logger.info("βœ… API server import test passed")
return True
except Exception as e:
logger.error(f"❌ API server import failed: {e}")
return False
def test_supported_intents(self) -> bool:
"""Test supported intents functionality."""
try:
from speech_recognizer import create_speech_recognizer
recognizer = create_speech_recognizer()
intents = recognizer.get_supported_intents()
assert isinstance(intents, list)
assert len(intents) > 0
# Check structure of first intent
if intents:
intent = intents[0]
assert "intent" in intent
assert "description" in intent
assert "examples" in intent
logger.info(
f"βœ… Supported intents test passed - {len(intents)} intents found"
)
return True
except Exception as e:
logger.error(f"❌ Supported intents test failed: {e}")
return False
def test_statistics(self) -> bool:
"""Test statistics functionality."""
try:
from speech_recognizer import create_speech_recognizer
recognizer = create_speech_recognizer()
stats = recognizer.get_statistics()
assert isinstance(stats, dict)
assert "total_requests" in stats
assert "successful_requests" in stats
logger.info("βœ… Statistics test passed")
return True
except Exception as e:
logger.error(f"❌ Statistics test failed: {e}")
return False
async def run_all_tests(self) -> Dict[str, bool]:
"""Run all tests and return results."""
tests = [
("config_import", self.test_config_import),
("speech_recognizer_import", self.test_speech_recognizer_import),
("whisper_model_load", self.test_whisper_model_load),
("audio_processing", self.test_audio_processing),
("intent_classification", self.test_intent_classification),
("end_to_end_recognition", self.test_end_to_end_recognition),
("health_check", self.test_health_check),
("api_server_import", self.test_api_server_import),
("supported_intents", self.test_supported_intents),
("statistics", self.test_statistics),
]
# Run async tests
async_tests = [
("async_recognition", self.test_async_recognition),
]
logger.info("=" * 60)
logger.info("OPTIMIZED TWI SPEECH ENGINE - TEST SUITE")
logger.info("=" * 60)
# Run synchronous tests
for test_name, test_func in tests:
logger.info(f"\nRunning {test_name}...")
try:
self.test_results[test_name] = test_func()
except Exception as e:
logger.error(f"Test {test_name} crashed: {e}")
self.test_results[test_name] = False
# Run asynchronous tests
for test_name, test_func in async_tests:
logger.info(f"\nRunning {test_name}...")
try:
self.test_results[test_name] = await test_func()
except Exception as e:
logger.error(f"Test {test_name} crashed: {e}")
self.test_results[test_name] = False
# Summary
self.print_test_summary()
return self.test_results
def print_test_summary(self):
"""Print test results summary."""
logger.info("\n" + "=" * 60)
logger.info("TEST RESULTS SUMMARY")
logger.info("=" * 60)
passed = sum(1 for result in self.test_results.values() if result)
total = len(self.test_results)
for test_name, result in self.test_results.items():
status = "βœ… PASS" if result else "❌ FAIL"
logger.info(f"{test_name:25s} {status}")
logger.info("-" * 60)
logger.info(
f"TOTAL: {passed}/{total} tests passed ({passed / total * 100:.1f}%)"
)
if passed == total:
logger.info("πŸŽ‰ ALL TESTS PASSED! Engine is ready for use.")
elif passed >= total * 0.8:
logger.info("⚠️ Most tests passed. Engine should work with minor issues.")
else:
logger.info("❌ Multiple test failures. Please check the setup.")
logger.info("=" * 60)
async def main():
"""Main test function."""
test_suite = EngineTestSuite()
try:
results = await test_suite.run_all_tests()
# Cleanup
test_suite.cleanup()
# Exit with appropriate code
passed = sum(1 for result in results.values() if result)
total = len(results)
if passed == total:
sys.exit(0) # All tests passed
elif passed >= total * 0.8:
sys.exit(1) # Most tests passed but some issues
else:
sys.exit(2) # Multiple failures
except Exception as e:
logger.error(f"Test suite crashed: {e}")
test_suite.cleanup()
sys.exit(3)
if __name__ == "__main__":
asyncio.run(main())