saemstunes commited on
Commit
4d27856
·
verified ·
1 Parent(s): 1d1ef2a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +235 -203
app.py CHANGED
@@ -16,10 +16,16 @@ from pydantic import BaseModel
16
 
17
  load_dotenv()
18
 
19
- from src.ai_system import SaemsTunesAISystem
20
- from src.supabase_integration import AdvancedSupabaseIntegration
21
- from src.security_system import AdvancedSecuritySystem
22
- from src.monitoring_system import ComprehensiveMonitor
 
 
 
 
 
 
23
 
24
  class Config:
25
  SUPABASE_URL = os.getenv("SUPABASE_URL", "")
@@ -28,7 +34,7 @@ class Config:
28
  MODEL_REPO = os.getenv("MODEL_REPO", "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF")
29
  MODEL_FILE = os.getenv("MODEL_FILE", "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf")
30
  HF_SPACE = os.getenv("HF_SPACE", "saemstunes/STA-AI")
31
- PORT = int(os.getenv("PORT", 8000))
32
  LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
33
  MAX_RESPONSE_LENGTH = int(os.getenv("MAX_RESPONSE_LENGTH", "500"))
34
  TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))
@@ -36,13 +42,15 @@ class Config:
36
  CONTEXT_WINDOW = int(os.getenv("CONTEXT_WINDOW", "2048"))
37
  ENABLE_MONITORING = os.getenv("ENABLE_MONITORING", "true").lower() == "true"
38
 
 
39
  logging.basicConfig(
40
  level=getattr(logging, Config.LOG_LEVEL),
41
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
42
- handlers=[logging.StreamHandler()] # Only StreamHandler for Hugging Face Spaces
43
  )
44
  logger = logging.getLogger(__name__)
45
 
 
46
  supabase_integration = None
47
  security_system = None
48
  monitor = None
@@ -51,25 +59,44 @@ systems_ready = False
51
  initialization_complete = False
52
  initialization_errors = []
53
  initialization_start_time = None
 
54
 
55
  def initialize_systems():
 
56
  global supabase_integration, security_system, monitor, ai_system, systems_ready, initialization_complete, initialization_errors
57
 
 
 
 
 
 
58
  logger.info("🚀 Initializing Saem's Tunes AI System...")
59
 
60
  try:
 
 
61
  supabase_integration = AdvancedSupabaseIntegration(
62
  Config.SUPABASE_URL,
63
  Config.SUPABASE_ANON_KEY
64
  )
65
- logger.info("✅ Supabase integration initialized")
66
 
 
 
 
 
 
 
 
67
  security_system = AdvancedSecuritySystem()
68
  logger.info("✅ Security system initialized")
69
 
 
 
70
  monitor = ComprehensiveMonitor(prometheus_port=8001)
71
  logger.info("✅ Monitoring system initialized")
72
 
 
 
73
  ai_system = SaemsTunesAISystem(
74
  supabase_integration=supabase_integration,
75
  security_system=security_system,
@@ -84,13 +111,15 @@ def initialize_systems():
84
  )
85
  logger.info("✅ AI system initialized")
86
 
87
- if ai_system.is_healthy():
 
88
  systems_ready = True
89
  initialization_complete = True
90
  logger.info("🎉 All systems initialized successfully!")
91
  else:
92
  initialization_errors.append("AI system health check failed")
93
  initialization_complete = True
 
94
 
95
  return True
96
 
@@ -101,89 +130,80 @@ def initialize_systems():
101
  initialization_complete = True
102
  return False
103
 
104
- def initialize_systems_background():
105
- """Run system initialization in background thread"""
106
- global initialization_start_time
107
  initialization_start_time = time.time()
108
 
109
- thread = threading.Thread(target=initialize_systems)
110
- thread.daemon = True
111
- thread.start()
112
 
113
- def chat_interface(message: str, history: List[List[str]], request: gr.Request) -> str:
 
114
  try:
