AmrGaberr commited on
Commit
05851ff
·
verified ·
1 Parent(s): dbb4ec9

Upload 10 files

Browse files
deployment/api/app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_from_directory
2
+ from flask_cors import CORS
3
+ from predict import predict_injury_risk
4
+ from recommendation import generate_recommendations
5
+ import os
6
+ import requests
7
+ import json
8
+ import logging
9
+
10
+ # Set up logging
11
+ logging.basicConfig(level=logging.DEBUG)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ # Define paths
15
+ FRONTEND_FOLDER = os.path.join(os.path.dirname(__file__), "..", "..", "UI2") # Point to UI2 in the root directory
16
+
17
+ app = Flask(__name__, static_folder=FRONTEND_FOLDER, template_folder=FRONTEND_FOLDER, static_url_path="")
18
+ CORS(app)
19
+
20
+ # Cohere API setup
21
+ COHERE_API_TOKEN = os.getenv("COHERE_API_TOKEN")
22
+ if not COHERE_API_TOKEN:
23
+ raise ValueError("COHERE_API_TOKEN environment variable is not set")
24
+ COHERE_API_URL = "https://api.cohere.ai/v1/generate"
25
+
26
+ # System prompt for context
27
+ SYSTEM_PROMPT = (
28
+ "You are AthleteGuard AI, an assistant for a sports injury prediction system. "
29
+ "Answer questions about sports injuries, prevention, and the system concisely (under 100 words). "
30
+ "Context: Sports injuries result from overuse, improper technique, or insufficient recovery. "
31
+ "Shin splints are caused by repetitive stress, often from running or improper footwear. "
32
+ "Prevent injuries with balanced training, proper gear, and fatigue monitoring. "
33
+ "The system uses RandomForest and XGBoost to predict injury risk with 92% accuracy. "
34
+ "For personal injury risk queries, prompt the user to provide data via the calculator form."
35
+ )
36
+
37
+ # Serve index.html
38
+ @app.route("/", methods=["GET"])
39
+ def serve_index():
40
+ return send_from_directory(FRONTEND_FOLDER, "index.html")
41
+
42
+ # Serve calculator.html
43
+ @app.route("/calculator.html", methods=["GET"])
44
+ def serve_calculator():
45
+ return send_from_directory(FRONTEND_FOLDER, "calculator.html")
46
+
47
+ # Serve about.html
48
+ @app.route("/about.html", methods=["GET"])
49
+ def serve_about():
50
+ return send_from_directory(FRONTEND_FOLDER, "about.html")
51
+
52
+ # Serve chatbot.html
53
+ @app.route("/chatbot.html", methods=["GET"])
54
+ def serve_chatbot():
55
+ return send_from_directory(FRONTEND_FOLDER, "chatbot.html")
56
+
57
+ # Serve static files (JS, CSS)
58
+ @app.route("/<path:filename>")
59
+ def serve_static_files(filename):
60
+ return send_from_directory(FRONTEND_FOLDER, filename)
61
+
62
+ # API: Injury prediction
63
+ @app.route("/predict", methods=["POST"])
64
+ def predict():
65
+ try:
66
+ input_data = request.get_json()
67
+ result = predict_injury_risk(input_data)
68
+ return jsonify(result)
69
+ except Exception as e:
70
+ logger.error(f"Predict endpoint error: {str(e)}")
71
+ return jsonify({"error": str(e)}), 400
72
+
73
+ # API: Chatbot
74
+ @app.route("/chat", methods=["POST"])
75
+ def chat():
76
+ try:
77
+ data = request.get_json()
78
+ logger.debug(f"Received chat request: {data}")
79
+ user_input = data.get("message", "").lower()
80
+ user_data = data.get("user_data", None)
81
+
82
+ if "risk" in user_input or "predict" in user_input or "my" in user_input:
83
+ if user_data:
84
+ result = predict_injury_risk(user_data)
85
+ response = (
86
+ f"Your injury risk is {result['predicted_risk_level']} "
87
+ f"({result['injury_likelihood_percent']}%). "
88
+ f"Recommendations: {', '.join(result['recommendations'])}"
89
+ )
90
+ else:
91
+ response = "Please provide details like age, training hours, and fatigue level using the calculator form."
92
+ return jsonify({"response": response, "requires_data": not user_data})
93
+
94
+ headers = {
95
+ "Authorization": f"Bearer {COHERE_API_TOKEN}",
96
+ "Content-Type": "application/json"
97
+ }
98
+ payload = {
99
+ "model": "command",
100
+ "prompt": f"{SYSTEM_PROMPT}\nUser: {user_input}\nAssistant:",
101
+ "max_tokens": 100,
102
+ "temperature": 0.7
103
+ }
104
+ logger.debug(f"Sending Cohere API request: {payload}")
105
+ response = requests.post(COHERE_API_URL, headers=headers, json=payload)
106
+ logger.debug(f"Cohere API response status: {response.status_code}, content: {response.text}")
107
+
108
+ if response.status_code != 200:
109
+ logger.error(f"Cohere API error: {response.status_code} - {response.text}")
110
+ return jsonify({"error": f"Cohere API error: {response.status_code} - {response.text}"}), 500
111
+
112
+ try:
113
+ answer = response.json()["generations"][0]["text"].strip()
114
+ except (KeyError, IndexError, TypeError) as e:
115
+ logger.error(f"Unexpected API response format: {str(response.json())}")
116
+ return jsonify({"error": f"Unexpected API response format: {str(response.json())}"}), 500
117
+
118
+ if "prevent" in user_input or "avoid" in user_input:
119
+ sample_input = {
120
+ "Fatigue_Level": 5,
121
+ "Recovery_Time_Between_Sessions": 12,
122
+ "Total_Weekly_Training_Hours": 10,
123
+ "High_Intensity_Training_Hours": 3,
124
+ "Previous_Injury_Count": 0,
125
+ "Flexibility_Score": 5,
126
+ "Agility_Score": 5,
127
+ "Strength_Training_Frequency": 2,
128
+ "Experience_Level": 1,
129
+ "Sport_Type": 0
130
+ }
131
+ recs = generate_recommendations(sample_input)
132
+ answer += " Specific tips: " + ", ".join(recs)
133
+
134
+ logger.debug(f"Chat response: {answer}")
135
+ return jsonify({"response": answer, "requires_data": False})
136
+ except Exception as e:
137
+ logger.error(f"Chat endpoint error: {str(e)}")
138
+ return jsonify({"error": str(e)}), 400
139
+
140
+ if __name__ == "__main__":
141
+ app.run(host="0.0.0.0", port=7860)
deployment/api/predict.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import joblib
4
+ import os
5
+ from recommendation import generate_recommendations
6
+
7
+ # Define mappings for categorical variables (consistent with CalibrateLikelihood.ipynb)
8
+ gender_mapping = {"Male": 0, "Female": 1}
9
+ experience_mapping = {"Beginner": 0, "Intermediate": 1, "Advanced": 2, "Professional": 3}
10
+ injury_type_mapping = {"None": 0, "Sprain": 1, "Ligament Tear": 2, "Tendonitis": 3, "Strain": 4, "Fracture": 5}
11
+ sport_type_mapping = {"Football": 0, "Basketball": 1, "Swimming": 2, "Tennis": 3, "Running": 4}
12
+ risk_level_mapping = {0: "High", 1: "Low", 2: "Medium"}
13
+
14
+ # Define model directory using relative path
15
+ MODEL_DIR = os.path.join(os.path.dirname(__file__), "..", "model")
16
+
17
+ # Load models, encoders, and calibration threshold
18
+ try:
19
+ rf_model = joblib.load(os.path.join(MODEL_DIR, "rf_injury_model.pkl"))
20
+ xgb_model = joblib.load(os.path.join(MODEL_DIR, "xgboost_injury_model.pkl"))
21
+ calibrator = joblib.load(os.path.join(MODEL_DIR, "likelihood_calibrator.pkl"))
22
+ rf_encoder = joblib.load(os.path.join(MODEL_DIR, "rf_target_encoder.pkl"))
23
+ xgb_encoder = joblib.load(os.path.join(MODEL_DIR, "xgb_target_encoder.pkl"))
24
+ low_threshold = joblib.load(os.path.join(MODEL_DIR, "calibration_threshold.pkl"))
25
+ except FileNotFoundError as e:
26
+ raise FileNotFoundError(f"Model file not found: {str(e)}. Ensure all model files are in {MODEL_DIR}.")
27
+
28
+ # Verify encoder consistency
29
+ if not (rf_encoder.classes_ == xgb_encoder.classes_).all():
30
+ raise ValueError("RandomForest and XGBoost encoders have inconsistent class mappings.")
31
+
32
+ def preprocess_data(data_dict):
33
+ """
34
+ Preprocess the input data consistently with CalibrateLikelihood.ipynb.
35
+
36
+ Args:
37
+ data_dict (dict): Input dictionary containing athlete data.
38
+
39
+ Returns:
40
+ pd.DataFrame: Preprocessed features ready for prediction.
41
+ """
42
+ try:
43
+ df = pd.DataFrame([data_dict])
44
+
45
+ df["Gender"] = df["Gender"].map(gender_mapping).fillna(0).astype(int)
46
+ df["Sport_Type"] = df["Sport_Type"].map(sport_type_mapping).fillna(0).astype(int)
47
+ df["Experience_Level"] = df["Experience_Level"].map(experience_mapping).fillna(0).astype(int)
48
+ df["Previous_Injury_Type"] = df["Previous_Injury_Type"].fillna("None")
49
+ df["Previous_Injury_Type"] = df["Previous_Injury_Type"].map(injury_type_mapping).fillna(0).astype(int)
50
+
51
+ df["Total_Weekly_Training_Hours"] = df["Total_Weekly_Training_Hours"].replace(0, 0.1)
52
+
53
+ df["Intensity_Ratio"] = df["High_Intensity_Training_Hours"] / df["Total_Weekly_Training_Hours"]
54
+ df["Recovery_Per_Training"] = df["Recovery_Time_Between_Sessions"] / df["Total_Weekly_Training_Hours"]
55
+
56
+ features = [
57
+ "Age", "Gender", "Sport_Type", "Experience_Level", "Flexibility_Score",
58
+ "Total_Weekly_Training_Hours", "High_Intensity_Training_Hours", "Strength_Training_Frequency",
59
+ "Recovery_Time_Between_Sessions", "Training_Load_Score", "Sprint_Speed", "Endurance_Score",
60
+ "Agility_Score", "Fatigue_Level", "Previous_Injury_Count", "Previous_Injury_Type",
61
+ "Intensity_Ratio", "Recovery_Per_Training"
62
+ ]
63
+
64
+ missing_features = [f for f in features if f not in df.columns]
65
+ if missing_features:
66
+ raise ValueError(f"Missing required features: {missing_features}")
67
+
68
+ X = df[features]
69
+ return X
70
+ except Exception as e:
71
+ raise Exception(f"Error in preprocessing data: {str(e)}")
72
+
73
+ def predict_injury_risk(user_input: dict) -> dict:
74
+ """
75
+ Predict injury risk using the ensemble of RandomForest and XGBoost models with calibrated probabilities.
76
+ Uses a data-driven threshold from calibration to classify Low vs. Medium risks.
77
+
78
+ Args:
79
+ user_input (dict): Input dictionary containing athlete data.
80
+
81
+ Returns:
82
+ dict: Prediction results including risk level, likelihood, and recommendations.
83
+ """
84
+ print("User Input Received:\n", user_input)
85
+
86
+ # Preprocess input
87
+ features = preprocess_data(user_input)
88
+ print("FINAL Features After Preprocessing:", list(features.columns))
89
+ print("Preprocessed Input:\n", features)
90
+
91
+ # Predict probabilities from both models
92
+ rf_probs = rf_model.predict_proba(features)
93
+ xgb_probs = xgb_model.predict_proba(features)
94
+ print("RandomForest Probabilities (High, Low, Medium):", rf_probs)
95
+ print("XGBoost Probabilities (High, Low, Medium):", xgb_probs)
96
+
97
+ # Ensemble average
98
+ avg_probs = (rf_probs + xgb_probs) / 2
99
+ predicted_class = np.argmax(avg_probs, axis=1)[0]
100
+ confidence = np.max(avg_probs, axis=1)[0]
101
+ predicted_label = rf_encoder.inverse_transform([predicted_class])[0]
102
+ print("Ensemble Probabilities (High, Low, Medium):", avg_probs)
103
+ print("Predicted Class:", predicted_class, "Label:", predicted_label, "Confidence:", confidence)
104
+
105
+ # Calibrate the probability using the likelihood calibrator
106
+ calib_data = pd.DataFrame({
107
+ "prob_high": [avg_probs[0][0]],
108
+ "prob_low": [avg_probs[0][1]],
109
+ "prob_medium": [avg_probs[0][2]]
110
+ })
111
+ injury_likelihood = calibrator.predict_proba(calib_data)[:, 1][0] * 100
112
+ print("Calibrated Injury Likelihood (%):", injury_likelihood)
113
+
114
+ # Adjust prediction using dynamic threshold based on raw prob_low
115
+ if avg_probs[0][1] > low_threshold and predicted_label != "Low":
116
+ print(f"⚠️ Calibration adjustment: Low probability ({avg_probs[0][1]:.2f}) above threshold ({low_threshold:.2f}) — classifying as Low.")
117
+ predicted_label = "Low"
118
+
119
+ # Generate recommendations
120
+ recommendations = generate_recommendations(user_input)
121
+
122
+ return {
123
+ "predicted_risk_level": predicted_label,
124
+ "injury_likelihood_percent": round(injury_likelihood, 2),
125
+ "model_class_probability": round(confidence * 100, 2),
126
+ "recommendations": recommendations
127
+ }
deployment/api/preprocessing.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+
3
+ def preprocess_data(df: pd.DataFrame) -> pd.DataFrame:
4
+ """
5
+ Preprocess input data for injury risk prediction.
6
+
7
+ Args:
8
+ df (pd.DataFrame): Input DataFrame with raw features.
9
+
10
+ Returns:
11
+ pd.DataFrame: Processed DataFrame with engineered features.
12
+ """
13
+ # Input validation
14
+ required_columns = [
15
+ "Age", "Gender", "Sport_Type", "Experience_Level", "Flexibility_Score",
16
+ "Total_Weekly_Training_Hours", "High_Intensity_Training_Hours", "Strength_Training_Frequency",
17
+ "Recovery_Time_Between_Sessions", "Training_Load_Score", "Sprint_Speed", "Endurance_Score",
18
+ "Agility_Score", "Fatigue_Level", "Previous_Injury_Count", "Previous_Injury_Type"
19
+ ]
20
+
21
+ # Check for missing columns
22
+ missing_cols = [col for col in required_columns if col not in df.columns]
23
+ if missing_cols:
24
+ raise ValueError(f"Missing required columns: {missing_cols}")
25
+
26
+ # Create a copy to avoid modifying the original DataFrame
27
+ df_processed = df.copy()
28
+
29
+ # Handle missing values (fill with median)
30
+ df_processed.fillna(df_processed.median(), inplace=True)
31
+
32
+ # Replace 0 with 0.1 in Total_Weekly_Training_Hours to avoid division by zero
33
+ df_processed["Total_Weekly_Training_Hours"] = df_processed["Total_Weekly_Training_Hours"].replace(0, 0.1)
34
+
35
+ # Create derived features
36
+ df_processed["Intensity_Ratio"] = df_processed["High_Intensity_Training_Hours"] / df_processed["Total_Weekly_Training_Hours"]
37
+ df_processed["Recovery_Per_Training"] = df_processed["Recovery_Time_Between_Sessions"] / df_processed["Total_Weekly_Training_Hours"]
38
+
39
+ # Define final feature set (excluding Predicted_Injury_Type)
40
+ model_features = [
41
+ "Age", "Gender", "Sport_Type", "Experience_Level", "Flexibility_Score",
42
+ "Total_Weekly_Training_Hours", "High_Intensity_Training_Hours", "Strength_Training_Frequency",
43
+ "Recovery_Time_Between_Sessions", "Training_Load_Score", "Sprint_Speed", "Endurance_Score",
44
+ "Agility_Score", "Fatigue_Level", "Previous_Injury_Count", "Previous_Injury_Type",
45
+ "Intensity_Ratio", "Recovery_Per_Training"
46
+ ]
47
+
48
+ return df_processed[model_features]
deployment/api/recommendation.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Professional Injury Prevention Recommendation System
2
+ """
3
+ Generates evidence-based, personalized injury prevention recommendations for athletes.
4
+ Aligned with the injury prediction model and integrated with the frontend.
5
+ Recommendations include actionable advice, priorities, detailed explanations, and credible sources.
6
+ """
7
+
8
+ from typing import List, Dict, Any
9
+ import uuid
10
+
11
+ def generate_recommendations(user_input: Dict[str, Any]) -> List[str]:
12
+ """
13
+ Generate professional, targeted injury prevention strategies.
14
+
15
+ Args:
16
+ user_input: Dictionary with fields like Age, Gender, Fatigue_Level, etc.
17
+
18
+ Returns:
19
+ List of recommendation strings (simplified for compatibility with existing frontend).
20
+ """
21
+ # Internal structure for recommendations with categories
22
+ internal_recs = {
23
+ "Recovery Strategies": [],
24
+ "Training Adjustments": [],
25
+ "Injury Prevention": [],
26
+ "Nutrition": [],
27
+ "Mental Health": [],
28
+ "Sport-Specific Warm-Ups": []
29
+ }
30
+
31
+ # Helper function to calculate priority
32
+ def calculate_priority(factor_value: float, threshold: float, weight: float) -> float:
33
+ return min(1.0, max(0.0, (factor_value / threshold) * weight))
34
+
35
+ # Fatigue Management
36
+ fatigue = user_input.get("Fatigue_Level", 5)
37
+ if fatigue >= 8:
38
+ internal_recs["Recovery Strategies"].append({
39
+ "id": str(uuid.uuid4()),
40
+ "text": "High fatigue detected. Prioritize 48–72 hours of active recovery with hydration and 8+ hours of sleep nightly.",
41
+ "priority": calculate_priority(fatigue, 10, 0.9),
42
+ "details": "Incorporate light stretching and 2–3L of water daily. Monitor sleep quality with a tracker for optimal recovery.",
43
+ "source": "https://www.mayoclinic.org/healthy-lifestyle/fitness/in-depth/recovery/art-20057777",
44
+ "category": "Recovery Strategies"
45
+ })
46
+ elif fatigue >= 6:
47
+ internal_recs["Recovery Strategies"].append({
48
+ "id": str(uuid.uuid4()),
49
+ "text": "Elevated fatigue: Reduce high-intensity sessions by 20% this week and monitor soreness.",
50
+ "priority": calculate_priority(fatigue, 10, 0.7),
51
+ "details": "Use foam rolling for 10–15 minutes post-session to alleviate muscle tension and promote circulation.",
52
+ "source": "https://www.nsca.com/education/articles/recovery-techniques-for-athletes/",
53
+ "category": "Recovery Strategies"
54
+ })
55
+
56
+ # Recovery Time Optimization
57
+ recovery = user_input.get("Recovery_Time_Between_Sessions", 12)
58
+ if recovery < 8:
59
+ internal_recs["Recovery Strategies"].append({
60
+ "id": str(uuid.uuid4()),
61
+ "text": "Insufficient recovery time. Increase rest to 12–24 hours between sessions.",
62
+ "priority": calculate_priority(8 - recovery, 8, 0.8),
63
+ "details": "Schedule sessions to allow muscle repair, especially after high-intensity workouts, to reduce injury risk.",
64
+ "source": "https://pubmed.ncbi.nlm.nih.gov/28933711/",
65
+ "category": "Recovery Strategies"
66
+ })
67
+
68
+ # Intensity Ratio Check
69
+ total_hours = max(user_input.get("Total_Weekly_Training_Hours", 1), 1)
70
+ hi_hours = user_input.get("High_Intensity_Training_Hours", 0)
71
+ intensity_ratio = hi_hours / total_hours
72
+ if intensity_ratio > 0.7:
73
+ internal_recs["Training Adjustments"].append({
74
+ "id": str(uuid.uuid4()),
75
+ "text": "High-intensity training exceeds 70%. Shift to 60% low-intensity/technical work.",
76
+ "priority": calculate_priority(intensity_ratio, 1, 0.75),
77
+ "details": "Incorporate drills focusing on technique or endurance to balance training load and prevent overtraining.",
78
+ "source": "https://www.acsm.org/docs/default-source/files-for-resource-library/overtraining.pdf",
79
+ "category": "Training Adjustments"
80
+ })
81
+
82
+ # Previous Injury Consideration
83
+ injury_count = user_input.get("Previous_Injury_Count", 0)
84
+ if injury_count >= 2:
85
+ internal_recs["Injury Prevention"].append({
86
+ "id": str(uuid.uuid4()),
87
+ "text": "Multiple injuries noted. Add daily mobility and strength balance exercises.",
88
+ "priority": calculate_priority(injury_count, 5, 0.85),
89
+ "details": "Perform exercises like single-leg squats and hip bridges for 15 minutes daily to enhance joint stability.",
90
+ "source": "https://www.physio-pedia.com/Injury_Prevention_in_Sports",
91
+ "category": "Injury Prevention"
92
+ })
93
+
94
+ # Flexibility and Agility
95
+ flexibility = user_input.get("Flexibility_Score", 5)
96
+ if flexibility < 5:
97
+ internal_recs["Injury Prevention"].append({
98
+ "id": str(uuid.uuid4()),
99
+ "text": "Low flexibility. Include 10–15 minutes of dynamic warm-ups and static stretching daily.",
100
+ "priority": calculate_priority(5 - flexibility, 5, 0.65),
101
+ "details": "Focus on hamstrings, hip flexors, and shoulders with stretches like lunges and arm circles to improve range of motion.",
102
+ "source": "https://www.mayoclinic.org/healthy-lifestyle/fitness/in-depth/stretching/art-20047931",
103
+ "category": "Injury Prevention"
104
+ })
105
+
106
+ agility = user_input.get("Agility_Score", 5)
107
+ if agility < 5:
108
+ internal_recs["Training Adjustments"].append({
109
+ "id": str(uuid.uuid4()),
110
+ "text": "Improve agility with cone drills and ladder exercises twice weekly.",
111
+ "priority": calculate_priority(5 - agility, 5, 0.6),
112
+ "details": "Perform 3 sets of 10 reps for drills like lateral shuffles or T-drills to enhance quickness and coordination.",
113
+ "source": "https://www.nsca.com/education/articles/agility-and-quickness-training/",
114
+ "category": "Training Adjustments"
115
+ })
116
+
117
+ # Strength Training Frequency
118
+ strength_freq = user_input.get("Strength_Training_Frequency", 0)
119
+ if strength_freq < 2:
120
+ internal_recs["Training Adjustments"].append({
121
+ "id": str(uuid.uuid4()),
122
+ "text": "Increase strength training to 2–3 sessions/week for joint stability.",
123
+ "priority": calculate_priority(2 - strength_freq, 2, 0.7),
124
+ "details": "Include compound lifts like squats and deadlifts with moderate weights to build resilience.",
125
+ "source": "https://www.acsm.org/docs/default-source/files-for-resource-library/strength-training.pdf",
126
+ "category": "Training Adjustments"
127
+ })
128
+
129
+ # Nutrition for Recovery
130
+ if fatigue >= 6 or recovery < 12:
131
+ internal_recs["Nutrition"].append({
132
+ "id": str(uuid.uuid4()),
133
+ "text": "Optimize nutrition with 1.2–2.0g/kg body weight protein daily for recovery.",
134
+ "priority": calculate_priority(max(fatigue, 12 - recovery), 10, 0.6),
135
+ "details": "Consume protein-rich meals within 2 hours post-workout (e.g., chicken, eggs, or whey) to support muscle repair.",
136
+ "source": "https://jissn.biomedcentral.com/articles/10.1186/s12970-017-0177-8",
137
+ "category": "Nutrition"
138
+ })
139
+
140
+ # Mental Health
141
+ if fatigue >= 7:
142
+ internal_recs["Mental Health"].append({
143
+ "id": str(uuid.uuid4()),
144
+ "text": "Address mental fatigue with 10–15 minutes of mindfulness or meditation daily.",
145
+ "priority": calculate_priority(fatigue, 10, 0.55),
146
+ "details": "Use guided meditation apps or breathing exercises to reduce stress and improve focus.",
147
+ "source": "https://www.mayoclinic.org/tests-procedures/meditation/in-depth/meditation/art-20045858",
148
+ "category": "Mental Health"
149
+ })
150
+
151
+ # Sport-Specific Warm-Ups
152
+ sport_type = user_input.get("Sport_Type", 0)
153
+ if sport_type == 0: # Football
154
+ internal_recs["Sport-Specific Warm-Ups"].append({
155
+ "id": str(uuid.uuid4()),
156
+ "text": "Football: Perform dynamic warm-ups with high-knee sprints and lateral cuts for 10 minutes.",
157
+ "priority": 0.6,
158
+ "details": "Focus on explosive movements to prepare for sprinting and tackling demands.",
159
+ "source": "https://www.nsca.com/education/articles/warm-ups-for-soccer/",
160
+ "category": "Sport-Specific Warm-Ups"
161
+ })
162
+ elif sport_type == 3: # Running
163
+ internal_recs["Sport-Specific Warm-Ups"].append({
164
+ "id": str(uuid.uuid4()),
165
+ "text": "Running: Include 10-minute warm-ups with leg swings and walking lunges.",
166
+ "priority": 0.6,
167
+ "details": "Emphasize hip mobility and gradual pace increases to prevent shin splints and strains.",
168
+ "source": "https://www.runnersworld.com/training/a20787998/dynamic-warmup/",
169
+ "category": "Sport-Specific Warm-Ups"
170
+ })
171
+
172
+ # Age-Based Recommendations
173
+ age = user_input.get("Age", 30)
174
+ if age > 40:
175
+ internal_recs["Injury Prevention"].append({
176
+ "id": str(uuid.uuid4()),
177
+ "text": "Age over 40: Add low-impact cross-training (e.g., swimming, yoga) twice weekly.",
178
+ "priority": calculate_priority(age - 40, 40, 0.6),
179
+ "details": "Low-impact activities reduce joint stress while maintaining fitness.",
180
+ "source": "https://www.arthritis.org/health-wellness/healthy-living/physical-activity/other-activities/low-impact-exercises",
181
+ "category": "Injury Prevention"
182
+ })
183
+
184
+ # Gender-Specific Recommendations
185
+ gender = user_input.get("Gender", 0)
186
+ if gender == 1: # Female
187
+ internal_recs["Injury Prevention"].append({
188
+ "id": str(uuid.uuid4()),
189
+ "text": "Female athletes: Include pelvic floor exercises 3 times/week to support core stability.",
190
+ "priority": 0.65,
191
+ "details": "Exercises like Kegels strengthen the pelvic floor, reducing injury risk during high-impact activities.",
192
+ "source": "https://www.womenshealthmag.com/fitness/a20709126/pelvic-floor-exercises/",
193
+ "category": "Injury Prevention"
194
+ })
195
+
196
+ # Flatten recommendations for compatibility with existing frontend
197
+ flat_recommendations = []
198
+ for category in internal_recs:
199
+ for rec in internal_recs[category]:
200
+ flat_recommendations.append(rec["text"])
201
+
202
+ return flat_recommendations
deployment/model/calibration_threshold.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5d4a700a3a9d9189b6dc34f3e5704d1851855f86c19d32db13ecda0dccbd1202
3
+ size 117
deployment/model/likelihood_calibrator.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e669ee317df2373ba4b025d4f3d99c3b00258d488b9aa2612fd2db8e6586b210
3
+ size 1247
deployment/model/rf_injury_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:128cd660a06279de530ae484e6878c0049bd33536e8398bb90632820645919cf
3
+ size 80605269
deployment/model/rf_target_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:82243ebe944079adcf57dd5ff06f2dfebd07a9c71d824f2a2cd214555b5e36cf
3
+ size 553
deployment/model/xgb_target_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:82243ebe944079adcf57dd5ff06f2dfebd07a9c71d824f2a2cd214555b5e36cf
3
+ size 553
deployment/model/xgboost_injury_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6d31c73649e76af5c98d0095b63a6e8b437758591fe88455c70342ff9f202121
3
+ size 23315040