Spaces:
Running
Running
Upload app.py
Browse files
app.py
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import google.generativeai as genai
|
3 |
+
import os
|
4 |
+
from dotenv import load_dotenv
|
5 |
+
|
6 |
+
# Load environment variables
|
7 |
+
load_dotenv()
|
8 |
+
|
9 |
+
# Streamlit Page Configuration
|
10 |
+
st.set_page_config(
|
11 |
+
page_title="VitalEdge: Your AI-Powered Health & Fitness Companion π",
|
12 |
+
page_icon="ποΈββοΈ",
|
13 |
+
layout="wide",
|
14 |
+
initial_sidebar_state="expanded"
|
15 |
+
)
|
16 |
+
|
17 |
+
# Custom Styling
|
18 |
+
st.markdown(
|
19 |
+
"""
|
20 |
+
<style>
|
21 |
+
.main { padding: 2rem; }
|
22 |
+
.stButton>button { width: 100%; border-radius: 5px; height: 3em; }
|
23 |
+
.success-box, .warning-box {
|
24 |
+
padding: 1rem; border-radius: 0.5rem;
|
25 |
+
}
|
26 |
+
.success-box { background-color: #f0fff4; border: 1px solid #9ae6b4; }
|
27 |
+
.warning-box { background-color: #fffaf0; border: 1px solid #fbd38d; }
|
28 |
+
div[data-testid="stExpander"] div[role="button"] p { font-size: 1.1rem; font-weight: 600; }
|
29 |
+
.qa-box { margin-bottom: 1rem; padding: 1rem; background-color: #f9f9f9; border-radius: 0.5rem; border: 1px solid #ddd; }
|
30 |
+
.qa-box h4 { margin: 0 0 0.5rem; }
|
31 |
+
</style>
|
32 |
+
""",
|
33 |
+
unsafe_allow_html=True
|
34 |
+
)
|
35 |
+
|
36 |
+
def display_plan(title, content, key_details, tips=None):
|
37 |
+
"""Reusable function to display both Dietary and Fitness plans."""
|
38 |
+
with st.expander(title, expanded=True):
|
39 |
+
col1, col2 = st.columns([2, 1])
|
40 |
+
with col1:
|
41 |
+
st.markdown(f"### π― {key_details['title']}")
|
42 |
+
st.success(content.get(key_details['key'], "Information not available"))
|
43 |
+
st.markdown(f"### {key_details['plan_title']}")
|
44 |
+
st.write(content.get(key_details['plan_key'], "Plan not available"))
|
45 |
+
with col2:
|
46 |
+
if tips:
|
47 |
+
st.markdown(f"### π‘ {tips['title']}")
|
48 |
+
for tip in content.get(tips['key'], "").split('\n'):
|
49 |
+
if tip.strip():
|
50 |
+
st.info(tip)
|
51 |
+
|
52 |
+
def generate_ai_plan(user_profile, additional_input, model, instructions):
|
53 |
+
"""Function to generate AI-powered health and fitness plans."""
|
54 |
+
context = f"Relevant Context:\n{user_profile}\nAdditional Input:\n{additional_input}"
|
55 |
+
prompt_parts = [context, "\n".join(instructions)]
|
56 |
+
response = model.generate_content(prompt_parts)
|
57 |
+
return response.text
|
58 |
+
|
59 |
+
def main():
|
60 |
+
st.title("VitalEdge: Your AI-Powered Health & Fitness Companion π")
|
61 |
+
st.markdown(
|
62 |
+
"""
|
63 |
+
<div style='background-color: #00008B; padding: 1rem; border-radius: 0.5rem; margin-bottom: 2rem;'>
|
64 |
+
Achieve Your Best Self with AI-Powered Health & Fitness! π
|
65 |
+
Get personalized dietary, fitness, and lifestyle plans tailored to your goals and preferences. Powered by Manojkumar Tech, our intelligent system delivers a holistic approach to wellness. πͺπβ¨
|
66 |
+
</div>
|
67 |
+
""",
|
68 |
+
unsafe_allow_html=True
|
69 |
+
)
|
70 |
+
|
71 |
+
if 'dietary_plan' not in st.session_state:
|
72 |
+
st.session_state.dietary_plan = {}
|
73 |
+
st.session_state.fitness_plan = {}
|
74 |
+
st.session_state.activity_plan = {}
|
75 |
+
st.session_state.qa_pairs = []
|
76 |
+
st.session_state.plans_generated = False
|
77 |
+
|
78 |
+
# Sidebar - User Profile
|
79 |
+
with st.sidebar:
|
80 |
+
st.header("π€ Your Profile")
|
81 |
+
col1, col2 = st.columns(2)
|
82 |
+
with col1:
|
83 |
+
age = st.number_input("Age", min_value=10, max_value=100, step=1)
|
84 |
+
height = st.number_input("Height (cm)", min_value=100.0, max_value=250.0, step=0.1)
|
85 |
+
activity_level = st.selectbox("Activity Level", ["Sedentary", "Lightly Active", "Moderately Active", "Very Active", "Extremely Active"])
|
86 |
+
dietary_preferences = st.selectbox("Dietary Preferences", ["Vegetarian", "Keto", "Gluten Free", "Low Carb", "Dairy Free"])
|
87 |
+
with col2:
|
88 |
+
weight = st.number_input("Weight (kg)", min_value=20.0, max_value=300.0, step=0.1)
|
89 |
+
sex = st.selectbox("Sex", ["Male", "Female", "Other"])
|
90 |
+
fitness_goals = st.selectbox("Fitness Goals", ["Lose Weight", "Gain Muscle", "Endurance", "Stay Fit", "Strength Training"])
|
91 |
+
work_type = st.selectbox("Work Type", ["Student", "Desk Job", "Field Work", "Remote Work"])
|
92 |
+
country = st.text_input("Country", placeholder="Enter your country")
|
93 |
+
|
94 |
+
additional_input = st.text_area("π Additional Information", placeholder="Share any specific goals, challenges, or preferences...")
|
95 |
+
|
96 |
+
google_api_key = os.getenv("GOOGLE_API_KEY")
|
97 |
+
if google_api_key:
|
98 |
+
try:
|
99 |
+
genai.configure(api_key=google_api_key)
|
100 |
+
gemini_model = genai.GenerativeModel('gemini-2.0-flash')
|
101 |
+
except Exception as e:
|
102 |
+
st.error(f"β Error initializing Gemini model: {e}")
|
103 |
+
return
|
104 |
+
|
105 |
+
if st.button("π― Generate My Personalized Plan"):
|
106 |
+
with st.spinner("Creating your perfect health and fitness routine..."):
|
107 |
+
user_profile = f"""
|
108 |
+
Age: {age}, Weight: {weight}kg, Height: {height}cm, Sex: {sex},
|
109 |
+
Activity Level: {activity_level}, Dietary Preferences: {dietary_preferences},
|
110 |
+
Fitness Goals: {fitness_goals}, Work Type: {work_type}, Country: {country}
|
111 |
+
"""
|
112 |
+
|
113 |
+
dietary_instructions = [
|
114 |
+
"Focus only on the provided user profile and context.",
|
115 |
+
"Generate a meal plan relevant to their profile without unrelated details.",
|
116 |
+
"Suggest a detailed meal plan for the day, including breakfast, lunch, dinner, and snacks.",
|
117 |
+
"Explain why the plan is suited to the user's goals and country-specific considerations.",
|
118 |
+
"Use Chain-of-Thought reasoning for high-quality recommendations."
|
119 |
+
]
|
120 |
+
|
121 |
+
fitness_instructions = [
|
122 |
+
"Focus only on the provided user profile and goals.",
|
123 |
+
"Include warm-up, main workout, and cool-down exercises tailored to the user.",
|
124 |
+
"Explain the benefits of each exercise, focusing on relevance to user goals.",
|
125 |
+
"Ensure plans are specific and actionable with no unrelated information."
|
126 |
+
]
|
127 |
+
|
128 |
+
activity_instructions = [
|
129 |
+
"Suggest activities based only on the user's input and preferences.",
|
130 |
+
"Provide country-specific recommendations for recreational and mental health activities.",
|
131 |
+
"Explain the benefits of each activity and how it aligns with the user's goals.",
|
132 |
+
"Avoid extraneous information outside the provided context."
|
133 |
+
]
|
134 |
+
|
135 |
+
try:
|
136 |
+
dietary_plan = generate_ai_plan(user_profile, additional_input, gemini_model, dietary_instructions)
|
137 |
+
fitness_plan = generate_ai_plan(user_profile, additional_input, gemini_model, fitness_instructions)
|
138 |
+
activity_plan = generate_ai_plan(user_profile, additional_input, gemini_model, activity_instructions)
|
139 |
+
|
140 |
+
st.session_state.dietary_plan = {
|
141 |
+
"why_this_plan_works": "High Protein, Healthy Fats, Moderate Carbohydrates, and Caloric Balance",
|
142 |
+
"meal_plan": dietary_plan,
|
143 |
+
"important_considerations": "Hydration, Electrolytes, Fiber, and Adjusting Portion Sizes"
|
144 |
+
}
|
145 |
+
|
146 |
+
st.session_state.fitness_plan = {
|
147 |
+
"goals": "Build strength, improve endurance, and maintain overall fitness",
|
148 |
+
"routine": fitness_plan,
|
149 |
+
"tips": "Track progress, Rest adequately, Maintain proper form, Stay consistent"
|
150 |
+
}
|
151 |
+
|
152 |
+
st.session_state.activity_plan = {
|
153 |
+
"suggestions": activity_plan,
|
154 |
+
"why_these": "Activities selected to improve mental health, relaxation, and social interaction."
|
155 |
+
}
|
156 |
+
|
157 |
+
st.session_state.plans_generated = True
|
158 |
+
|
159 |
+
display_plan("π Your Personalized Dietary Plan", st.session_state.dietary_plan, {"title": "Why this plan works", "key": "why_this_plan_works", "plan_title": "π½οΈ Meal Plan", "plan_key": "meal_plan"})
|
160 |
+
display_plan("πͺ Your Personalized Fitness Plan", st.session_state.fitness_plan, {"title": "π― Goals", "key": "goals", "plan_title": "ποΈββοΈ Exercise Routine", "plan_key": "routine"}, {"title": "π‘ Pro Tips", "key": "tips"})
|
161 |
+
display_plan("π Suggested Activities", st.session_state.activity_plan, {"title": "Why these activities?", "key": "why_these", "plan_title": "π Activity Suggestions", "plan_key": "suggestions"})
|
162 |
+
except Exception as e:
|
163 |
+
st.error(f"β An error occurred: {e}")
|
164 |
+
|
165 |
+
if st.session_state.plans_generated:
|
166 |
+
st.header("β Questions about your plan?")
|
167 |
+
question_input = st.text_input("What would you like to know?")
|
168 |
+
|
169 |
+
if st.button("Get Answer"):
|
170 |
+
if question_input:
|
171 |
+
with st.spinner("Finding the best answer for you..."):
|
172 |
+
dietary_plan = st.session_state.dietary_plan
|
173 |
+
fitness_plan = st.session_state.fitness_plan
|
174 |
+
activity_plan = st.session_state.activity_plan
|
175 |
+
|
176 |
+
context = f"Dietary Plan: {dietary_plan.get('meal_plan', '')}\n\nFitness Plan: {fitness_plan.get('routine', '')}\n\nActivity Plan: {activity_plan.get('suggestions', '')}"
|
177 |
+
full_context = f"{context}\nAdditional Input: {additional_input}\nUser Question: {question_input}"
|
178 |
+
|
179 |
+
try:
|
180 |
+
instructions = [
|
181 |
+
"Answer only based on the provided context and plans.",
|
182 |
+
"If the question is unrelated to the plans, respond with: 'This question is outside the scope of your personalized plan.'",
|
183 |
+
"Ensure clarity, conciseness, and accuracy in your response."
|
184 |
+
]
|
185 |
+
prompt_parts = [full_context, "\n".join(instructions)]
|
186 |
+
response = gemini_model.generate_content(prompt_parts)
|
187 |
+
|
188 |
+
if response.text:
|
189 |
+
answer = response.text
|
190 |
+
else:
|
191 |
+
answer = "Sorry, I couldn't generate a response at this time."
|
192 |
+
|
193 |
+
st.session_state.qa_pairs.append((question_input, answer))
|
194 |
+
except Exception as e:
|
195 |
+
st.error(f"β An error occurred while getting the answer: {e}")
|
196 |
+
|
197 |
+
if st.session_state.qa_pairs:
|
198 |
+
st.header("π¬ Q&A History")
|
199 |
+
for question, answer in st.session_state.qa_pairs:
|
200 |
+
with st.container():
|
201 |
+
st.markdown(f"**Q:** {question}")
|
202 |
+
st.markdown(f"**A:** {answer}", unsafe_allow_html=True)
|
203 |
+
|
204 |
+
if __name__ == "__main__":
|
205 |
+
main()
|