115
- if not message.strip():
116
- return "Please ask me anything about Saem's Tunes!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  if not systems_ready:
119
- return "🔄 Systems are still initializing. Please wait a moment and try again..."
120
-
121
- client_host = getattr(request, "client", None)
122
- if client_host:
123
- user_ip = client_host.host
124
- else:
125
- user_ip = "unknown"
126
- user_id = f"gradio_user_{user_ip}"
127
-
128
- security_result = security_system.check_request(message, user_id)
129
- if security_result["is_suspicious"]:
130
- logger.warning(f"Suspicious request blocked from {user_ip}: {message}")
131
- return "Your request has been blocked for security reasons. Please try a different question."
132
-
133
- start_time = time.time()
134
- response = ai_system.process_query(message, user_id)
135
- processing_time = time.time() - start_time
136
-
137
- formatted_response = f"{response}\n\n_Generated in {processing_time:.1f}s_"
138
 
139
- logger.info(f"Chat processed: {message[:50]}... -> {processing_time:.2f}s")
 
 
 
 
 
 
 
140
 
141
- return formatted_response
 
 
 
 
 
 
 
 
 
142
 
143
- except Exception as e:
144
- logger.error(f"Chat error: {e}")
145
- return "I apologize, but I'm experiencing technical difficulties. Please try again later."
146
-
147
- def get_system_status() -> Dict[str, Any]:
148
- if not initialization_complete:
149
- return {
150
- "status": "initializing",
151
- "details": "Systems are starting up...",
152
- "timestamp": datetime.now().isoformat(),
153
- "initialization_started": initialization_start_time is not None,
154
- "duration_seconds": time.time() - initialization_start_time if initialization_start_time else 0
155
- }
156
-
157
- if not systems_ready:
158
- return {
159
- "status": "degraded",
160
- "details": "Systems initialized but not fully ready",
161
- "errors": initialization_errors,
162
- "timestamp": datetime.now().isoformat()
163
- }
164
-
165
- try:
166
  return {
167
  "status": "healthy",
168
  "timestamp": datetime.now().isoformat(),
169
- "systems": {
170
- "supabase": supabase_integration.is_connected() if supabase_integration else False,
171
- "security": bool(security_system),
172
- "monitoring": bool(monitor),
173
- "ai_system": ai_system.is_healthy() if ai_system else False,
174
- "model_loaded": ai_system.model_loaded if ai_system else False
175
- },
176
- "resources": {
177
- "cpu_percent": psutil.cpu_percent(),
178
- "memory_percent": psutil.virtual_memory().percent,
179
- "disk_percent": psutil.disk_usage('/').percent
180
- },
181
- "performance": {
182
- "total_requests": len(monitor.inference_metrics) if monitor else 0,
183
- "avg_response_time": monitor.get_average_response_time() if monitor else 0,
184
- "error_rate": monitor.get_error_rate() if monitor else 0
185
- }
186
  }
 
187
  except Exception as e:
188
  return {
189
  "status": "error",
@@ -191,25 +211,68 @@ def get_system_status() -> Dict[str, Any]:
191
  "timestamp": datetime.now().isoformat()
192
  }
193
 
194
- class ChatRequest(BaseModel):
195
- message: str
196
- user_id: Optional[str] = "anonymous"
197
- conversation_id: Optional[str] = None
198
-
199
- class ChatResponse(BaseModel):
200
- response: str
201
- processing_time: float
202
- conversation_id: str
203
- timestamp: str
204
- model_used: str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
 
206
- # Create FastAPI app at module level - REQUIRED FOR HUGGING FACE
207
- fastapi_app = FastAPI(title="Saem's Tunes AI API", version="2.0.0")
 
 
 
 
208
 
209
- # Add root route - REQUIRED FOR HUGGING FACE HEALTH CHECKS
210
  @fastapi_app.get("/")
211
  def root():
212
- """Root endpoint for Hugging Face health checks"""
213
  return {
214
  "status": "healthy" if systems_ready else "initializing",
215
  "message": "Saem's Tunes AI API is running",
@@ -218,20 +281,28 @@ def root():
218
  "environment": "huggingface-spaces"
219
  }
220
 
 
221
  @fastapi_app.get("/api/health")
222
  def api_health():
 
223
  try:
224
  status_data = get_system_status()
225
  return status_data
226
  except Exception as e:
227
  logger.error(f"Health endpoint error: {e}")
228
  return JSONResponse(
229
- content={"status": "error", "error": str(e)},
230
- status_code=500
 
 
 
 
231
  )
232
 
 
233
  @fastapi_app.get("/api/models")
234
  def api_models():
 
