DrishtiSharma's picture
Update app.py
5fb305a verified
import gradio as gr
import matplotlib.pyplot as plt
import pandas as np
import tempfile
from datetime import datetime
from langchain_core.messages import HumanMessage
from tools import tools
from agents import *
from config import *
from workflow import create_workflow
import logging
import threading
import queue
# Global timeout variable
TIMEOUT_SECONDS = 300
# Initialize workflow
graph = create_workflow()
# Configure logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
# Helper Functions
def run_graph(input_message, history, user_details):
def invoke_workflow(q):
try:
# Determine if the query is general or personal
if "how" in input_message.lower() or "what" in input_message.lower():
general_query = True if "general" in input_message.lower() else False
else:
general_query = False
system_prompt = (
"You are a fitness and health assistant. "
"If the user's query is personal, provide tailored advice based on their details, including BMI and caloric needs. "
"If the query is general, respond broadly without relying on personal metrics. "
"Encourage the user to ask follow-up questions and maintain a conversational tone."
)
# Summarize user details
user_details_summary = (
f"Name: {user_details.get('name', 'Unknown')}, "
f"Age: {user_details.get('age', 'Unknown')}, "
f"Gender: {user_details.get('gender', 'Unknown')}, "
f"Weight: {user_details.get('weight', 'Unknown')} kg, "
f"Height: {user_details.get('height', 'Unknown')} cm, "
f"Activity Level: {user_details.get('activity_level', 'Unknown')}"
)
# Messages for the workflow
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"User details: {user_details_summary}" if not general_query else "General query"},
{"role": "user", "content": input_message}
]
response = graph.invoke({"messages": messages})
# Extract LLM response
llm_response = None
for msg in response.get("messages", []):
if isinstance(msg, HumanMessage) and msg.name in ["nutritionist", "workout_coach", "general_expert"]:
llm_response = msg.content
break
if llm_response:
q.put(llm_response)
else:
q.put("The workflow did not return a valid response. Please try again.")
except Exception as e:
q.put(f"An error occurred: {e}")
q = queue.Queue()
thread = threading.Thread(target=invoke_workflow, args=(q,))
thread.start()
thread.join(timeout=TIMEOUT_SECONDS)
if thread.is_alive():
return f"The request took longer than {TIMEOUT_SECONDS} seconds and timed out. Please try again."
return q.get()
def calculate_bmi(height, weight):
height_m = height / 100
bmi = weight / (height_m ** 2)
if bmi < 18.5:
status = "underweight"
elif 18.5 <= bmi < 24.9:
status = "normal weight"
elif 25 <= bmi < 29.9:
status = "overweight"
else:
status = "obese"
return bmi, status
def visualize_bmi_and_calories(bmi, calories):
categories = ["Underweight", "Normal Weight", "Overweight", "Obese"]
bmi_values = [18.5, 24.9, 29.9, 40]
calorie_range = [1500, 2000, 2500, 3000]
fig, ax1 = plt.subplots(figsize=(10, 6))
# BMI Visualization
ax1.bar(categories, bmi_values, color=['blue', 'green', 'orange', 'red'], alpha=0.6, label="BMI Ranges")
ax1.axhline(y=bmi, color='purple', linestyle='--', linewidth=2, label=f"Your BMI: {bmi:.2f}")
ax1.set_ylabel("BMI Value")
ax1.set_title("BMI and Caloric Needs Visualization")
ax1.legend(loc="upper left")
# Calorie Visualization
ax2 = ax1.twinx()
ax2.plot(categories, calorie_range, 'o-', color='magenta', label="Calorie Ranges")
ax2.axhline(y=calories, color='cyan', linestyle='--', linewidth=2, label=f"Your Calorie Needs: {calories:.2f} kcal")
ax2.set_ylabel("Calories")
ax2.legend(loc="upper right")
plt.tight_layout()
# Save visualization to a temporary file
temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
try:
plt.savefig(temp_file.name)
finally:
plt.close()
return temp_file.name
def calculate_calories(age, weight, height, activity_level, gender):
if gender.lower() == "male":
bmr = 10 * weight + 6.25 * height - 5 * age + 5
else:
bmr = 10 * weight + 6.25 * height - 5 * age - 161
activity_multipliers = {
"sedentary": 1.2,
"lightly active": 1.375,
"moderately active": 1.55,
"very active": 1.725,
"extra active": 1.9,
}
activity_level = activity_level.lower()
return bmr * activity_multipliers.get(activity_level, 1.2)
# Interface Components
with gr.Blocks() as demo:
gr.Markdown("<strong>FIT.AI - Your Fitness and Wellbeing Coach</strong>")
with gr.Tabs():
with gr.Tab("Visualization + Chat"):
# User Input
with gr.Row():
user_name = gr.Textbox(placeholder="Enter your name", label="Name")
user_age = gr.Number(label="Age (years)", value=25, precision=0)
user_gender = gr.Dropdown(choices=["Male", "Female"], label="Gender", value="Male")
user_weight = gr.Number(label="Weight (kg)", value=70, precision=1)
user_height = gr.Number(label="Height (cm)", value=170, precision=1)
activity_level = gr.Dropdown(
choices=["Sedentary", "Lightly active", "Moderately active", "Very active", "Extra active"],
label="Activity Level",
value="Moderately active"
)
# Visualization Output
bmi_chart = gr.Image(label="BMI and Calorie Chart")
# Chat Outputs
with gr.Row():
chatbot = gr.Chatbot(label="Chat with FIT.AI")
text_input = gr.Textbox(placeholder="Type your question here...", label="Your Question")
submit_button = gr.Button("Submit")
clear_button = gr.Button("Clear Chat")
def submit_message(message, history=[]):
user_details = {
"name": user_name.value,
"age": user_age.value,
"weight": user_weight.value,
"height": user_height.value,
"activity_level": activity_level.value,
"gender": user_gender.value
}
bmi, status = calculate_bmi(user_details['height'], user_details['weight'])
calories = calculate_calories(
user_details['age'], user_details['weight'], user_details['height'], user_details['activity_level'], user_details['gender']
)
chart_path = visualize_bmi_and_calories(bmi, calories)
user_prompt = (
f"User wants advice on: {message}\n"
f"User Details:\n"
f"- Name: {user_details['name']}\n"
f"- Age: {user_details['age']}\n"
f"- Gender: {user_details['gender']}\n"
f"- Weight: {user_details['weight']} kg\n"
f"- Height: {user_details['height']} cm\n"
f"- Activity Level: {user_details['activity_level']}\n"
f"- BMI: {bmi:.2f} ({status})\n"
f"- Daily Caloric Needs: {calories:.2f} kcal\n"
f"\nProvide tailored advice based on these metrics."
)
response = run_graph(user_prompt, history, user_details)
history.append(("User", message))
if isinstance(response, str):
history.append(("FIT.AI", response + "\nLet me know if there's anything else you'd like to ask! 😊"))
else:
history.append(("FIT.AI", "An unexpected response was received."))
return history, chart_path
submit_button.click(submit_message, inputs=[text_input, chatbot], outputs=[chatbot, bmi_chart])
clear_button.click(lambda: ([], ""), inputs=None, outputs=[chatbot, bmi_chart])
# Calculator + Visualization Tab
with gr.Tab("Calculator + Visualization"):
user_age_calc = gr.Number(label="Age (years)", value=25, precision=0)
user_gender_calc = gr.Dropdown(choices=["Male", "Female"], label="Gender", value="Male")
user_weight_calc = gr.Number(label="Weight (kg)", value=70, precision=1)
user_height_calc = gr.Number(label="Height (cm)", value=170, precision=1)
activity_level_calc = gr.Dropdown(
choices=["Sedentary", "Lightly active", "Moderately active", "Very active", "Extra active"],
label="Activity Level",
value="Moderately active"
)
bmi_output = gr.Label(label="BMI Result")
calorie_output = gr.Label(label="Calorie Needs")
bmi_chart_calc = gr.Image(label="BMI and Calorie Chart")
calculate_button = gr.Button("Calculate")
def calculate_metrics(age, weight, height, gender, activity_level):
bmi, status = calculate_bmi(height, weight)
calories = calculate_calories(age, weight, height, activity_level, gender)
chart_path = visualize_bmi_and_calories(bmi, calories)
return f"Your BMI is {bmi:.2f}, considered {status}.", f"Daily calorie needs: {calories:.2f} kcal", chart_path
calculate_button.click(
calculate_metrics,
inputs=[user_age_calc, user_weight_calc, user_height_calc, user_gender_calc, activity_level_calc],
outputs=[bmi_output, calorie_output, bmi_chart_calc]
)
demo.launch(share=True)