Spaces:
Running
Running
| import streamlit as st | |
| from prompt_builder import build_prompt | |
| from model_api import query_model | |
| from diet_builder import build_diet_prompt | |
| st.set_page_config(page_title="FitPlan AI", layout="wide") | |
| # --- UI STYLING (Preserving your exact original look) --- | |
| st.markdown(""" | |
| <style> | |
| header {visibility: hidden;} | |
| .stApp { background: linear-gradient(135deg, #f6d365 0%, #fda085 100%); background-attachment: fixed; } | |
| section[data-testid="stSidebar"] { background-color: #000000 !important; } | |
| section[data-testid="stSidebar"] h1, section[data-testid="stSidebar"] p { color: #FFFFFF !important; } | |
| .assessment-card { | |
| background-color: white !important; padding: 25px; border-radius: 15px; | |
| border-left: 10px solid #004d57; color: #000000 !important; margin-bottom: 30px; | |
| } | |
| .stat-card { background: white; padding: 20px; border-radius: 15px; text-align: center; border-top: 5px solid #004d57; box-shadow: 0 4px 15px rgba(0,0,0,0.05); } | |
| .day-container { background-color: white !important; padding: 30px; border-radius: 25px; margin-bottom: 40px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); } | |
| .day-header { color: #004d57; font-size: 26px; font-weight: bold; margin-bottom: 20px; border-bottom: 2px solid #f0f2f6; padding-bottom: 15px; } | |
| .item-row { display: flex; align-items: center; justify-content: space-between; padding: 18px 0; border-bottom: 1px solid #f1f1f1; } | |
| .item-row:last-child { border-bottom: none; } | |
| .ex-name { flex: 2; font-weight: 600; color: #2d3436; font-size: 18px; } | |
| .stat-group { display: flex; gap: 15px; flex: 1.5; justify-content: flex-end; } | |
| .stat-pill { text-align: center; min-width: 75px; background: #f8f9fa; padding: 6px; border-radius: 12px; } | |
| .stat-val { color: #004d57; font-weight: bold; font-size: 15px; display: block; } | |
| .stat-label { font-size: 10px; color: #636e72; text-transform: uppercase; display: block; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- NAVIGATION STATE --- | |
| if 'page' not in st.session_state: st.session_state.page = 'dashboard' | |
| if 'user_data' not in st.session_state: st.session_state.user_data = None | |
| if 'workout_plan' not in st.session_state: st.session_state.workout_plan = None | |
| if 'diet_plan' not in st.session_state: st.session_state.diet_plan = None | |
| # --- SIDEBAR --- | |
| with st.sidebar: | |
| st.markdown("# π€ FitPlan AI") | |
| if st.button("π Dashboard", use_container_width=True): | |
| st.session_state.page = 'dashboard' | |
| st.rerun() | |
| if st.button("ποΈ Workout Plan", use_container_width=True): | |
| # If a plan exists, show the result, otherwise show input | |
| if st.session_state.workout_plan: | |
| st.session_state.page = 'result' | |
| else: | |
| st.session_state.page = 'input' | |
| st.rerun() | |
| if st.button("π₯ Dietary Plan", use_container_width=True): | |
| st.session_state.page = 'diet' | |
| st.rerun() | |
| if st.session_state.workout_plan: | |
| st.write("---") | |
| if st.button("π Create New Profile"): | |
| st.session_state.workout_plan = None | |
| st.session_state.diet_plan = None | |
| st.session_state.user_data = None | |
| st.session_state.page = 'input' | |
| st.rerun() | |
| # --- 1. DASHBOARD PAGE --- | |
| if st.session_state.page == 'dashboard': | |
| st.title("π Your Dashboard") | |
| if st.session_state.user_data: | |
| d = st.session_state.user_data | |
| col1, col2, col3 = st.columns(3) | |
| with col1: st.markdown(f'<div class="stat-card"><div style="font-size:24px; font-weight:bold;">{d["name"]}</div><div style="color:#636e72;">USER</div></div>', unsafe_allow_html=True) | |
| with col2: st.markdown(f'<div class="stat-card"><div style="font-size:24px; font-weight:bold;">{d["bmi"]:.1f}</div><div style="color:#636e72;">BMI</div></div>', unsafe_allow_html=True) | |
| with col3: st.markdown(f'<div class="stat-card"><div style="font-size:24px; font-weight:bold; color:{d["color"]}">{d["status"]}</div><div style="color:#636e72;">HEALTH STATUS</div></div>', unsafe_allow_html=True) | |
| st.write("---") | |
| st.success(f"Current Goal: **{d['goal']}**") | |
| else: | |
| st.warning("Go to 'Workout Plan' to generate your profile.") | |
| # --- 2. INPUT PAGE --- | |
| elif st.session_state.page == 'input': | |
| st.title("ποΈ Fitness Profile") | |
| c1, c2, c3 = st.columns([2, 1, 1]) | |
| with c1: name = st.text_input("Name") | |
| with c2: gender = st.selectbox("Gender", ["Male", "Female", "Other"]) | |
| with c3: age = st.number_input("Age", min_value=1, value=19) | |
| h, w = st.columns(2) | |
| with h: height = st.number_input("Height (cm)", min_value=1.0) | |
| with w: weight = st.number_input("Weight (kg)", min_value=1.0) | |
| goal = st.selectbox("Goal", ["Build Muscle", "Weight Loss", "Strength", "Flexibility"]) | |
| level = st.selectbox("Fitness Level", ["Beginner", "Intermediate", "Advanced"]) | |
| equip = st.multiselect("Equipment", ["Dumbbells", "Kettlebells", "Pull-up Bar", "Resistance Bands", "Yoga Mat", "No Equipment"]) | |
| if st.button("Generate Complete Plan"): | |
| prompt, bmi, status, color = build_prompt(name, gender, age, height, weight, goal, level, equip) | |
| with st.spinner("AI is crafting your routine..."): | |
| st.session_state.workout_plan = query_model(prompt) | |
| st.session_state.user_data = {"name": name, "bmi": bmi, "status": status, "color": color, "age": age, "gender": gender, "goal": goal, "height": height, "weight": weight, "level": level} | |
| st.session_state.diet_plan = None | |
| st.session_state.page = 'result' | |
| st.rerun() | |
| # --- 3. WORKOUT RESULT (Stored Memory) --- | |
| elif st.session_state.page == 'result': | |
| d = st.session_state.user_data | |
| st.markdown(f'<div class="assessment-card"><h2>Hello {d["name"]}</h2><p>BMI: <strong>{d["bmi"]:.2f}</strong> | <span style="color:{d["color"]}">{d["status"]}</span></p></div>', unsafe_allow_html=True) | |
| raw = st.session_state.workout_plan | |
| days = ["Day 1:", "Day 2:", "Day 3:", "Day 4:", "Day 5:"] | |
| for i in range(len(days)): | |
| start = raw.find(days[i]) | |
| if start != -1: | |
| end = raw.find(days[i+1]) if i+1 < len(days) else len(raw) | |
| day_text = raw[start:end].strip() | |
| st.markdown(f'<div class="day-container"><div class="day-header">π· {days[i][:-1]}</div>', unsafe_allow_html=True) | |
| for line in day_text.split("\n"): | |
| if "|" in line: | |
| parts = [p.strip() for p in line.replace("- ", "").split("|")] | |
| if len(parts) == 4: | |
| n, s, r, rs = parts | |
| st.markdown(f'<div class="item-row"><div class="ex-name">π₯ {n}</div><div class="stat-group"><div class="stat-pill"><span class="stat-val">{s}</span><span class="stat-label">Sets</span></div><div class="stat-pill"><span class="stat-val">{r}</span><span class="stat-label">Reps</span></div><div class="stat-pill" style="background:#fff3e0;"><span class="stat-val" style="color:#e65100;">{rs}</span><span class="stat-label">Rest</span></div></div></div>', unsafe_allow_html=True) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| st.download_button("π₯ Download Plan", data=raw, file_name=f"{d['name']}_Plan.txt") | |
| # --- 4. DIETARY PAGE (Stored Memory) --- | |
| elif st.session_state.page == 'diet': | |
| st.title("π₯ Dietary Plan") | |
| if st.session_state.user_data: | |
| d = st.session_state.user_data | |
| # Only query the model if the diet doesn't exist yet | |
| if not st.session_state.diet_plan: | |
| d_prompt = build_diet_prompt(d['name'], d['gender'], d['age'], d['height'], d['weight'], d['goal']) | |
| with st.spinner("Generating unique meal plan..."): | |
| st.session_state.diet_plan = query_model(d_prompt) | |
| raw_diet = st.session_state.diet_plan | |
| st.markdown('<div class="day-container"><div class="day-header">π Daily Nutrition</div>', unsafe_allow_html=True) | |
| for line in raw_diet.split("\n"): | |
| if "|" in line: | |
| parts = [p.strip() for p in line.replace("- ", "").split("|")] | |
| if len(parts) == 4: | |
| m_n, m_t, m_i, m_c = parts | |
| st.markdown(f'<div class="item-row"><div class="ex-name">π΄ {m_n}<br><small>{m_i}</small></div><div class="stat-group"><div class="stat-pill"><span class="stat-val">{m_t}</span><span class="stat-label">Time</span></div><div class="stat-pill" style="background:#e8f5e9;"><span class="stat-val" style="color:#2e7d32;">{m_c}</span><span class="stat-label">Energy</span></div></div></div>', unsafe_allow_html=True) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| else: | |
| st.warning("Generate a profile in 'Workout Plan' first.") |