DietPro / app.py
Vishwas1's picture
Update app.py
c3050f9 verified
from flask import Flask, request, jsonify, render_template
import requests
import os
import math
import logging
app = Flask(__name__)
app.static_folder = 'static'
# Configure logging
logging.basicConfig(level=logging.DEBUG)
# Configuration
USDA_API_ENDPOINT = "https://api.nal.usda.gov/fdc/v1"
USDA_API_KEY = os.environ.get('USDA_API_KEY')
# Error messages
INVALID_INPUT_ERROR = "Invalid input"
MISSING_REQUIRED_FIELDS_ERROR = "Missing required fields"
FAILED_TO_FETCH_NUTRIENT_DATA_ERROR = "Failed to fetch nutrient data"
@app.route('/')
def index():
return render_template('index.html')
@app.route('/api/calculate-metrics', methods=['POST'])
def calculate_metrics():
data = request.json
app.logger.debug(f"Received data for calculate_metrics: {data}")
required_fields = ['age', 'gender', 'heightFeet', 'heightInches', 'weight', 'targetWeight', 'waist', 'neck', 'hip', 'steps', 'standingHours']
missing_fields = [field for field in required_fields if field not in data or data[field] is None]
if missing_fields:
app.logger.error(f"Missing required fields: {', '.join(missing_fields)}")
return jsonify({"error": MISSING_REQUIRED_FIELDS_ERROR, "missing_fields": missing_fields}), 400
try:
age = int(data['age'])
gender = data['gender']
height_feet = int(data['heightFeet'])
height_inches = int(data['heightInches'])
weight = float(data['weight']) # in kg
target_weight = float(data['targetWeight']) # in kg
waist = float(data['waist']) # in cm
neck = float(data['neck']) # in cm
hip = float(data['hip']) # in cm
steps = int(data['steps'])
standing_hours = float(data['standingHours'])
# Convert height to cm
height = (height_feet * 30.48) + (height_inches * 2.54) # Convert to cm
except (ValueError, KeyError) as e:
app.logger.error(f"Invalid input: {str(e)}")
return jsonify({"error": INVALID_INPUT_ERROR, "details": str(e)}), 400
if age <= 0 or height <= 0 or weight <= 0 or target_weight <= 0 or waist <= 0 or neck <= 0 or hip <= 0 or steps < 0 or standing_hours < 0:
app.logger.error("Invalid input values")
return jsonify({"error": INVALID_INPUT_ERROR, "details": "Input values must be positive numbers"}), 400
if gender not in ['male', 'female', 'other']:
app.logger.error("Invalid gender")
return jsonify({"error": INVALID_INPUT_ERROR, "details": "Gender must be 'male', 'female', or 'other'"}), 400
# Calculate BMI
bmi = weight / ((height / 100) ** 2)
# Calculate body fat percentage (using U.S. Navy method)
if gender == 'male':
body_fat = 86.010 * math.log10(waist - neck) - 70.041 * math.log10(height) + 36.76
elif gender == 'female':
body_fat = 163.205 * math.log10(waist + hip - neck) - 97.684 * math.log10(height) - 78.387
else:
# For 'other' gender, use an average of male and female calculations
body_fat_male = 86.010 * math.log10(waist - neck) - 70.041 * math.log10(height) + 36.76
body_fat_female = 163.205 * math.log10(waist + hip - neck) - 97.684 * math.log10(height) - 78.387
body_fat = (body_fat_male + body_fat_female) / 2
# Calculate lean body mass
lean_body_mass = weight * (1 - (body_fat / 100))
# Calculate recommended calorie intake (using Mifflin-St Jeor Equation)
if gender == 'male':
bmr = 10 * weight + 6.25 * height - 5 * age + 5
elif gender == 'female':
bmr = 10 * weight + 6.25 * height - 5 * age - 161
else:
# For 'other' gender, use an average of male and female calculations
bmr_male = 10 * weight + 6.25 * height - 5 * age + 5
bmr_female = 10 * weight + 6.25 * height - 5 * age - 161
bmr = (bmr_male + bmr_female) / 2
# Adjust for activity level
activity_factor = 1.2 + (steps / 10000) * 0.1 + (standing_hours / 24) * 0.1
recommended_calories = bmr * activity_factor
# Calculate time to reach target weight
weight_difference = abs(weight - target_weight)
daily_calorie_deficit = 500 # Assuming a 500 calorie deficit per day
days_to_target = (weight_difference * 7700) / daily_calorie_deficit # 7700 calories ≈ 1 kg of body fat
response = {
'bmi': round(bmi, 2),
'bodyFatPercentage': round(body_fat, 2),
'leanBodyMass': round(lean_body_mass, 2),
'recommendedCalories': round(recommended_calories),
'timeToTargetWeight': f"{round(days_to_target)} days"
}
app.logger.debug(f"Calculated metrics: {response}")
return jsonify(response)
@app.route('/api/personalized-recommendations', methods=['POST'])
def get_personalized_recommendations():
data = request.json
app.logger.debug(f"Received data for personalized_recommendations: {data}")
required_fields = ['age', 'gender', 'height', 'weight', 'targetWeight', 'bmi', 'bodyFatPercentage', 'recommendedCalories', 'steps', 'standingHours']
missing_fields = [field for field in required_fields if field not in data or data[field] is None]
if missing_fields:
app.logger.error(f"Missing required fields: {', '.join(missing_fields)}")
return jsonify({"error": MISSING_REQUIRED_FIELDS_ERROR, "missing_fields": missing_fields}), 400
try:
age = int(data['age'])
gender = data['gender']
height = float(data['height'])
weight = float(data['weight'])
target_weight = float(data['targetWeight'])
bmi = float(data['bmi'])
body_fat_percentage = float(data['bodyFatPercentage'])
recommended_calories = int(data['recommendedCalories'])
steps = int(data['steps'])
standing_hours = float(data['standingHours'])
except (ValueError, KeyError) as e:
app.logger.error(f"Invalid input: {str(e)}")
return jsonify({"error": INVALID_INPUT_ERROR, "details": str(e)}), 400
# Diet recommendations
diet_recommendations = []
if bmi < 18.5:
diet_recommendations.append("Increase calorie intake with nutrient-dense foods to reach a healthy weight")
diet_recommendations.append("Focus on foods high in healthy fats, such as avocados, nuts, and olive oil")
diet_recommendations.append("Incorporate protein-rich foods like lean meats, fish, eggs, and legumes")
elif 18.5 <= bmi < 25:
diet_recommendations.append("Maintain a balanced diet with a focus on whole foods")
diet_recommendations.append("Ensure adequate intake of fruits, vegetables, whole grains, and lean proteins")
diet_recommendations.append("Monitor portion sizes to maintain your healthy weight")
elif 25 <= bmi < 30:
diet_recommendations.append("Slightly reduce calorie intake and focus on nutrient-dense, low-calorie foods")
diet_recommendations.append("Increase fiber intake through vegetables, fruits, and whole grains")
diet_recommendations.append("Choose lean proteins and limit saturated fats")
else:
diet_recommendations.append("Reduce calorie intake and focus on whole, unprocessed foods")
diet_recommendations.append("Prioritize vegetables, lean proteins, and complex carbohydrates")
diet_recommendations.append("Avoid sugary drinks and high-calorie snacks")
if (gender == 'male' and body_fat_percentage > 25) or (gender == 'female' and body_fat_percentage > 32) or (gender == 'other' and body_fat_percentage > 28):
diet_recommendations.append("Increase protein intake to support lean muscle mass")
diet_recommendations.append("Consider adding a protein shake or Greek yogurt as a snack")
diet_recommendations.append("Include more fish, chicken, turkey, or plant-based proteins in your meals")
diet_recommendations.append(f"Aim for {recommended_calories} calories per day")
diet_recommendations.append("Include a variety of colorful fruits and vegetables in your diet")
diet_recommendations.append("Stay hydrated by drinking at least 8 glasses of water daily")
diet_recommendations.append("Limit processed foods and choose whole grains over refined grains")
if weight > target_weight:
diet_recommendations.append("Create a calorie deficit of 500 calories per day to lose weight")
diet_recommendations.append("Use smaller plates to help control portion sizes")
diet_recommendations.append("Start meals with a salad or vegetable soup to increase satiety")
elif weight < target_weight:
diet_recommendations.append("Increase your calorie intake by 500 calories per day to gain weight")
diet_recommendations.append("Add healthy, calorie-dense foods like nuts, seeds, and dried fruits to your meals")
diet_recommendations.append("Consider drinking smoothies made with fruits, oats, and protein powder")
else:
diet_recommendations.append("Maintain your current calorie intake to maintain your weight")
diet_recommendations.append("Practice mindful eating and listen to your body's hunger and fullness cues")
# Exercise recommendations
exercise_recommendations = []
if steps < 5000:
exercise_recommendations.append("Gradually increase your daily step count to at least 7,500 steps")
exercise_recommendations.append("Take short walks during breaks or after meals")
exercise_recommendations.append("Use stairs instead of elevators when possible")
elif 5000 <= steps < 10000:
exercise_recommendations.append("Aim to reach 10,000 steps per day for better health")
exercise_recommendations.append("Try brisk walking or light jogging to increase step count")
exercise_recommendations.append("Consider using a treadmill desk or walking meetings")
else:
exercise_recommendations.append("Great job on your step count! Consider adding more intense exercises")
exercise_recommendations.append("Incorporate interval training or hill walks to challenge yourself")
exercise_recommendations.append("Set new step goals to maintain motivation")
if standing_hours < 2:
exercise_recommendations.append("Try to increase your standing time to at least 2-4 hours per day")
exercise_recommendations.append("Use a standing desk or elevate your workstation for part of the day")
exercise_recommendations.append("Take phone calls while standing or walking")
elif 2 <= standing_hours < 4:
exercise_recommendations.append("Good job on standing! Aim to increase your standing time to 4-6 hours per day")
exercise_recommendations.append("Alternate between sitting and standing every 30-60 minutes")
exercise_recommendations.append("Try gentle exercises or stretches while standing")
else:
exercise_recommendations.append("Excellent standing habits! Maintain your current standing routine")
exercise_recommendations.append("Incorporate balance exercises or yoga poses while standing")
exercise_recommendations.append("Consider a treadmill desk for light walking while working")
exercise_recommendations.append("Include strength training exercises at least 2-3 times per week")
exercise_recommendations.append("Aim for at least 150 minutes of moderate-intensity aerobic activity per week")
exercise_recommendations.append("Don't forget to stretch before and after exercises to improve flexibility")
if weight > target_weight:
exercise_recommendations.append("Incorporate high-intensity interval training (HIIT) to boost fat burning")
exercise_recommendations.append("Try circuit training to combine strength and cardio exercises")
exercise_recommendations.append("Consider joining group fitness classes for motivation and guidance")
elif weight < target_weight:
exercise_recommendations.append("Focus on compound exercises and progressive overload to build muscle mass")
exercise_recommendations.append("Incorporate resistance band exercises for muscle growth")
exercise_recommendations.append("Ensure adequate rest between workouts for muscle recovery and growth")
else:
exercise_recommendations.append("Mix cardio and strength training to maintain your current weight and improve overall fitness")
exercise_recommendations.append("Try new activities or sports to keep your routine interesting")
exercise_recommendations.append("Set performance-based goals to stay motivated")
if age > 50:
exercise_recommendations.append("Include balance and flexibility exercises to maintain mobility")
exercise_recommendations.append("Consider low-impact activities like swimming or cycling to protect joints")
response = {
'dietRecommendations': diet_recommendations,
'exerciseRecommendations': exercise_recommendations
}
app.logger.debug(f"Generated recommendations: {response}")
return jsonify(response)
@app.route('/api/search-food', methods=['GET'])
def search_food():
query = request.args.get('query', '')
if not query:
return jsonify({"error": "Missing query parameter"}), 400
try:
response = requests.get(
f"{USDA_API_ENDPOINT}/foods/search",
params={
"api_key": USDA_API_KEY,
"query": query,
"dataType": ["Survey (FNDDS)"],
"pageSize": 10
}
)
response.raise_for_status()
data = response.json()
results = []
for food in data.get('foods', []):
nutrients = {nutrient['nutrientName']: nutrient['value'] for nutrient in food.get('foodNutrients', [])}
results.append({
'description': food['description'],
'calories': nutrients.get('Energy', 0),
'protein': nutrients.get('Protein', 0),
'carbs': nutrients.get('Carbohydrate, by difference', 0),
'fat': nutrients.get('Total lipid (fat)', 0)
})
return jsonify(results)
except requests.RequestException as e:
app.logger.error(f"Error fetching food data: {str(e)}")
return jsonify({"error": "Failed to fetch food data"}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860, debug=True)