-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_integration.py
More file actions
executable file
·347 lines (278 loc) · 12.2 KB
/
Copy pathtest_integration.py
File metadata and controls
executable file
·347 lines (278 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/usr/bin/env python3
"""
Test script to verify ChirpKit MoE integration
This script tests the ChirpKit classifier integration to ensure it works
properly with the MoE (Mixture of Experts) system.
"""
import asyncio
import sys
import logging
import numpy as np
from pathlib import Path
# Add src to path for imports
sys.path.insert(0, str(Path(__file__).parent / "src"))
from chirpkit import InsectClassifier, DependencyManager
from chirpkit.models import find_any_model, list_models
from chirpkit.cli import classify_audio_file, get_classifier_instance
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class MockProcessedAudio:
"""Mock audio object for testing"""
def __init__(self, duration: float = 2.5, sample_rate: int = 16000):
self.duration = duration
self.sample_rate = sample_rate
# Generate realistic-sounding mock audio (chirp-like pattern)
t = np.linspace(0, duration, int(sample_rate * duration))
# Create a chirp pattern - frequency sweep with some harmonics
freq_sweep = np.linspace(2000, 8000, len(t))
self.waveform = (
0.5 * np.sin(2 * np.pi * freq_sweep * t) + # Main chirp
0.2 * np.sin(4 * np.pi * freq_sweep * t) + # Second harmonic
0.1 * np.sin(6 * np.pi * freq_sweep * t) + # Third harmonic
0.05 * np.random.randn(len(t)) # Background noise
)
# Apply envelope to make it more realistic
envelope = np.exp(-((t - duration/2) / (duration/4))**2)
self.waveform = self.waveform * envelope
async def test_dependency_management():
"""Test the dependency management system"""
logger.info("🔧 Testing dependency management...")
# Test PyTorch detection
torch = DependencyManager.get_torch()
if torch:
logger.info(f"✅ PyTorch detected: {torch.__version__}")
# Test device detection
if torch.cuda.is_available():
logger.info(f"🚀 CUDA available: {torch.cuda.device_count()} device(s)")
elif hasattr(torch.backends, 'mps') and torch.backends.mps.is_available():
logger.info("🍎 Apple MPS backend available")
else:
logger.info("💻 Using CPU backend")
else:
logger.warning("⚠️ PyTorch not available")
# Test TensorFlow detection (should show as not required)
tf = DependencyManager.get_tensorflow()
if tf:
logger.info(f"ℹ️ TensorFlow also available: {tf.__version__}")
else:
logger.info("ℹ️ TensorFlow not available (not required)")
# Check for failed imports
failed_imports = DependencyManager.get_failed_imports()
if failed_imports:
logger.warning(f"⚠️ Failed imports: {failed_imports}")
async def test_model_discovery():
"""Test model discovery and loading utilities"""
logger.info("🔍 Testing model discovery...")
# List available models
models = list_models()
logger.info(f"Available models: {list(models.keys())}")
for name, info in models.items():
logger.info(f" {name}: {info.get('status', 'unknown')} - {info.get('description', 'no description')}")
# Try to find any model
model_files = find_any_model()
if model_files:
model_path, encoder_path, info_path = model_files
logger.info(f"✅ Found model files:")
logger.info(f" Model: {model_path}")
logger.info(f" Encoder: {encoder_path}")
logger.info(f" Info: {info_path}")
return model_files
else:
logger.warning("⚠️ No model files found")
return None
async def test_classifier_initialization():
"""Test classifier initialization"""
logger.info("🧠 Testing classifier initialization...")
try:
classifier = InsectClassifier()
await classifier.initialize()
if classifier.is_available():
logger.info("✅ Classifier initialized successfully")
# Get model info
info = classifier.get_model_info()
logger.info(f"Model info: {info}")
# Get species list
species = classifier.get_species_list()
logger.info(f"Supports {len(species)} species")
logger.info(f"Example species: {species[:5]}")
return classifier
else:
logger.error("❌ Classifier not available after initialization")
return None
except Exception as e:
logger.error(f"❌ Classifier initialization failed: {e}")
return None
async def test_classification():
"""Test audio classification with mock data"""
logger.info("🎵 Testing audio classification...")
try:
classifier = InsectClassifier()
# Test with mock audio
mock_audio = MockProcessedAudio()
logger.info(f"Created mock audio: {mock_audio.duration}s at {mock_audio.sample_rate}Hz")
result = await classifier.classify(mock_audio, detailed=True)
logger.info("✅ Classification completed")
logger.info(f"Result format check:")
# Verify expected format
expected_keys = ['model', 'classification', 'confidence', 'predictions', 'features']
for key in expected_keys:
if key in result:
logger.info(f" ✓ {key}: present")
else:
logger.error(f" ✗ {key}: missing")
# Check classification sub-structure
if 'classification' in result:
classification = result['classification']
class_keys = ['is_insect', 'species', 'confidence', 'family']
for key in class_keys:
if key in classification:
logger.info(f" ✓ classification.{key}: {classification[key]}")
else:
logger.error(f" ✗ classification.{key}: missing")
# Show top predictions
if 'predictions' in result and result['predictions']:
logger.info("Top predictions:")
for i, pred in enumerate(result['predictions'][:3]):
logger.info(f" {i+1}. {pred['species']}: {pred['confidence']:.4f}")
return result
except Exception as e:
logger.error(f"❌ Classification test failed: {e}")
return None
async def test_cli_integration():
"""Test CLI integration functions"""
logger.info("🔧 Testing CLI integration...")
# Test audio file if one exists
test_audio = Path("test_audio/synthetic_insect.wav")
if test_audio.exists():
logger.info(f"Testing with real audio file: {test_audio}")
try:
result = classify_audio_file(str(test_audio))
logger.info("✅ CLI audio classification successful")
logger.info(f"Species: {result['classification']['species']}")
logger.info(f"Confidence: {result['classification']['confidence']:.4f}")
except Exception as e:
logger.error(f"❌ CLI audio classification failed: {e}")
else:
logger.info("ℹ️ No test audio file found, skipping file-based test")
# Test classifier instance creation
try:
classifier = get_classifier_instance()
logger.info("✅ CLI classifier instance created")
# Test compatibility methods
info = classifier.get_model_info()
species_count = len(classifier.get_species_list()) if classifier.get_species_list() else 0
logger.info(f"Species supported: {species_count}")
except Exception as e:
logger.error(f"❌ CLI classifier instance failed: {e}")
async def test_compatibility_methods():
"""Test backward compatibility methods"""
logger.info("🔄 Testing backward compatibility...")
try:
classifier = InsectClassifier()
# Test synchronous model loading
success = classifier.load_model()
if success:
logger.info("✅ Synchronous model loading works")
else:
logger.warning("⚠️ Synchronous model loading failed")
# Test compatibility with existing predict_audio method
test_audio = Path("test_audio/synthetic_insect.wav")
if test_audio.exists():
try:
result = classifier.predict_audio(str(test_audio))
logger.info("✅ Backward compatible predict_audio works")
logger.info(f"Result: {result['species']} ({result['confidence']:.4f})")
except Exception as e:
logger.error(f"❌ predict_audio compatibility failed: {e}")
except Exception as e:
logger.error(f"❌ Compatibility test failed: {e}")
async def run_all_tests():
"""Run all integration tests"""
logger.info("🚀 Starting ChirpKit MoE integration tests")
logger.info("=" * 50)
test_results = {}
# Test 1: Dependency Management
try:
await test_dependency_management()
test_results['dependencies'] = 'PASS'
except Exception as e:
logger.error(f"Dependency test failed: {e}")
test_results['dependencies'] = 'FAIL'
# Test 2: Model Discovery
try:
model_files = await test_model_discovery()
test_results['model_discovery'] = 'PASS' if model_files else 'WARN'
if not model_files:
logger.warning("⚠️ No models found - some tests may fail")
except Exception as e:
logger.error(f"Model discovery test failed: {e}")
test_results['model_discovery'] = 'FAIL'
# Test 3: Classifier Initialization
try:
classifier = await test_classifier_initialization()
test_results['initialization'] = 'PASS' if classifier else 'FAIL'
except Exception as e:
logger.error(f"Initialization test failed: {e}")
test_results['initialization'] = 'FAIL'
# Test 4: Classification
try:
result = await test_classification()
test_results['classification'] = 'PASS' if result else 'FAIL'
except Exception as e:
logger.error(f"Classification test failed: {e}")
test_results['classification'] = 'FAIL'
# Test 5: CLI Integration
try:
await test_cli_integration()
test_results['cli_integration'] = 'PASS'
except Exception as e:
logger.error(f"CLI integration test failed: {e}")
test_results['cli_integration'] = 'FAIL'
# Test 6: Compatibility
try:
await test_compatibility_methods()
test_results['compatibility'] = 'PASS'
except Exception as e:
logger.error(f"Compatibility test failed: {e}")
test_results['compatibility'] = 'FAIL'
# Results summary
logger.info("=" * 50)
logger.info("🎯 TEST RESULTS SUMMARY")
logger.info("=" * 50)
all_passed = True
for test_name, result in test_results.items():
status_icon = "✅" if result == 'PASS' else "⚠️" if result == 'WARN' else "❌"
logger.info(f"{status_icon} {test_name.replace('_', ' ').title()}: {result}")
if result == 'FAIL':
all_passed = False
if all_passed:
logger.info("\n🎉 ALL TESTS PASSED - ChirpKit is ready for MoE integration!")
else:
logger.info("\n🔧 Some tests failed - please check the logs above")
return test_results
def main():
"""Main test runner"""
try:
# Run all tests
results = asyncio.run(run_all_tests())
# Exit with error code if any critical tests failed
critical_tests = ['dependencies', 'initialization', 'classification']
critical_failures = [test for test in critical_tests if results.get(test) == 'FAIL']
if critical_failures:
logger.error(f"Critical test failures: {critical_failures}")
sys.exit(1)
else:
logger.info("✅ Integration test completed successfully")
sys.exit(0)
except KeyboardInterrupt:
logger.info("Test interrupted by user")
sys.exit(130)
except Exception as e:
logger.error(f"Test runner failed: {e}")
sys.exit(1)
if __name__ == "__main__":
main()