Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -17,19 +17,13 @@ import logging
|
|
| 17 |
import json
|
| 18 |
import gc
|
| 19 |
|
| 20 |
-
from utils.detector import ArabicSignDetector
|
| 21 |
-
from utils.translator import MedicalTranslator
|
| 22 |
-
from utils.medical_agent import MedicalAgent
|
| 23 |
-
from utils.speech import SpeechProcessor
|
| 24 |
-
from utils.sign_generator import SignGenerator
|
| 25 |
-
|
| 26 |
logging.basicConfig(level=logging.INFO)
|
| 27 |
logger = logging.getLogger(__name__)
|
| 28 |
|
| 29 |
app = Flask(__name__)
|
| 30 |
CORS(app)
|
| 31 |
|
| 32 |
-
# Global instances
|
| 33 |
detector = None
|
| 34 |
translator = None
|
| 35 |
medical_agent = None
|
|
@@ -55,14 +49,16 @@ def setup_environment():
|
|
| 55 |
|
| 56 |
return device
|
| 57 |
|
| 58 |
-
def
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
| 62 |
|
| 63 |
try:
|
| 64 |
-
# Step 1: Load detector first
|
| 65 |
logger.info("π₯ Step 1: Loading YOLO detector...")
|
|
|
|
| 66 |
detector = ArabicSignDetector()
|
| 67 |
logger.info("β
YOLO Detector loaded")
|
| 68 |
|
|
@@ -72,42 +68,75 @@ def initialize_models():
|
|
| 72 |
if torch.cuda.is_available():
|
| 73 |
torch.cuda.empty_cache()
|
| 74 |
|
| 75 |
-
# Step 2: Load
|
| 76 |
-
logger.info("π₯ Step 2: Loading
|
| 77 |
-
|
| 78 |
-
logger.info("β
Medical Translator loaded")
|
| 79 |
-
|
| 80 |
-
# Clear memory
|
| 81 |
-
gc.collect()
|
| 82 |
-
if torch.cuda.is_available():
|
| 83 |
-
torch.cuda.empty_cache()
|
| 84 |
-
|
| 85 |
-
# Step 3: Load medical agent (HuatuoGPT)
|
| 86 |
-
logger.info("π₯ Step 3: Loading HuatuoGPT medical agent...")
|
| 87 |
-
medical_agent = MedicalAgent()
|
| 88 |
-
logger.info("β
HuatuoGPT Medical Agent loaded")
|
| 89 |
-
|
| 90 |
-
# Clear memory
|
| 91 |
-
gc.collect()
|
| 92 |
-
if torch.cuda.is_available():
|
| 93 |
-
torch.cuda.empty_cache()
|
| 94 |
-
|
| 95 |
-
# Step 4: Load speech processor
|
| 96 |
-
logger.info("π₯ Step 4: Loading speech processor...")
|
| 97 |
speech_processor = SpeechProcessor()
|
| 98 |
logger.info("β
Speech Processor loaded")
|
| 99 |
|
| 100 |
-
# Step
|
| 101 |
-
logger.info("π₯ Step
|
|
|
|
| 102 |
sign_generator = SignGenerator()
|
| 103 |
logger.info("β
Sign Generator loaded")
|
| 104 |
|
| 105 |
-
logger.info("π
|
| 106 |
|
| 107 |
except Exception as e:
|
| 108 |
-
logger.error(f"β
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
@app.route('/')
|
| 113 |
def index():
|
|
@@ -115,7 +144,7 @@ def index():
|
|
| 115 |
try:
|
| 116 |
return send_file('index.html')
|
| 117 |
except Exception as e:
|
| 118 |
-
return "Medical
|
| 119 |
|
| 120 |
@app.route('/ui')
|
| 121 |
def serve_ui():
|
|
@@ -126,30 +155,26 @@ def serve_ui():
|
|
| 126 |
def health_check():
|
| 127 |
return jsonify({
|
| 128 |
"status": "healthy",
|
| 129 |
-
"models_loaded": bool(detector
|
| 130 |
-
"
|
| 131 |
-
"
|
|
|
|
| 132 |
})
|
| 133 |
|
| 134 |
@app.route('/debug-model')
|
| 135 |
def debug_model():
|
| 136 |
"""Debug endpoint to check model status"""
|
| 137 |
detector_status = {
|
| 138 |
-
'model_loaded': detector
|
| 139 |
-
'
|
| 140 |
-
'
|
| 141 |
-
'
|
|
|
|
| 142 |
}
|
| 143 |
|
| 144 |
-
if detector and detector.model:
|
| 145 |
-
detector_status['model_path'] = 'best.pt'
|
| 146 |
-
detector_status['classes_loaded'] = True
|
| 147 |
-
detector_status['total_classes'] = len(detector.model.names)
|
| 148 |
-
detector_status['class_names'] = dict(detector.model.names)
|
| 149 |
-
|
| 150 |
return jsonify({
|
| 151 |
-
'
|
| 152 |
-
'message': '
|
| 153 |
})
|
| 154 |
|
| 155 |
@app.route('/debug-files')
|
|
@@ -222,19 +247,21 @@ def process_sign_language():
|
|
| 222 |
arabic_text = detection_result['arabic_text']
|
| 223 |
logger.info(f"π Detected Arabic: {arabic_text}")
|
| 224 |
|
| 225 |
-
#
|
| 226 |
-
|
|
|
|
| 227 |
logger.info(f"π Translated to English: {english_text}")
|
| 228 |
|
| 229 |
-
#
|
| 230 |
-
|
|
|
|
| 231 |
english_text,
|
| 232 |
session_id=session_id
|
| 233 |
)
|
| 234 |
-
logger.info(f"π€
|
| 235 |
|
| 236 |
# Translate response back to Arabic
|
| 237 |
-
arabic_response =
|
| 238 |
logger.info(f"π Translated to Arabic: {arabic_response}")
|
| 239 |
|
| 240 |
# Generate sign animation for the response
|
|
@@ -270,7 +297,7 @@ def process_sign_language():
|
|
| 270 |
'conversation_state': agent_response.get('state', 'questioning'),
|
| 271 |
'session_id': session_id,
|
| 272 |
'workflow_used': agent_response.get('workflow_used', False),
|
| 273 |
-
'medical_ai': '
|
| 274 |
}
|
| 275 |
|
| 276 |
# Add TTS audio if available
|
|
@@ -311,12 +338,14 @@ def process_audio():
|
|
| 311 |
doctor_text = speech_processor.speech_to_text(audio_path)
|
| 312 |
logger.info(f"π€ Doctor said: {doctor_text}")
|
| 313 |
|
| 314 |
-
#
|
| 315 |
-
|
| 316 |
-
|
|
|
|
| 317 |
|
| 318 |
-
#
|
| 319 |
-
|
|
|
|
| 320 |
logger.info(f"π Translated to Arabic: {arabic_question}")
|
| 321 |
|
| 322 |
# Generate sign data for the question
|
|
@@ -347,7 +376,7 @@ def process_audio():
|
|
| 347 |
'patient_question_arabic': arabic_question,
|
| 348 |
'sign_data': sign_data,
|
| 349 |
'session_id': session_id,
|
| 350 |
-
'medical_ai': '
|
| 351 |
}
|
| 352 |
|
| 353 |
if tts_audio:
|
|
@@ -404,7 +433,7 @@ def conversation_status():
|
|
| 404 |
'success': True,
|
| 405 |
'session_id': session_id,
|
| 406 |
'max_questions': 3,
|
| 407 |
-
'medical_ai': '
|
| 408 |
'system_ready': all([
|
| 409 |
detector is not None,
|
| 410 |
translator is not None,
|
|
@@ -422,8 +451,9 @@ def reset_conversation():
|
|
| 422 |
session_id = data.get('session_id', 'default_session')
|
| 423 |
|
| 424 |
# Reset session in medical agent
|
| 425 |
-
|
| 426 |
-
|
|
|
|
| 427 |
logger.info(f"π Medical conversation reset for session: {session_id}")
|
| 428 |
else:
|
| 429 |
logger.info(f"π New session started: {session_id}")
|
|
@@ -485,12 +515,12 @@ def serve_static(filename):
|
|
| 485 |
except:
|
| 486 |
return "File not found", 404
|
| 487 |
|
| 488 |
-
@spaces.GPU
|
| 489 |
def create_app():
|
| 490 |
-
"""Application factory pattern with GPU declaration"""
|
| 491 |
-
print("π Initializing Medical Sign Language App with
|
| 492 |
setup_environment()
|
| 493 |
-
|
| 494 |
return app
|
| 495 |
|
| 496 |
if __name__ == '__main__':
|
|
|
|
| 17 |
import json
|
| 18 |
import gc
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
logging.basicConfig(level=logging.INFO)
|
| 21 |
logger = logging.getLogger(__name__)
|
| 22 |
|
| 23 |
app = Flask(__name__)
|
| 24 |
CORS(app)
|
| 25 |
|
| 26 |
+
# Global instances - will be initialized lazily
|
| 27 |
detector = None
|
| 28 |
translator = None
|
| 29 |
medical_agent = None
|
|
|
|
| 49 |
|
| 50 |
return device
|
| 51 |
|
| 52 |
+
def initialize_essential_models():
|
| 53 |
+
"""Initialize only essential models to avoid OOM"""
|
| 54 |
+
global detector, speech_processor, sign_generator
|
| 55 |
+
|
| 56 |
+
logger.info("π Initializing essential models only...")
|
| 57 |
|
| 58 |
try:
|
| 59 |
+
# Step 1: Load detector first (most critical)
|
| 60 |
logger.info("π₯ Step 1: Loading YOLO detector...")
|
| 61 |
+
from utils.detector import ArabicSignDetector
|
| 62 |
detector = ArabicSignDetector()
|
| 63 |
logger.info("β
YOLO Detector loaded")
|
| 64 |
|
|
|
|
| 68 |
if torch.cuda.is_available():
|
| 69 |
torch.cuda.empty_cache()
|
| 70 |
|
| 71 |
+
# Step 2: Load lightweight models
|
| 72 |
+
logger.info("π₯ Step 2: Loading speech processor...")
|
| 73 |
+
from utils.speech import SpeechProcessor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
speech_processor = SpeechProcessor()
|
| 75 |
logger.info("β
Speech Processor loaded")
|
| 76 |
|
| 77 |
+
# Step 3: Load sign generator
|
| 78 |
+
logger.info("π₯ Step 3: Loading sign generator...")
|
| 79 |
+
from utils.sign_generator import SignGenerator
|
| 80 |
sign_generator = SignGenerator()
|
| 81 |
logger.info("β
Sign Generator loaded")
|
| 82 |
|
| 83 |
+
logger.info("π Essential models loaded! Heavy models will load on demand.")
|
| 84 |
|
| 85 |
except Exception as e:
|
| 86 |
+
logger.error(f"β Essential models loading failed: {e}")
|
| 87 |
+
raise
|
| 88 |
+
|
| 89 |
+
def get_translator():
|
| 90 |
+
"""Lazy loader for translator"""
|
| 91 |
+
global translator
|
| 92 |
+
if translator is None:
|
| 93 |
+
try:
|
| 94 |
+
logger.info("π Lazy loading translator...")
|
| 95 |
+
from utils.translator import MedicalTranslator
|
| 96 |
+
translator = MedicalTranslator()
|
| 97 |
+
logger.info("β
Translator loaded")
|
| 98 |
+
except Exception as e:
|
| 99 |
+
logger.error(f"β Translator loading failed: {e}")
|
| 100 |
+
# Fallback translator
|
| 101 |
+
class FallbackTranslator:
|
| 102 |
+
def ar_to_en(self, text): return f"[EN] {text}"
|
| 103 |
+
def en_to_ar(self, text): return f"[AR] {text}"
|
| 104 |
+
translator = FallbackTranslator()
|
| 105 |
+
return translator
|
| 106 |
+
|
| 107 |
+
def get_medical_agent():
|
| 108 |
+
"""Lazy loader for medical agent with lighter model"""
|
| 109 |
+
global medical_agent
|
| 110 |
+
if medical_agent is None:
|
| 111 |
+
try:
|
| 112 |
+
logger.info("π Lazy loading medical agent...")
|
| 113 |
+
# Try to import the lite version first
|
| 114 |
+
try:
|
| 115 |
+
from utils.medical_agent_lite import LiteMedicalAgent
|
| 116 |
+
medical_agent = LiteMedicalAgent()
|
| 117 |
+
logger.info("β
Lite Medical Agent loaded")
|
| 118 |
+
except ImportError:
|
| 119 |
+
# Fallback to original with error handling
|
| 120 |
+
from utils.medical_agent import MedicalAgent
|
| 121 |
+
medical_agent = MedicalAgent()
|
| 122 |
+
logger.info("β
Original Medical Agent loaded")
|
| 123 |
+
except Exception as e:
|
| 124 |
+
logger.error(f"β Medical agent loading failed: {e}")
|
| 125 |
+
# Ultimate fallback
|
| 126 |
+
class UltimateFallbackAgent:
|
| 127 |
+
def __init__(self):
|
| 128 |
+
self.sessions = {}
|
| 129 |
+
def process_input(self, text, session_id):
|
| 130 |
+
return {
|
| 131 |
+
'response': 'Please describe your medical concern?',
|
| 132 |
+
'question_count': 1,
|
| 133 |
+
'state': 'questioning',
|
| 134 |
+
'workflow_used': False
|
| 135 |
+
}
|
| 136 |
+
def process_doctor_input(self, text):
|
| 137 |
+
return "Please describe your symptoms?"
|
| 138 |
+
medical_agent = UltimateFallbackAgent()
|
| 139 |
+
return medical_agent
|
| 140 |
|
| 141 |
@app.route('/')
|
| 142 |
def index():
|
|
|
|
| 144 |
try:
|
| 145 |
return send_file('index.html')
|
| 146 |
except Exception as e:
|
| 147 |
+
return "Medical Sign Language API is running! Add index.html for web interface."
|
| 148 |
|
| 149 |
@app.route('/ui')
|
| 150 |
def serve_ui():
|
|
|
|
| 155 |
def health_check():
|
| 156 |
return jsonify({
|
| 157 |
"status": "healthy",
|
| 158 |
+
"models_loaded": bool(detector),
|
| 159 |
+
"essential_models": "YOLO, Speech, Sign",
|
| 160 |
+
"heavy_models": "Load on demand",
|
| 161 |
+
"message": "System operational with lazy loading"
|
| 162 |
})
|
| 163 |
|
| 164 |
@app.route('/debug-model')
|
| 165 |
def debug_model():
|
| 166 |
"""Debug endpoint to check model status"""
|
| 167 |
detector_status = {
|
| 168 |
+
'model_loaded': detector is not None and detector.model is not None,
|
| 169 |
+
'translator_loaded': translator is not None,
|
| 170 |
+
'medical_agent_loaded': medical_agent is not None,
|
| 171 |
+
'speech_loaded': speech_processor is not None,
|
| 172 |
+
'sign_loaded': sign_generator is not None,
|
| 173 |
}
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
return jsonify({
|
| 176 |
+
'models_status': detector_status,
|
| 177 |
+
'message': 'Lazy loading enabled for heavy models'
|
| 178 |
})
|
| 179 |
|
| 180 |
@app.route('/debug-files')
|
|
|
|
| 247 |
arabic_text = detection_result['arabic_text']
|
| 248 |
logger.info(f"π Detected Arabic: {arabic_text}")
|
| 249 |
|
| 250 |
+
# Lazy load translator
|
| 251 |
+
translator_instance = get_translator()
|
| 252 |
+
english_text = translator_instance.ar_to_en(arabic_text)
|
| 253 |
logger.info(f"π Translated to English: {english_text}")
|
| 254 |
|
| 255 |
+
# Lazy load medical agent
|
| 256 |
+
medical_agent_instance = get_medical_agent()
|
| 257 |
+
agent_response = medical_agent_instance.process_input(
|
| 258 |
english_text,
|
| 259 |
session_id=session_id
|
| 260 |
)
|
| 261 |
+
logger.info(f"π€ Medical response: {agent_response}")
|
| 262 |
|
| 263 |
# Translate response back to Arabic
|
| 264 |
+
arabic_response = translator_instance.en_to_ar(agent_response['response'])
|
| 265 |
logger.info(f"π Translated to Arabic: {arabic_response}")
|
| 266 |
|
| 267 |
# Generate sign animation for the response
|
|
|
|
| 297 |
'conversation_state': agent_response.get('state', 'questioning'),
|
| 298 |
'session_id': session_id,
|
| 299 |
'workflow_used': agent_response.get('workflow_used', False),
|
| 300 |
+
'medical_ai': 'Medical AI'
|
| 301 |
}
|
| 302 |
|
| 303 |
# Add TTS audio if available
|
|
|
|
| 338 |
doctor_text = speech_processor.speech_to_text(audio_path)
|
| 339 |
logger.info(f"π€ Doctor said: {doctor_text}")
|
| 340 |
|
| 341 |
+
# Lazy load medical agent
|
| 342 |
+
medical_agent_instance = get_medical_agent()
|
| 343 |
+
patient_question = medical_agent_instance.process_doctor_input(doctor_text)
|
| 344 |
+
logger.info(f"π€ Medical rephrased: {patient_question}")
|
| 345 |
|
| 346 |
+
# Lazy load translator
|
| 347 |
+
translator_instance = get_translator()
|
| 348 |
+
arabic_question = translator_instance.en_to_ar(patient_question)
|
| 349 |
logger.info(f"π Translated to Arabic: {arabic_question}")
|
| 350 |
|
| 351 |
# Generate sign data for the question
|
|
|
|
| 376 |
'patient_question_arabic': arabic_question,
|
| 377 |
'sign_data': sign_data,
|
| 378 |
'session_id': session_id,
|
| 379 |
+
'medical_ai': 'Medical AI'
|
| 380 |
}
|
| 381 |
|
| 382 |
if tts_audio:
|
|
|
|
| 433 |
'success': True,
|
| 434 |
'session_id': session_id,
|
| 435 |
'max_questions': 3,
|
| 436 |
+
'medical_ai': 'Medical AI',
|
| 437 |
'system_ready': all([
|
| 438 |
detector is not None,
|
| 439 |
translator is not None,
|
|
|
|
| 451 |
session_id = data.get('session_id', 'default_session')
|
| 452 |
|
| 453 |
# Reset session in medical agent
|
| 454 |
+
medical_agent_instance = get_medical_agent()
|
| 455 |
+
if hasattr(medical_agent_instance, 'sessions') and session_id in medical_agent_instance.sessions:
|
| 456 |
+
del medical_agent_instance.sessions[session_id]
|
| 457 |
logger.info(f"π Medical conversation reset for session: {session_id}")
|
| 458 |
else:
|
| 459 |
logger.info(f"π New session started: {session_id}")
|
|
|
|
| 515 |
except:
|
| 516 |
return "File not found", 404
|
| 517 |
|
| 518 |
+
@spaces.GPU(enable_zero_gpu=True)
|
| 519 |
def create_app():
|
| 520 |
+
"""Application factory pattern with GPU declaration and ZeroGPU"""
|
| 521 |
+
print("π Initializing Medical Sign Language App with ZeroGPU support...")
|
| 522 |
setup_environment()
|
| 523 |
+
initialize_essential_models() # Only load essential models
|
| 524 |
return app
|
| 525 |
|
| 526 |
if __name__ == '__main__':
|