""" CardioAI 模块2: Flask API服务 心血管疾病风险预测 - 后端接口 """ import joblib import numpy as np import pandas as pd from flask import Flask, request, jsonify, render_template from pathlib import Path # ==================== 常量定义 ==================== CODE_ROOT = Path(r"F:\My_Git_Project\CardioAI") MODEL_PATH = CODE_ROOT / "module2_predictor" / "cardio_predictor_model.pkl" # ==================== Flask应用 ==================== app = Flask(__name__, template_folder='templates', static_folder='static') # 全局变量存储模型 model = None def load_model(): """加载模型""" global model if model is None: print("📂 正在加载模型...") model = joblib.load(MODEL_PATH) print("✅ 模型加载成功!") return model # ==================== 路由定义 ==================== @app.route('/') def index(): """渲染前端页面""" return render_template('index.html') @app.route('/predict_cardio', methods=['POST']) def predict_cardio(): """ 心血管疾病风险预测接口 接收11个原始特征值的JSON POST请求 返回预测概率和结果 """ try: # 获取JSON数据 data = request.get_json() if not data: return jsonify({ 'success': False, 'error': '未收到数据' }), 400 # 定义特征列顺序(与训练时一致) feature_names = [ 'age_years', 'gender', 'height', 'weight', 'ap_hi', 'ap_lo', 'cholesterol', 'gluc', 'smoke', 'alco', 'active' ] # 从请求中提取特征值 features = [] missing_fields = [] for col in feature_names: if col in data: features.append(float(data[col])) else: missing_fields.append(col) features.append(0.0) # 默认值 # 计算BMI: weight / (height/100)^2 weight = float(data.get('weight', 0)) height = float(data.get('height', 0)) if height > 0: bmi = weight / ((height / 100) ** 2) features.append(bmi) else: features.append(0.0) if missing_fields: return jsonify({ 'success': False, 'error': f'缺少必要字段: {", ".join(missing_fields)}' }), 400 # 定义特征列名(与训练时一致) feature_columns = [ 'age_years', 'gender', 'height', 'weight', 'ap_hi', 'ap_lo', 'cholesterol', 'gluc', 'smoke', 'alco', 'active', 'bmi' ] # 转换为DataFrame格式 X_input = pd.DataFrame([features], columns=feature_columns) # 加载模型(如果尚未加载) predictor = load_model() # 预测 prediction = int(predictor.predict(X_input)[0]) prob_risk = float(predictor.predict_proba(X_input)[0][1]) prob_healthy = float(predictor.predict_proba(X_input)[0][0]) # 构建响应 result = { 'success': True, 'prediction': prediction, 'prediction_label': '有风险' if prediction == 1 else '健康', 'probability': { '健康': round(prob_healthy * 100, 2), '有风险': round(prob_risk * 100, 2) }, 'risk_level': get_risk_level(prob_risk), 'recommendation': get_recommendation(prob_risk, data) } return jsonify(result) except ValueError as e: return jsonify({ 'success': False, 'error': f'数据格式错误: {str(e)}' }), 400 except Exception as e: return jsonify({ 'success': False, 'error': f'预测失败: {str(e)}' }), 500 def get_risk_level(probability: float) -> str: """根据概率返回风险等级""" if probability < 0.3: return '🟢 低风险' elif probability < 0.5: return '🟡 中低风险' elif probability < 0.7: return '🟠 中高风险' else: return '🔴 高风险' def get_recommendation(probability: float, data: dict) -> str: """根据预测结果给出建议""" if probability < 0.3: return '继续保持健康的生活方式,定期体检。' elif probability < 0.5: return '建议适当增加运动,注意饮食均衡。' elif probability < 0.7: return '建议咨询医生,制定健康管理计划。' else: return '⚠️ 风险较高,请尽快就医检查。' @app.route('/health', methods=['GET']) def health_check(): """健康检查接口""" return jsonify({ 'status': 'healthy', 'service': 'CardioAI Cardiovascular Prediction API', 'version': '1.0.0' }) # ==================== 启动应用 ==================== if __name__ == '__main__': print("\n" + "="*60) print("❤️ CardioAI 心血管疾病风险预测 API") print("="*60) print(f"📂 模型路径: {MODEL_PATH}") print(f"🌐 启动地址: http://localhost:5001") print("="*60 + "\n") # 预加载模型 load_model() # 启动Flask应用 app.run( host='0.0.0.0', port=5001, debug=True )