| from flask import Flask, jsonify, request |
| from flask_cors import CORS |
| import logging |
| from datetime import datetime, timedelta |
| import json |
| from typing import Dict, Any, List, Optional |
| import threading |
| import time |
|
|
| from .dashboard_database_manager import DashboardDatabaseManager |
|
|
| class DashboardAPI: |
| """API layer for dashboard integration""" |
| |
| def __init__(self, database_manager: DashboardDatabaseManager, port: int = 5001): |
| self.database_manager = database_manager |
| self.port = port |
| self.app = Flask(__name__) |
| CORS(self.app) |
| |
| |
| logging.basicConfig(level=logging.INFO) |
| self.logger = logging.getLogger(__name__) |
| |
| |
| self._setup_routes() |
| |
| |
| self.api_thread = None |
| self.running = False |
| |
| def _setup_routes(self): |
| """Setup API routes for dashboard integration""" |
| |
| @self.app.route('/api/health', methods=['GET']) |
| def health_check(): |
| """Health check endpoint""" |
| return jsonify({ |
| 'status': 'healthy', |
| 'timestamp': datetime.now().isoformat(), |
| 'service': 'SmartHeal Bot API' |
| }) |
| |
| @self.app.route('/api/bot/analytics', methods=['GET']) |
| def get_bot_analytics(): |
| """Get comprehensive bot analytics for dashboard""" |
| try: |
| analytics_data = self.database_manager.get_analytics_data() |
| |
| |
| analytics_data.update(self._get_trend_data()) |
| |
| return jsonify({ |
| 'success': True, |
| 'data': analytics_data, |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting bot analytics: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e), |
| 'timestamp': datetime.now().isoformat() |
| }), 500 |
| |
| @self.app.route('/api/bot/analytics/details/<int:analysis_id>', methods=['GET']) |
| def get_analysis_details(analysis_id): |
| """Get detailed analysis information""" |
| try: |
| query = "SELECT * FROM ai_analyses WHERE id = %s" |
| analysis = self.database_manager.execute_query_one(query, (analysis_id,)) |
| |
| if not analysis: |
| return jsonify({ |
| 'success': False, |
| 'error': 'Analysis not found' |
| }), 404 |
| |
| |
| if analysis.get('created_at'): |
| analysis['created_at'] = analysis['created_at'].isoformat() |
| |
| return jsonify({ |
| 'success': True, |
| 'data': analysis, |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting analysis details: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e) |
| }), 500 |
| |
| @self.app.route('/api/bot/interactions', methods=['GET']) |
| def get_bot_interactions(): |
| """Get bot interaction history""" |
| try: |
| limit = request.args.get('limit', 50, type=int) |
| interactions = self.database_manager.get_interaction_history(limit) |
| |
| |
| for interaction in interactions: |
| if interaction.get('interacted_at'): |
| interaction['interacted_at'] = interaction['interacted_at'].isoformat() |
| |
| return jsonify({ |
| 'success': True, |
| 'data': interactions, |
| 'count': len(interactions), |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting bot interactions: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e) |
| }), 500 |
| |
| @self.app.route('/api/bot/sessions', methods=['GET']) |
| def get_session_analytics(): |
| """Get session analytics""" |
| try: |
| session_data = self.database_manager.get_session_analytics() |
| |
| return jsonify({ |
| 'success': True, |
| 'data': session_data, |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting session analytics: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e) |
| }), 500 |
| |
| @self.app.route('/api/bot/stats/summary', methods=['GET']) |
| def get_summary_stats(): |
| """Get summary statistics for dashboard widgets""" |
| try: |
| |
| total_analyses = self.database_manager.execute_query_one("SELECT COUNT(*) as count FROM ai_analyses") |
| total_patients = self.database_manager.execute_query_one("SELECT COUNT(DISTINCT patient_id) as count FROM bot_interactions WHERE patient_id IS NOT NULL") |
| total_sessions = self.database_manager.execute_query_one("SELECT COUNT(*) as count FROM analysis_sessions") |
| |
| |
| today_analyses = self.database_manager.execute_query_one(""" |
| SELECT COUNT(*) as count FROM ai_analyses |
| WHERE DATE(created_at) = CURDATE() |
| """) |
| |
| |
| avg_processing_time = self.database_manager.execute_query_one(""" |
| SELECT AVG(processing_time) as avg_time FROM ai_analyses |
| WHERE processing_time IS NOT NULL |
| """) |
| |
| avg_risk_score = self.database_manager.execute_query_one(""" |
| SELECT AVG(risk_score) as avg_risk FROM ai_analyses |
| WHERE risk_score IS NOT NULL |
| """) |
| |
| summary = { |
| 'total_analyses': total_analyses['count'] if total_analyses else 0, |
| 'total_patients': total_patients['count'] if total_patients else 0, |
| 'total_sessions': total_sessions['count'] if total_sessions else 0, |
| 'today_analyses': today_analyses['count'] if today_analyses else 0, |
| 'avg_processing_time': round(avg_processing_time['avg_time'], 2) if avg_processing_time and avg_processing_time['avg_time'] else 0, |
| 'avg_risk_score': round(avg_risk_score['avg_risk'], 1) if avg_risk_score and avg_risk_score['avg_risk'] else 0 |
| } |
| |
| return jsonify({ |
| 'success': True, |
| 'data': summary, |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting summary stats: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e) |
| }), 500 |
| |
| @self.app.route('/api/bot/models/performance', methods=['GET']) |
| def get_model_performance(): |
| """Get AI model performance metrics""" |
| try: |
| performance_data = self.database_manager.execute_query(""" |
| SELECT |
| model_version, |
| COUNT(*) as total_analyses, |
| AVG(processing_time) as avg_processing_time, |
| AVG(risk_score) as avg_risk_score, |
| MIN(created_at) as first_used, |
| MAX(created_at) as last_used |
| FROM ai_analyses |
| WHERE model_version IS NOT NULL |
| GROUP BY model_version |
| ORDER BY last_used DESC |
| """, fetch=True) |
| |
| |
| for model in performance_data: |
| if model.get('first_used'): |
| model['first_used'] = model['first_used'].isoformat() |
| if model.get('last_used'): |
| model['last_used'] = model['last_used'].isoformat() |
| if model.get('avg_processing_time'): |
| model['avg_processing_time'] = round(model['avg_processing_time'], 2) |
| if model.get('avg_risk_score'): |
| model['avg_risk_score'] = round(model['avg_risk_score'], 1) |
| |
| return jsonify({ |
| 'success': True, |
| 'data': performance_data or [], |
| 'timestamp': datetime.now().isoformat() |
| }) |
| |
| except Exception as e: |
| self.logger.error(f"Error getting model performance: {e}") |
| return jsonify({ |
| 'success': False, |
| 'error': str(e) |
| }), 500 |
| |
| def _get_trend_data(self) -> Dict[str, Any]: |
| """Get trend data for dashboard charts""" |
| try: |
| |
| trend_data = self.database_manager.execute_query(""" |
| SELECT |
| DATE(created_at) as analysis_date, |
| COUNT(*) as count |
| FROM ai_analyses |
| WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) |
| GROUP BY DATE(created_at) |
| ORDER BY analysis_date |
| """, fetch=True) |
| |
| |
| labels = [] |
| data = [] |
| |
| if trend_data: |
| for row in trend_data: |
| labels.append(row['analysis_date'].strftime('%Y-%m-%d')) |
| data.append(row['count']) |
| |
| |
| risk_distribution = self.database_manager.execute_query(""" |
| SELECT risk_level, COUNT(*) as count |
| FROM ai_analyses |
| GROUP BY risk_level |
| """, fetch=True) |
| |
| risk_labels = [] |
| risk_data = [] |
| |
| if risk_distribution: |
| for row in risk_distribution: |
| risk_labels.append(row['risk_level']) |
| risk_data.append(row['count']) |
| |
| |
| processing_time_data = self.database_manager.execute_query(""" |
| SELECT |
| CASE |
| WHEN processing_time < 1 THEN '< 1s' |
| WHEN processing_time < 2 THEN '1-2s' |
| WHEN processing_time < 5 THEN '2-5s' |
| WHEN processing_time < 10 THEN '5-10s' |
| ELSE '> 10s' |
| END as time_range, |
| COUNT(*) as count |
| FROM ai_analyses |
| WHERE processing_time IS NOT NULL |
| GROUP BY time_range |
| ORDER BY |
| CASE |
| WHEN processing_time < 1 THEN 1 |
| WHEN processing_time < 2 THEN 2 |
| WHEN processing_time < 5 THEN 3 |
| WHEN processing_time < 10 THEN 4 |
| ELSE 5 |
| END |
| """, fetch=True) |
| |
| processing_labels = [] |
| processing_data = [] |
| |
| if processing_time_data: |
| for row in processing_time_data: |
| processing_labels.append(row['time_range']) |
| processing_data.append(row['count']) |
| |
| return { |
| 'trend_labels': labels, |
| 'trend_data': data, |
| 'risk_level_labels': risk_labels, |
| 'risk_level_data': risk_data, |
| 'processing_time_labels': processing_labels, |
| 'processing_time_data': processing_data |
| } |
| |
| except Exception as e: |
| self.logger.error(f"Error getting trend data: {e}") |
| return { |
| 'trend_labels': [], |
| 'trend_data': [], |
| 'risk_level_labels': [], |
| 'risk_level_data': [], |
| 'processing_time_labels': [], |
| 'processing_time_data': [] |
| } |
| |
| def start_api_server(self): |
| """Start the API server in a background thread""" |
| if self.running: |
| self.logger.warning("API server is already running") |
| return |
| |
| def run_server(): |
| try: |
| self.logger.info(f"Starting SmartHeal Bot API server on port {self.port}") |
| self.app.run(host='0.0.0.0', port=self.port, debug=False, threaded=True) |
| except Exception as e: |
| self.logger.error(f"Error starting API server: {e}") |
| |
| self.running = True |
| self.api_thread = threading.Thread(target=run_server, daemon=True) |
| self.api_thread.start() |
| |
| |
| time.sleep(1) |
| self.logger.info(f"β
SmartHeal Bot API server started on http://0.0.0.0:{self.port}") |
| |
| def stop_api_server(self): |
| """Stop the API server""" |
| self.running = False |
| if self.api_thread and self.api_thread.is_alive(): |
| self.logger.info("Stopping SmartHeal Bot API server") |
| |
| |
| |
| def is_running(self) -> bool: |
| """Check if the API server is running""" |
| return self.running and self.api_thread and self.api_thread.is_alive() |
|
|
| class DashboardIntegrationManager: |
| """Manager class for dashboard integration functionality""" |
| |
| def __init__(self, database_manager: DashboardDatabaseManager): |
| self.database_manager = database_manager |
| self.api = DashboardAPI(database_manager) |
| self.logger = logging.getLogger(__name__) |
| |
| def start_integration(self): |
| """Start dashboard integration services""" |
| try: |
| self.api.start_api_server() |
| self.logger.info("β
Dashboard integration started successfully") |
| except Exception as e: |
| self.logger.error(f"β Failed to start dashboard integration: {e}") |
| |
| def stop_integration(self): |
| """Stop dashboard integration services""" |
| try: |
| self.api.stop_api_server() |
| self.logger.info("β
Dashboard integration stopped") |
| except Exception as e: |
| self.logger.error(f"β Error stopping dashboard integration: {e}") |
| |
| def log_analysis_session(self, session_data: Dict[str, Any]) -> Optional[int]: |
| """Log an analysis session for dashboard tracking""" |
| try: |
| session_id = self.database_manager.save_analysis_session(session_data) |
| if session_id: |
| self.logger.info(f"β
Analysis session logged with ID: {session_id}") |
| return session_id |
| except Exception as e: |
| self.logger.error(f"β Error logging analysis session: {e}") |
| return None |
| |
| def log_bot_interaction(self, interaction_data: Dict[str, Any]) -> Optional[int]: |
| """Log a bot interaction for dashboard tracking""" |
| try: |
| interaction_id = self.database_manager.save_bot_interaction(interaction_data) |
| if interaction_id: |
| self.logger.info(f"β
Bot interaction logged with ID: {interaction_id}") |
| return interaction_id |
| except Exception as e: |
| self.logger.error(f"β Error logging bot interaction: {e}") |
| return None |
| |
| def get_integration_status(self) -> Dict[str, Any]: |
| """Get the status of dashboard integration""" |
| return { |
| 'api_running': self.api.is_running(), |
| 'database_connected': self.database_manager.get_connection() is not None, |
| 'timestamp': datetime.now().isoformat() |
| } |
|
|
|
|