|
""" |
|
Test Modal Final Improvements - Updated for new service architecture |
|
Tests model preloading, distributed processing with enhanced segmentation, and speaker diarization |
|
""" |
|
|
|
import asyncio |
|
import pytest |
|
import os |
|
import time |
|
from pathlib import Path |
|
|
|
|
|
from src.services import ( |
|
ModalTranscriptionService, |
|
ModalDownloadService, |
|
HealthService, |
|
TranscriptionService, |
|
DistributedTranscriptionService |
|
) |
|
|
|
|
|
from src.tools.transcription_tools import ( |
|
transcribe_audio_file_tool, |
|
check_modal_endpoints_health, |
|
get_system_status |
|
) |
|
|
|
from src.tools.download_tools import ( |
|
get_file_info_tool, |
|
read_text_file_segments_tool |
|
) |
|
|
|
|
|
class TestModalFinalImprovements: |
|
"""Test suite for Modal improvements with new architecture""" |
|
|
|
@pytest.mark.asyncio |
|
async def test_model_preloading_health_check(self): |
|
"""Test that models are properly preloaded in Modal""" |
|
print("\nποΈ Testing model preloading health check...") |
|
|
|
health_status = await check_modal_endpoints_health() |
|
|
|
|
|
assert "health_check" in health_status, "Health check endpoint not found" |
|
health_endpoint = health_status["health_check"] |
|
|
|
if health_endpoint["status"] == "healthy": |
|
print("β
Health check endpoint is accessible") |
|
|
|
|
|
system_status = await get_system_status() |
|
|
|
|
|
whisper_status = system_status.get("whisper", {}) |
|
print(f"π€ Whisper status: {whisper_status.get('status', 'unknown')}") |
|
print(f"π― Default model: {whisper_status.get('default_model', 'unknown')}") |
|
print(f"π¦ Model cache exists: {whisper_status.get('model_cache_exists', False)}") |
|
|
|
|
|
available_models = whisper_status.get("available_models", []) |
|
assert "turbo" in available_models, f"Turbo model not available. Available: {available_models}" |
|
|
|
|
|
speaker_status = system_status.get("speaker_diarization", {}) |
|
print(f"π₯ Speaker diarization: {speaker_status.get('status', 'unknown')}") |
|
print(f"π HF Token available: {speaker_status.get('hf_token_available', False)}") |
|
|
|
else: |
|
print(f"β οΈ Health check endpoint not healthy: {health_endpoint.get('error', 'Unknown error')}") |
|
pytest.skip("Health check endpoint not accessible") |
|
|
|
@pytest.mark.asyncio |
|
async def test_distributed_processing_with_turbo_model(self): |
|
"""Test distributed processing using turbo model""" |
|
print("\nπ Testing distributed processing with turbo model...") |
|
|
|
|
|
test_audio_files = [ |
|
"tests/cache/apple_podcast_episode.mp3", |
|
"tests/cache/xyz_podcast_episode.mp3" |
|
] |
|
|
|
available_files = [f for f in test_audio_files if os.path.exists(f)] |
|
|
|
if not available_files: |
|
pytest.skip("No test audio files available. Run real-world integration tests first.") |
|
|
|
|
|
test_file = max(available_files, key=lambda f: os.path.getsize(f)) |
|
file_size_mb = os.path.getsize(test_file) / (1024 * 1024) |
|
|
|
print(f"π Using test file: {test_file} ({file_size_mb:.2f} MB)") |
|
|
|
start_time = time.time() |
|
|
|
|
|
result = await transcribe_audio_file_tool( |
|
audio_file_path=test_file, |
|
model_size="turbo", |
|
language=None, |
|
output_format="srt", |
|
enable_speaker_diarization=False, |
|
use_parallel_processing=True, |
|
chunk_duration=60, |
|
use_intelligent_segmentation=True |
|
) |
|
|
|
end_time = time.time() |
|
processing_time = end_time - start_time |
|
|
|
|
|
assert result["processing_status"] == "success", \ |
|
f"Distributed transcription failed: {result.get('error_message', 'Unknown error')}" |
|
|
|
|
|
distributed_processing = result.get("distributed_processing", False) |
|
chunks_processed = result.get("chunks_processed", 0) |
|
chunks_failed = result.get("chunks_failed", 0) |
|
segmentation_type = result.get("segmentation_type", "unknown") |
|
|
|
print(f"π Distributed processing results:") |
|
print(f" Processing time: {processing_time:.2f}s") |
|
print(f" Model used: {result.get('model_used', 'unknown')}") |
|
print(f" Segments: {result.get('segment_count', 0)}") |
|
print(f" Duration: {result.get('audio_duration', 0):.2f}s") |
|
print(f" Language: {result.get('language_detected', 'unknown')}") |
|
print(f" Distributed processing: {distributed_processing}") |
|
print(f" Chunks processed: {chunks_processed}") |
|
print(f" Chunks failed: {chunks_failed}") |
|
print(f" Segmentation type: {segmentation_type}") |
|
|
|
|
|
if result.get("audio_duration", 0) > 120: |
|
assert distributed_processing, "Distributed processing should be used for long audio files" |
|
assert chunks_processed > 1, f"Expected multiple chunks, got {chunks_processed}" |
|
|
|
|
|
assert result.get("model_used") == "turbo", \ |
|
f"Expected turbo model, got {result.get('model_used')}" |
|
|
|
|
|
|
|
assert result.get("segment_count", 0) > 0, "No transcription segments found" |
|
assert result.get("audio_duration", 0) > 0, "No audio duration detected" |
|
|
|
def test_health_check_with_model_preloading(self): |
|
"""Test health service functionality""" |
|
print("\nπ Testing health service with model preloading...") |
|
|
|
health_service = HealthService() |
|
|
|
|
|
whisper_status = health_service._check_whisper_models() |
|
print(f"π€ Whisper status: {whisper_status}") |
|
|
|
assert whisper_status["default_model"] == "turbo" |
|
assert "turbo" in whisper_status["available_models"] |
|
|
|
|
|
speaker_status = health_service._check_speaker_diarization() |
|
print(f"π₯ Speaker status: {speaker_status}") |
|
|
|
|
|
assert speaker_status["status"] in ["healthy", "partial", "disabled"] |
|
|
|
def test_speaker_diarization_pipeline_loading(self): |
|
"""Test speaker diarization pipeline loading""" |
|
print("\nπ₯ Testing speaker diarization pipeline...") |
|
|
|
transcription_service = TranscriptionService() |
|
|
|
|
|
pipeline = transcription_service._load_speaker_diarization_pipeline() |
|
|
|
if pipeline is not None: |
|
print("β
Speaker diarization pipeline loaded successfully") |
|
|
|
assert hasattr(pipeline, '__call__'), "Pipeline should be callable" |
|
else: |
|
print("β οΈ Speaker diarization pipeline not available (likely missing HF_TOKEN)") |
|
|
|
|
|
@pytest.mark.asyncio |
|
async def test_transcription_service_with_speaker_diarization(self): |
|
"""Test local transcription service with speaker diarization""" |
|
print("\nπ€ Testing transcription service with speaker diarization...") |
|
|
|
|
|
test_audio_files = [ |
|
"tests/cache/apple_podcast_episode.mp3", |
|
"tests/cache/xyz_podcast_episode.mp3" |
|
] |
|
|
|
available_files = [f for f in test_audio_files if os.path.exists(f)] |
|
|
|
if not available_files: |
|
pytest.skip("No test audio files available") |
|
|
|
|
|
test_file = min(available_files, key=lambda f: os.path.getsize(f)) |
|
|
|
transcription_service = TranscriptionService() |
|
|
|
|
|
result = transcription_service.transcribe_audio( |
|
audio_file_path=test_file, |
|
model_size="turbo", |
|
enable_speaker_diarization=True |
|
) |
|
|
|
assert result["processing_status"] == "success" |
|
assert result["model_used"] == "turbo" |
|
|
|
|
|
speaker_enabled = result.get("speaker_diarization_enabled", False) |
|
speaker_count = result.get("global_speaker_count", 0) |
|
|
|
print(f"π₯ Speaker diarization enabled: {speaker_enabled}") |
|
print(f"π₯ Speakers detected: {speaker_count}") |
|
|
|
if speaker_enabled: |
|
print("β
Speaker diarization worked successfully") |
|
else: |
|
print("β οΈ Speaker diarization was disabled (likely missing dependencies)") |
|
|
|
@pytest.mark.asyncio |
|
async def test_speaker_diarization_with_real_audio(self): |
|
"""Test speaker diarization with real audio file""" |
|
print("\nπ― Testing speaker diarization with real audio...") |
|
|
|
|
|
test_audio_files = [ |
|
"tests/cache/apple_podcast_episode.mp3", |
|
"tests/cache/xyz_podcast_episode.mp3" |
|
] |
|
|
|
available_files = [f for f in test_audio_files if os.path.exists(f)] |
|
|
|
if not available_files: |
|
pytest.skip("No test audio files available") |
|
|
|
test_file = available_files[0] |
|
|
|
|
|
transcription_service = TranscriptionService() |
|
|
|
result = transcription_service.transcribe_audio( |
|
audio_file_path=test_file, |
|
model_size="turbo", |
|
enable_speaker_diarization=True |
|
) |
|
|
|
assert result["processing_status"] == "success" |
|
|
|
|
|
speakers_detected = result.get("global_speaker_count", 0) |
|
speaker_enabled = result.get("speaker_diarization_enabled", False) |
|
|
|
print(f"π― Speaker diarization results:") |
|
print(f" Enabled: {speaker_enabled}") |
|
print(f" Speakers detected: {speakers_detected}") |
|
print(f" Audio duration: {result.get('audio_duration', 0):.2f}s") |
|
print(f" Segments: {result.get('segment_count', 0)}") |
|
|
|
@pytest.mark.asyncio |
|
async def test_distributed_transcription_with_speaker_diarization(self): |
|
"""Test distributed transcription with speaker diarization""" |
|
print("\nπ― Testing distributed transcription with speaker diarization...") |
|
|
|
|
|
distributed_service = DistributedTranscriptionService() |
|
|
|
|
|
test_file = "dummy_audio.mp3" |
|
|
|
|
|
try: |
|
segments = distributed_service.choose_segmentation_strategy(test_file) |
|
|
|
print("β
Distributed service properly handles missing files without exceptions") |
|
except Exception as e: |
|
|
|
print(f"β
Distributed service properly detected missing file: {type(e).__name__}") |
|
|
|
|
|
test_audio_files = [ |
|
"tests/cache/apple_podcast_episode.mp3", |
|
"tests/cache/xyz_podcast_episode.mp3" |
|
] |
|
|
|
available_files = [f for f in test_audio_files if os.path.exists(f)] |
|
|
|
if available_files: |
|
test_file = available_files[0] |
|
try: |
|
segments = distributed_service.choose_segmentation_strategy(test_file) |
|
print(f"β
Segmentation strategy worked for real file: {segments}") |
|
except Exception as e: |
|
print(f"β οΈ Segmentation strategy failed: {e}") |
|
else: |
|
print("β οΈ No test audio files available for segmentation testing") |
|
|
|
def test_local_startup_with_new_architecture(self): |
|
"""Test that all imports work correctly in new architecture""" |
|
print("\nπ Testing local startup with new architecture...") |
|
|
|
|
|
try: |
|
from src.services.transcription_service import TranscriptionService |
|
print("β
TranscriptionService imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import TranscriptionService: {e}") |
|
|
|
try: |
|
from src.services.distributed_transcription_service import DistributedTranscriptionService |
|
print("β
DistributedTranscriptionService imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import DistributedTranscriptionService: {e}") |
|
|
|
try: |
|
from src.services.health_service import HealthService |
|
print("β
HealthService imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import HealthService: {e}") |
|
|
|
|
|
try: |
|
from src.services.modal_transcription_service import ModalTranscriptionService |
|
|
|
print("β
Modal services imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import Modal services: {e}") |
|
|
|
|
|
try: |
|
from src.tools.transcription_tools import ( |
|
transcribe_audio_file_tool, |
|
check_modal_endpoints_health |
|
) |
|
print("β
Transcription tools imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import transcription tools: {e}") |
|
|
|
try: |
|
from src.tools.download_tools import ( |
|
get_file_info_tool, |
|
read_text_file_segments_tool |
|
) |
|
print("β
Download tools imported successfully") |
|
except ImportError as e: |
|
pytest.fail(f"Failed to import download tools: {e}") |
|
|
|
|
|
try: |
|
from src.services import get_service, list_available_services |
|
|
|
|
|
transcription_service = get_service("transcription") |
|
assert transcription_service is not None |
|
|
|
modal_service = get_service("modal_transcription") |
|
assert modal_service is not None |
|
|
|
|
|
available_services = list_available_services() |
|
assert "transcription" in available_services |
|
assert "modal_transcription" in available_services |
|
|
|
print("β
Service registry working correctly") |
|
except Exception as e: |
|
pytest.fail(f"Service registry error: {e}") |
|
|
|
@pytest.mark.asyncio |
|
async def test_modal_endpoints_availability(self): |
|
"""Test Modal endpoints availability""" |
|
print("\nπ Testing Modal endpoints availability...") |
|
|
|
modal_service = ModalTranscriptionService() |
|
|
|
health_status = await modal_service.check_endpoints_health() |
|
|
|
print(f"π Endpoint health status:") |
|
for endpoint_name, status in health_status.items(): |
|
print(f" {endpoint_name}: {status.get('status', 'unknown')}") |
|
|
|
|
|
health_check_status = health_status.get("health_check", {}) |
|
if health_check_status.get("status") == "healthy": |
|
print("β
Health check endpoint is working") |
|
else: |
|
print("β οΈ Health check endpoint may not be available") |
|
|
|
def test_model_cache_usage(self): |
|
"""Test model cache usage in transcription service""" |
|
print("\nπ¦ Testing model cache usage...") |
|
|
|
transcription_service = TranscriptionService() |
|
|
|
|
|
model = transcription_service._load_cached_model("turbo") |
|
assert model is not None |
|
|
|
print("β
Model loading successful") |
|
|
|
|
|
pipeline = transcription_service._load_speaker_diarization_pipeline() |
|
|
|
if pipeline is not None: |
|
print("β
Speaker diarization pipeline loaded") |
|
else: |
|
print("β οΈ Speaker diarization pipeline not available") |
|
|
|
|
|
if __name__ == "__main__": |
|
pytest.main([__file__, "-v"]) |