Spaces:
Runtime error
Runtime error
Pranav Mishra
commited on
Commit
·
a26c11a
1
Parent(s):
93ceaba
Fix performance issues: updated requirements with exact versions and added model caching
Browse files- app.py +34 -10
- requirements_hf.txt +15 -9
app.py
CHANGED
|
@@ -12,8 +12,9 @@ from typing import Dict, Any, Optional
|
|
| 12 |
from dotenv import load_dotenv
|
| 13 |
import numpy as np
|
| 14 |
|
| 15 |
-
# Import audio processors (only
|
| 16 |
from audio_processors.external_api import ExternalAPIProcessor
|
|
|
|
| 17 |
from audio_processors.ml_mfcc_processor import MLMFCCProcessor
|
| 18 |
from audio_processors.ml_mel_cnn_processor import MLMelCNNProcessor
|
| 19 |
from audio_processors.ml_raw_cnn_processor import MLRawCNNProcessor
|
|
@@ -44,8 +45,18 @@ def allowed_file(filename: str) -> bool:
|
|
| 44 |
"""Check if file extension is allowed."""
|
| 45 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 46 |
|
|
|
|
|
|
|
|
|
|
| 47 |
def initialize_processors():
|
| 48 |
-
"""Initialize audio processors optimized for HF Spaces deployment."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
procs = {}
|
| 50 |
|
| 51 |
# ML-trained processors (high priority - use best models only)
|
|
@@ -58,11 +69,13 @@ def initialize_processors():
|
|
| 58 |
ml_working_count = 0
|
| 59 |
for proc_key, proc_class, proc_name in ml_processors:
|
| 60 |
try:
|
|
|
|
|
|
|
| 61 |
processor = proc_class()
|
| 62 |
if processor.is_configured():
|
| 63 |
procs[proc_key] = processor
|
| 64 |
ml_working_count += 1
|
| 65 |
-
app.logger.info(f"[OK] {proc_name} loaded successfully")
|
| 66 |
else:
|
| 67 |
app.logger.warning(f"[WARN] {proc_name} not configured (model files missing)")
|
| 68 |
except Exception as e:
|
|
@@ -73,20 +86,31 @@ def initialize_processors():
|
|
| 73 |
external_processor = ExternalAPIProcessor()
|
| 74 |
if external_processor.is_configured():
|
| 75 |
procs['external_api'] = external_processor
|
| 76 |
-
app.logger.info("[OK] External API processor initialized")
|
| 77 |
else:
|
| 78 |
app.logger.warning("[WARN] External API not configured")
|
| 79 |
except Exception as e:
|
| 80 |
app.logger.error(f"[FAIL] Failed to initialize External API: {str(e)}")
|
| 81 |
|
| 82 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
|
| 84 |
app.logger.info(f"Processor initialization complete:")
|
| 85 |
app.logger.info(f" ML Models loaded: {ml_working_count}/3")
|
| 86 |
-
app.logger.info(f" Total processors: {len(procs)}")
|
| 87 |
|
| 88 |
return procs
|
| 89 |
|
|
|
|
| 90 |
processors = initialize_processors()
|
| 91 |
|
| 92 |
@app.route('/')
|
|
@@ -95,7 +119,7 @@ def index():
|
|
| 95 |
return jsonify({
|
| 96 |
'message': 'Streaming Digit Classifier API',
|
| 97 |
'status': 'running',
|
| 98 |
-
'version': '1.
|
| 99 |
'available_processors': list(processors.keys()),
|
| 100 |
'documentation': 'Frontend at Vercel, Backend API at HF Spaces'
|
| 101 |
})
|
|
@@ -173,7 +197,7 @@ def process_audio():
|
|
| 173 |
result.update({
|
| 174 |
'audio_duration': round(duration, 3),
|
| 175 |
'file_size': len(audio_data),
|
| 176 |
-
'api_version': '1.
|
| 177 |
})
|
| 178 |
|
| 179 |
app.logger.info(f"Processed audio with {method}: '{result['predicted_digit']}' in {result['inference_time']}s")
|
|
@@ -231,7 +255,7 @@ def process_audio_chunk():
|
|
| 231 |
'segment_index': 0,
|
| 232 |
'segment_size': len(standardized_audio),
|
| 233 |
'is_streaming': True,
|
| 234 |
-
'api_version': '1.
|
| 235 |
})
|
| 236 |
|
| 237 |
app.logger.info(f"Streaming prediction: '{result['predicted_digit']}' "
|
|
@@ -294,7 +318,7 @@ def health_check():
|
|
| 294 |
'status': 'healthy',
|
| 295 |
'timestamp': time.time(),
|
| 296 |
'processors': processor_health,
|
| 297 |
-
'version': '1.
|
| 298 |
'deployment': 'huggingface-spaces'
|
| 299 |
})
|
| 300 |
|
|
|
|
| 12 |
from dotenv import load_dotenv
|
| 13 |
import numpy as np
|
| 14 |
|
| 15 |
+
# Import audio processors (only essential ones for deployment)
|
| 16 |
from audio_processors.external_api import ExternalAPIProcessor
|
| 17 |
+
from audio_processors.whisper_digit_processor import WhisperDigitProcessor
|
| 18 |
from audio_processors.ml_mfcc_processor import MLMFCCProcessor
|
| 19 |
from audio_processors.ml_mel_cnn_processor import MLMelCNNProcessor
|
| 20 |
from audio_processors.ml_raw_cnn_processor import MLRawCNNProcessor
|
|
|
|
| 45 |
"""Check if file extension is allowed."""
|
| 46 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 47 |
|
| 48 |
+
# Global processor cache for model persistence
|
| 49 |
+
_processor_cache = {}
|
| 50 |
+
|
| 51 |
def initialize_processors():
|
| 52 |
+
"""Initialize audio processors optimized for HF Spaces deployment with caching."""
|
| 53 |
+
global _processor_cache
|
| 54 |
+
|
| 55 |
+
# Return cached processors if already initialized
|
| 56 |
+
if _processor_cache:
|
| 57 |
+
app.logger.info(f"Using cached processors: {len(_processor_cache)} available")
|
| 58 |
+
return _processor_cache
|
| 59 |
+
|
| 60 |
procs = {}
|
| 61 |
|
| 62 |
# ML-trained processors (high priority - use best models only)
|
|
|
|
| 69 |
ml_working_count = 0
|
| 70 |
for proc_key, proc_class, proc_name in ml_processors:
|
| 71 |
try:
|
| 72 |
+
# Initialize once and cache
|
| 73 |
+
app.logger.info(f"Loading {proc_name}...")
|
| 74 |
processor = proc_class()
|
| 75 |
if processor.is_configured():
|
| 76 |
procs[proc_key] = processor
|
| 77 |
ml_working_count += 1
|
| 78 |
+
app.logger.info(f"[OK] {proc_name} loaded successfully (cached)")
|
| 79 |
else:
|
| 80 |
app.logger.warning(f"[WARN] {proc_name} not configured (model files missing)")
|
| 81 |
except Exception as e:
|
|
|
|
| 86 |
external_processor = ExternalAPIProcessor()
|
| 87 |
if external_processor.is_configured():
|
| 88 |
procs['external_api'] = external_processor
|
| 89 |
+
app.logger.info("[OK] External API processor initialized (cached)")
|
| 90 |
else:
|
| 91 |
app.logger.warning("[WARN] External API not configured")
|
| 92 |
except Exception as e:
|
| 93 |
app.logger.error(f"[FAIL] Failed to initialize External API: {str(e)}")
|
| 94 |
|
| 95 |
+
# Whisper digit processor as another fallback
|
| 96 |
+
try:
|
| 97 |
+
whisper_processor = WhisperDigitProcessor()
|
| 98 |
+
if whisper_processor.is_configured():
|
| 99 |
+
procs['whisper_digit'] = whisper_processor
|
| 100 |
+
app.logger.info("[OK] Whisper digit processor initialized (cached)")
|
| 101 |
+
except Exception as e:
|
| 102 |
+
app.logger.error(f"[FAIL] Failed to initialize Whisper: {str(e)}")
|
| 103 |
+
|
| 104 |
+
# Cache the processors globally
|
| 105 |
+
_processor_cache = procs
|
| 106 |
|
| 107 |
app.logger.info(f"Processor initialization complete:")
|
| 108 |
app.logger.info(f" ML Models loaded: {ml_working_count}/3")
|
| 109 |
+
app.logger.info(f" Total processors cached: {len(procs)}")
|
| 110 |
|
| 111 |
return procs
|
| 112 |
|
| 113 |
+
# Initialize processors on startup (cached globally)
|
| 114 |
processors = initialize_processors()
|
| 115 |
|
| 116 |
@app.route('/')
|
|
|
|
| 119 |
return jsonify({
|
| 120 |
'message': 'Streaming Digit Classifier API',
|
| 121 |
'status': 'running',
|
| 122 |
+
'version': '1.0.0',
|
| 123 |
'available_processors': list(processors.keys()),
|
| 124 |
'documentation': 'Frontend at Vercel, Backend API at HF Spaces'
|
| 125 |
})
|
|
|
|
| 197 |
result.update({
|
| 198 |
'audio_duration': round(duration, 3),
|
| 199 |
'file_size': len(audio_data),
|
| 200 |
+
'api_version': '1.0.0'
|
| 201 |
})
|
| 202 |
|
| 203 |
app.logger.info(f"Processed audio with {method}: '{result['predicted_digit']}' in {result['inference_time']}s")
|
|
|
|
| 255 |
'segment_index': 0,
|
| 256 |
'segment_size': len(standardized_audio),
|
| 257 |
'is_streaming': True,
|
| 258 |
+
'api_version': '1.0.0'
|
| 259 |
})
|
| 260 |
|
| 261 |
app.logger.info(f"Streaming prediction: '{result['predicted_digit']}' "
|
|
|
|
| 318 |
'status': 'healthy',
|
| 319 |
'timestamp': time.time(),
|
| 320 |
'processors': processor_health,
|
| 321 |
+
'version': '1.0.0',
|
| 322 |
'deployment': 'huggingface-spaces'
|
| 323 |
})
|
| 324 |
|
requirements_hf.txt
CHANGED
|
@@ -1,14 +1,14 @@
|
|
| 1 |
-
# HF Spaces Requirements -
|
| 2 |
# Core Flask API
|
| 3 |
Flask==2.3.3
|
| 4 |
Flask-CORS==4.0.0
|
| 5 |
requests==2.31.0
|
| 6 |
python-dotenv==1.0.0
|
| 7 |
|
| 8 |
-
# Audio Processing Core
|
| 9 |
-
numpy==1.
|
| 10 |
librosa==0.10.1
|
| 11 |
-
scipy==1.
|
| 12 |
soundfile==0.12.1
|
| 13 |
|
| 14 |
# Critical Audio Processing Libraries (Fix audio corruption)
|
|
@@ -17,12 +17,18 @@ ffmpeg-python==0.2.0
|
|
| 17 |
audioread==3.0.0
|
| 18 |
resampy==0.4.2
|
| 19 |
|
| 20 |
-
# ML Models - PyTorch CPU
|
| 21 |
-
torch==
|
| 22 |
-
torchaudio==
|
|
|
|
| 23 |
|
| 24 |
-
# Essential ML utilities
|
| 25 |
-
scikit-learn==1.3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# Logging and utilities
|
| 28 |
tqdm==4.65.0
|
|
|
|
| 1 |
+
# HF Spaces Requirements - Exact working versions from local system
|
| 2 |
# Core Flask API
|
| 3 |
Flask==2.3.3
|
| 4 |
Flask-CORS==4.0.0
|
| 5 |
requests==2.31.0
|
| 6 |
python-dotenv==1.0.0
|
| 7 |
|
| 8 |
+
# Audio Processing Core - Fixed versions (avoid yanked scipy 1.11.0)
|
| 9 |
+
numpy==1.21.6
|
| 10 |
librosa==0.10.1
|
| 11 |
+
scipy==1.9.3
|
| 12 |
soundfile==0.12.1
|
| 13 |
|
| 14 |
# Critical Audio Processing Libraries (Fix audio corruption)
|
|
|
|
| 17 |
audioread==3.0.0
|
| 18 |
resampy==0.4.2
|
| 19 |
|
| 20 |
+
# ML Models - PyTorch CPU with exact versions
|
| 21 |
+
torch==1.12.1
|
| 22 |
+
torchaudio==0.12.1
|
| 23 |
+
torchvision==0.13.1
|
| 24 |
|
| 25 |
+
# Essential ML utilities
|
| 26 |
+
scikit-learn==1.1.3
|
| 27 |
+
transformers==4.21.3
|
| 28 |
+
collections-extended==2.0.2
|
| 29 |
+
|
| 30 |
+
# VAD processing
|
| 31 |
+
webrtcvad==2.0.10
|
| 32 |
|
| 33 |
# Logging and utilities
|
| 34 |
tqdm==4.65.0
|