235
  models_info = {
236
  "available_models": ["TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"],
237
  "current_model": Config.MODEL_NAME,
@@ -256,62 +327,41 @@ def api_models():
256
 
257
  @fastapi_app.get("/api/stats")
258
  def api_stats():
259
- if not monitor or not systems_ready:
260
- return JSONResponse(
261
- content={
262
- "status": "initializing" if not systems_ready else "degraded",
263
- "systems_ready": systems_ready,
264
- "timestamp": datetime.now().isoformat()
265
- },
266
- status_code=200 # Always return 200 for Hugging Face
267
- )
268
 
269
- stats_data = {
270
- "status": "healthy",
271
- "total_requests": len(monitor.inference_metrics),
272
- "average_response_time": monitor.get_average_response_time(),
273
- "error_rate": monitor.get_error_rate(),
274
- "uptime": monitor.get_uptime(),
275
- "system_health": get_system_status(),
276
- "timestamp": datetime.now().isoformat()
277
- }
278
- return stats_data
279
-
280
- @fastapi_app.post("/api/chat")
281
- def api_chat(request: ChatRequest):
282
  try:
283
- if not request.message.strip():
284
- raise HTTPException(status_code=400, detail="Message cannot be empty")
285
-
286
- if not systems_ready:
287
- raise HTTPException(
288
- status_code=503,
289
- detail="Systems are still initializing. Please try again in a moment."
290
- )
291
-
292
- security_result = security_system.check_request(request.message, request.user_id)
293
- if security_result["is_suspicious"]:
294
- raise HTTPException(status_code=429, detail="Request blocked for security reasons")
295
 
296
- start_time = time.time()
297
- response = ai_system.process_query(request.message, request.user_id, request.conversation_id)
298
- processing_time = time.time() - start_time
 
 
 
 
 
 
299
 
 
 
300
  return {
301
- "response": response,
302
- "processing_time": processing_time,
303
- "conversation_id": request.conversation_id or f"conv_{int(time.time())}",
304
- "timestamp": datetime.now().isoformat(),
305
- "model_used": Config.MODEL_NAME
306
  }
307
-
308
- except HTTPException:
309
- raise
310
- except Exception as e:
311
- logger.error(f"API chat error: {e}")
312
- raise HTTPException(status_code=500, detail="Internal server error")
313
 
314
  def create_gradio_interface():
 
315
  custom_css = """
316
  .gradio-container {
317
  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
@@ -400,7 +450,7 @@ def create_gradio_interface():
400
  with gr.Row():
401
  for question in quick_questions:
402
  btn = gr.Button(question, size="sm", elem_classes="quick-action-btn")
403
- quick_buttons.append((btn, question))
404
 
405
  gr.Markdown("### 💬 Chat with Saem's Tunes AI")
406
 
@@ -408,20 +458,18 @@ def create_gradio_interface():
408
  label="Saem's Tunes Chat",
409
  height=450,
410
  placeholder="Ask me anything about Saem's Tunes music platform...",
411
- show_label=False,
412
- type="messages"
413
  )
414
 
415
  with gr.Row():
416
  msg = gr.Textbox(
417
- placeholder="Type your question here... (Press Enter to send, Shift+Enter for new line)",
418
  show_label=False,
419
  scale=4,
420
  container=False,
421
- lines=2,
422
- max_lines=4
423
  )
424
- submit_btn = gr.Button("Send 🚀", variant="primary", scale=1, size="lg")
425
 
426
  gr.Examples(
427
  examples=[
@@ -429,12 +477,7 @@ def create_gradio_interface():
429
  "What are the premium features?",
430
  "How do I upload my music as an artist?",
431
  "Tell me about the music courses available",
432
- "How does the recommendation system work?",
433
- "Can I share playlists with friends?",
434
- "What music genres are available?",
435
- "How do I follow artists?",
436
- "Is there a mobile app?",
437
- "How do I reset my password?"
438
  ],
439
  inputs=msg,
440
  label="💡 Example Questions"
@@ -442,7 +485,6 @@ def create_gradio_interface():
442
 
443
  with gr.Row():
444
  clear_btn = gr.Button("🗑️ Clear Chat", size="sm")
445
- export_btn = gr.Button("💾 Export Chat", size="sm")
446
 
447
  gr.Markdown("""
448
  <div class="footer">
@@ -451,84 +493,71 @@ def create_gradio_interface():
451
  <a href="https://www.saemstunes.com" target="_blank">Saem's Tunes Music Platform</a>
452
  </p>
453
  <p style="font-size: 0.9em; opacity: 0.7;">
454
- Model: Q4_K_M quantization • Context: 2K tokens • Response time: ~2-5s
455
  </p>
456
  </div>
457
  """)
458
 
459
  def update_status():
 
460
  status = get_system_status()
461
  status_text = status.get("status", "unknown")
462
- status_class = f"status-{status_text}" if status_text in ["healthy", "warning", "error"] else "status-warning"
463
 
464
  if status_text == "healthy":
465
- systems = status.get("systems", {})
466
- resources = status.get("resources", {})
467
- html = f"""
468
- <div class='status-indicator {status_class}'></div>
469
  <strong>System Status: Healthy</strong><br>
470
- <small>
471
- Supabase: {'✅' if systems.get('supabase') else '❌'} |
472
- AI System: {'✅' if systems.get('ai_system') else '❌'} |
473
- Model: {'✅' if systems.get('model_loaded') else '❌'} |
474
- CPU: {resources.get('cpu_percent', 0):.1f}% |
475
- Memory: {resources.get('memory_percent', 0):.1f}%
476
- </small>
477
  """
478
  elif status_text == "initializing":
479
  duration = status.get('duration_seconds', 0)
480
  html = f"""
481
- <div class='status-indicator {status_class}'></div>
482
  <strong>System Status: Initializing</strong><br>
483
- <small>Started {duration:.0f}s ago • Downloading AI model...</small>
484
  """
485
  else:
486
- html = f"<div class='status-indicator {status_class}'></div>{status.get('details', 'Unknown status')}"
487
 
488
  return html
489
 
490
  def user_message(user_message, chat_history):
491
- return "", chat_history + [{"role": "user", "content": user_message}]
492
 
493
  def bot_response(chat_history):
494
  if not chat_history:
495
  return chat_history
496
 
497
- user_message = chat_history[-1]["content"]
498
  bot_message = chat_interface(user_message, chat_history, gr.Request())
499
 
500
- return chat_history + [{"role": "assistant", "content": bot_message}]
 
501
 
502
  def clear_chat():
503
  return []
504
 
505
- def export_chat(chat_history):
506
- if not chat_history:
507
- return "No conversation to export"
508
-
509
- export_text = f"Saem's Tunes AI Conversation - {datetime.now().strftime('%Y-%m-%d %H:%M')}\n\n"
510
- for msg in chat_history:
511
- role = "You" if msg["role"] == "user" else "AI Assistant"
512
- export_text += f"{role}: {msg['content']}\n\n"
513
-
514
- return export_text
515
-
516
  refresh_btn.click(update_status, outputs=status_display)
517
 
518
- msg.submit(user_message, [msg, chatbot], [msg, chatbot], queue=False).then(
 
 
519
  bot_response, chatbot, chatbot
520
  )
521
 
522
- submit_btn.click(user_message, [msg, chatbot], [msg, chatbot], queue=False).then(
 
 
523
  bot_response, chatbot, chatbot
524
  )
525
 
526
  clear_btn.click(clear_chat, outputs=chatbot)
527
- export_btn.click(export_chat, chatbot, msg)
528
 
529
- for btn, question_text in quick_buttons:
 
530
  btn.click(
531
- fn=lambda q=question_text: q,
532
  outputs=msg
533
  ).then(
534
  user_message, [msg, chatbot], [msg, chatbot]
@@ -540,20 +569,23 @@ def create_gradio_interface():
540
 
541
  return demo
542
 
543
- # Create Gradio interface and mount to FastAPI - AT MODULE LEVEL FOR HUGGING FACE
544
  demo = create_gradio_interface()
545
  app = gr.mount_gradio_app(fastapi_app, demo, path="/")
546
 
547
- # Start background initialization
548
- initialize_systems_background()
 
 
 
 
549
 
 
550
  if __name__ == "__main__":
551
- logger.info("🎵 Starting Saem's Tunes AI on Hugging Face Spaces...")
552
-
553
- import uvicorn
554
- uvicorn.run(
555
- app,
556
- host="0.0.0.0",
557
- port=Config.PORT,
558
- log_level=Config.LOG_LEVEL.lower()
559
  )
 
16
 
17
  load_dotenv()
18
 
19
+ # Import systems - but don't initialize them until needed
20
+ try:
21
+ from src.ai_system import SaemsTunesAISystem
22
+ from src.supabase_integration import AdvancedSupabaseIntegration
23
+ from src.security_system import AdvancedSecuritySystem
24
+ from src.monitoring_system import ComprehensiveMonitor
25
+ SYSTEMS_AVAILABLE = True
26
+ except ImportError as e:
27
+ print(f"Warning: Could not import systems: {e}")
28
+ SYSTEMS_AVAILABLE = False
29
 
30
  class Config:
31
  SUPABASE_URL = os.getenv("SUPABASE_URL", "")
 
34
  MODEL_REPO = os.getenv("MODEL_REPO", "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF")
35
  MODEL_FILE = os.getenv("MODEL_FILE", "tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf")
36
  HF_SPACE = os.getenv("HF_SPACE", "saemstunes/STA-AI")
37
+ PORT = int(os.getenv("PORT", 7860)) # Hugging Face Spaces uses 7860
38
  LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
39
  MAX_RESPONSE_LENGTH = int(os.getenv("MAX_RESPONSE_LENGTH", "500"))
40
  TEMPERATURE = float(os.getenv("TEMPERATURE", "0.7"))
 
42
  CONTEXT_WINDOW = int(os.getenv("CONTEXT_WINDOW", "2048"))
43
  ENABLE_MONITORING = os.getenv("ENABLE_MONITORING", "true").lower() == "true"
44
 
45
+ # Setup minimal logging first
46
  logging.basicConfig(
47
  level=getattr(logging, Config.LOG_LEVEL),
48
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
49
+ handlers=[logging.StreamHandler()]
50
  )
51
  logger = logging.getLogger(__name__)
52
 
53
+ # Global systems - initialize as None
54
  supabase_integration = None
55
  security_system = None
56
  monitor = None
 
59
  initialization_complete = False
60
  initialization_errors = []
61
  initialization_start_time = None
62
+ initialization_thread = None
63
 
64
  def initialize_systems():
65
+ """Initialize all systems - runs in background thread"""
66
  global supabase_integration, security_system, monitor, ai_system, systems_ready, initialization_complete, initialization_errors
67
 
68
+ if not SYSTEMS_AVAILABLE:
69
+ initialization_errors.append("System dependencies not available")
70
+ initialization_complete = True
71
+ return False
72
+
73
  logger.info("🚀 Initializing Saem's Tunes AI System...")
74
 
75
  try:
76
+ # Initialize Supabase integration
77
+ logger.info("📡 Connecting to Supabase...")
78
  supabase_integration = AdvancedSupabaseIntegration(
79
  Config.SUPABASE_URL,
80
  Config.SUPABASE_ANON_KEY
81
  )
 
82
 
83
+ if not supabase_integration.is_connected():
84
+ logger.warning("⚠️ Supabase connection failed, continuing with fallback data")
85
+ else:
86
+ logger.info("✅ Supabase integration initialized")
87
+
88
+ # Initialize security system
89
+ logger.info("🔒 Initializing security system...")
90
  security_system = AdvancedSecuritySystem()
91
  logger.info("✅ Security system initialized")
92
 
93
+ # Initialize monitoring
94
+ logger.info("📊 Initializing monitoring system...")
95
  monitor = ComprehensiveMonitor(prometheus_port=8001)
96
  logger.info("✅ Monitoring system initialized")
97
 
98
+ # Initialize AI system - this is the heavy part
99
+ logger.info("🤖 Initializing AI system with TinyLlama...")
100
  ai_system = SaemsTunesAISystem(
101
  supabase_integration=supabase_integration,
102
  security_system=security_system,
 
111
  )
112
  logger.info("✅ AI system initialized")
113
 
114
+ # Check if AI system is healthy
115
+ if ai_system and ai_system.is_healthy():
116
  systems_ready = True
117
  initialization_complete = True
118
  logger.info("🎉 All systems initialized successfully!")
119
  else:
120
  initialization_errors.append("AI system health check failed")
121
  initialization_complete = True
122
+ logger.warning("⚠️ AI system not fully healthy, but initialization complete")
123
 
124
  return True
125
 
 
130
  initialization_complete = True
131
  return False
132
 
133
+ def start_initialization():
134
+ """Start system initialization in background"""
135
+ global initialization_thread, initialization_start_time
136
  initialization_start_time = time.time()
137
 
138
+ initialization_thread = threading.Thread(target=initialize_systems, daemon=True)
139
+ initialization_thread.start()
140
+ logger.info("🔄 Started system initialization in background thread")
141
 
142
+ def get_system_status() -> Dict[str, Any]:
143
+ """Get current system status - lightweight and safe"""
144
  try:
145
+ # Get resource usage safely
146
+ resources = {}
147
+ try:
148
+ cpu_percent = psutil.cpu_percent()
149
+ memory = psutil.virtual_memory()
150
+ disk = psutil.disk_usage('/')
151
+ resources = {
152
+ "cpu_percent": cpu_percent,
153
+ "memory_percent": memory.percent,
154
+ "memory_used_gb": memory.used / (1024 ** 3),
155
+ "disk_percent": disk.percent
156
+ }
157
+ except Exception as e:
158
+ resources = {"error": f"Resource monitoring failed: {e}"}
159
+
160
+ if not initialization_complete:
161
+ return {
162
+ "status": "initializing",
163
+ "details": "Systems are starting up...",
164
+ "timestamp": datetime.now().isoformat(),
165
+ "initialization_started": initialization_start_time is not None,
166
+ "duration_seconds": time.time() - initialization_start_time if initialization_start_time else 0,
167
+ "resources": resources
168
+ }
169
 
170
  if not systems_ready:
171
+ return {
172
+ "status": "degraded",
173
+ "details": "Systems initialized but not fully ready",
174
+ "errors": initialization_errors,
175
+ "timestamp": datetime.now().isoformat(),
176
+ "resources": resources
177
+ }
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
+ # Systems are ready - get detailed status
180
+ systems_status = {
181
+ "supabase": supabase_integration.is_connected() if supabase_integration else False,
182
+ "security": bool(security_system),
183
+ "monitoring": bool(monitor),
184
+ "ai_system": ai_system.is_healthy() if ai_system else False,
185
+ "model_loaded": ai_system.model_loaded if ai_system else False
186
+ }
187
 
188
+ performance = {}
189
+ if monitor:
190
+ try:
191
+ performance = {
192
+ "total_requests": len(monitor.inference_metrics),
193
+ "avg_response_time": monitor.get_average_response_time(),
194
+ "error_rate": monitor.get_error_rate()
195
+ }
196
+ except Exception as e:
197
+ performance = {"error": f"Performance monitoring failed: {e}"}
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  return {
200
  "status": "healthy",
201
  "timestamp": datetime.now().isoformat(),
202
+ "systems": systems_status,
203
+ "resources": resources,
204
+ "performance": performance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  }
206
+
207
  except Exception as e:
208
  return {
209
  "status": "error",
 
211
  "timestamp": datetime.now().isoformat()
212
  }
213
 
214
+ def chat_interface(message: str, history: List[List[str]], request: gr.Request) -> str:
215
+ """Gradio chat interface - with proper error handling"""
216
+ try:
217
+ if not message.strip():
218
+ return "Please ask me anything about Saem's Tunes!"
219
+
220
+ if not systems_ready or not ai_system:
221
+ return "🔄 Systems are still initializing. Please wait a moment and try again..."
222
+
223
+ # Get client info safely
224
+ user_ip = "unknown"
225
+ try:
226
+ client_host = getattr(request, "client", None)
227
+ if client_host:
228
+ user_ip = client_host.host
229
+ except:
230
+ pass
231
+
232
+ user_id = f"gradio_user_{user_ip}"
233
+
234
+ # Security check with fallback
235
+ security_check_passed = True
236
+ try:
237
+ if security_system:
238
+ security_result = security_system.check_request(message, user_id)
239
+ if security_result["is_suspicious"]:
240
+ logger.warning(f"Suspicious request blocked from {user_ip}: {message}")
241
+ return "Your request has been blocked for security reasons. Please try a different question."
242
+ except Exception as e:
243
+ logger.warning(f"Security check failed, allowing request: {e}")
244
+
245
+ # Process query
246
+ start_time = time.time()
247
+ try:
248
+ response = ai_system.process_query(message, user_id)
249
+ processing_time = time.time() - start_time
250
+
251
+ formatted_response = f"{response}\n\n_Generated in {processing_time:.1f}s_"
252
+
253
+ logger.info(f"Chat processed: {message[:50]}... -> {processing_time:.2f}s")
254
+
255
+ return formatted_response
256
+
257
+ except Exception as e:
258
+ logger.error(f"AI processing error: {e}")
259
+ return "I apologize, but I'm experiencing technical difficulties. Please try again later."
260
+
261
+ except Exception as e:
262
+ logger.error(f"Chat interface error: {e}")
263
+ return "I apologize, but I'm experiencing technical difficulties. Please try again later."
264
 
265
+ # Create FastAPI app at module level - CRITICAL FOR HUGGING FACE
266
+ fastapi_app = FastAPI(
267
+ title="Saem's Tunes AI API",
268
+ description="AI Assistant for Saem's Tunes Music Platform",
269
+ version="2.0.0"
270
+ )
271
 
272
+ # Root endpoint - ALWAYS returns 200 for Hugging Face health checks
273
  @fastapi_app.get("/")
274
  def root():
275
+ """Root endpoint - MUST return 200 immediately for Hugging Face"""
276
  return {
277
  "status": "healthy" if systems_ready else "initializing",
278
  "message": "Saem's Tunes AI API is running",
 
281
  "environment": "huggingface-spaces"
282
  }
283
 
284
+ # Health endpoint - ALWAYS returns 200
285
  @fastapi_app.get("/api/health")
286
  def api_health():
287
+ """Health endpoint - ALWAYS returns 200 for Hugging Face"""
288
  try:
289
  status_data = get_system_status()
290
  return status_data
291
  except Exception as e:
292
  logger.error(f"Health endpoint error: {e}")
293
  return JSONResponse(
294
+ content={
295
+ "status": "error",
296
+ "error": str(e),
297
+ "timestamp": datetime.now().isoformat()
298
+ },
299
+ status_code=200 # Always 200 for Hugging Face
300
  )
301
 
302
+ # Other API endpoints with proper error handling
303
  @fastapi_app.get("/api/models")
304
  def api_models():
305
+ """Get model information"""
306
  models_info = {
307
  "available_models": ["TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"],
308
  "current_model": Config.MODEL_NAME,
 
327
 
328
  @fastapi_app.get("/api/stats")
329
  def api_stats():
330
+ """Get system statistics"""
331
+ if not systems_ready:
332
+ return {
333
+ "status": "initializing",
334
+ "systems_ready": systems_ready,
335
+ "timestamp": datetime.now().isoformat()
336
+ }
 
 
337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  try:
339
+ stats_data = {
340
+ "status": "healthy",
341
+ "system_health": get_system_status(),
342
+ "timestamp": datetime.now().isoformat()
343
+ }
 
 
 
 
 
 
 
344
 
345
+ if monitor:
346
+ stats_data.update({
347
+ "total_requests": len(monitor.inference_metrics),
348
+ "average_response_time": monitor.get_average_response_time(),
349
+ "error_rate": monitor.get_error_rate(),
350
+ "uptime": monitor.get_uptime(),
351
+ })
352
+
353
+ return stats_data
354
 
355
+ except Exception as e:
356
+ logger.error(f"Stats endpoint error: {e}")
357
  return {
358
+ "status": "error",
359
+ "error": str(e),
360
+ "timestamp": datetime.now().isoformat()
 
 
361
  }
 
 
 
 
 
 
362
 
363
  def create_gradio_interface():
364
+ """Create Gradio interface - lightweight and fast"""
365
  custom_css = """
366
  .gradio-container {
367
  font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
 
450
  with gr.Row():
451
  for question in quick_questions:
452
  btn = gr.Button(question, size="sm", elem_classes="quick-action-btn")
453
+ quick_buttons.append(btn)
454
 
455
  gr.Markdown("### 💬 Chat with Saem's Tunes AI")
456
 
 
458
  label="Saem's Tunes Chat",
459
  height=450,
460
  placeholder="Ask me anything about Saem's Tunes music platform...",
461
+ show_label=False
 
462
  )
463
 
464
  with gr.Row():
465
  msg = gr.Textbox(
466
+ placeholder="Type your question here... (Press Enter to send)",
467
  show_label=False,
468
  scale=4,
469
  container=False,
470
+ lines=2
 
471
  )
472
+ submit_btn = gr.Button("Send 🚀", variant="primary", scale=1)
473
 
474
  gr.Examples(
475
  examples=[
 
477
  "What are the premium features?",
478
  "How do I upload my music as an artist?",
479
  "Tell me about the music courses available",
480
+ "How does the recommendation system work?"
 
 
 
 
 
481
  ],
482
  inputs=msg,
483
  label="💡 Example Questions"
 
485
 
486
  with gr.Row():
487
  clear_btn = gr.Button("🗑️ Clear Chat", size="sm")
 
488
 
489
  gr.Markdown("""
490
  <div class="footer">
 
493
  <a href="https://www.saemstunes.com" target="_blank">Saem's Tunes Music Platform</a>
494
  </p>
495
  <p style="font-size: 0.9em; opacity: 0.7;">
496
+ Model: Q4_K_M quantization • Context: 2K tokens
497
  </p>
498
  </div>
499
  """)
500
 
501
  def update_status():
502
+ """Update status display - lightweight"""
503
  status = get_system_status()
504
  status_text = status.get("status", "unknown")
 
505
 
506
  if status_text == "healthy":
507
+ html = """
508
+ <div class='status-indicator status-healthy'></div>
 
 
509
  <strong>System Status: Healthy</strong><br>
510
+ <small>AI Assistant is ready to help!</small>
 
 
 
 
 
 
511
  """
512
  elif status_text == "initializing":
513
  duration = status.get('duration_seconds', 0)
514
  html = f"""
515
+ <div class='status-indicator status-warning'></div>
516
  <strong>System Status: Initializing</strong><br>
517
+ <small>Loading AI model... ({duration:.0f}s)</small>
518
  """
519
  else:
520
+ html = f"<div class='status-indicator status-error'></div>System Status: {status_text}"
521
 
522
  return html
523
 
524
  def user_message(user_message, chat_history):
525
+ return "", chat_history + [[user_message, None]]
526
 
527
  def bot_response(chat_history):
528
  if not chat_history:
529
  return chat_history
530
 
531
+ user_message = chat_history[-1][0]
532
  bot_message = chat_interface(user_message, chat_history, gr.Request())
533
 
534
+ chat_history[-1][1] = bot_message
535
+ return chat_history
536
 
537
  def clear_chat():
538
  return []
539
 
540
+ # Connect components
 
 
 
 
 
 
 
 
 
 
541
  refresh_btn.click(update_status, outputs=status_display)
542
 
543
+ msg.submit(
544
+ user_message, [msg, chatbot], [msg, chatbot], queue=False
545
+ ).then(
546
  bot_response, chatbot, chatbot
547
  )
548
 
549
+ submit_btn.click(
550
+ user_message, [msg, chatbot], [msg, chatbot], queue=False
551
+ ).then(
552
  bot_response, chatbot, chatbot
553
  )
554
 
555
  clear_btn.click(clear_chat, outputs=chatbot)
 
556
 
557
+ # Connect quick buttons
558
+ for btn in quick_buttons:
559
  btn.click(
560
+ lambda x=btn.value: x,
561
  outputs=msg
562
  ).then(
563
  user_message, [msg, chatbot], [msg, chatbot]
 
569
 
570
  return demo
571
 
572
+ # Create Gradio interface and mount to FastAPI - AT MODULE LEVEL
573
  demo = create_gradio_interface()
574
  app = gr.mount_gradio_app(fastapi_app, demo, path="/")
575
 
576
+ # Start initialization AFTER app is created
577
+ start_initialization()
578
+
579
+ logger.info(f"🚀 Saem's Tunes AI Assistant starting on port {Config.PORT}")
580
+ logger.info("📡 FastAPI and Gradio apps mounted successfully")
581
+ logger.info("🔄 System initialization started in background")
582
 
583
+ # Hugging Face Spaces entry point
584
  if __name__ == "__main__":
585
+ # This runs when developing locally
586
+ demo.launch(
587
+ server_name="0.0.0.0",
588
+ server_port=Config.PORT,
589
+ show_error=True,
590
+ share=False
 
 
591
  )