FitPlan_login / app.py
LakshmiNandaS's picture
Update app.py
4094905 verified
import streamlit as st
import json
import hashlib
import re
from prompt_builder import build_prompt
from model_api import query_model
# ================= PAGE CONFIG (ONLY ONCE) =================
st.set_page_config(page_title="FitPlan Pro", layout="wide", initial_sidebar_state="collapsed")
# ================= USER DATABASE =================
DB_FILE = "users.json"
def load_users():
try:
with open(DB_FILE, "r") as f:
return json.load(f)
except:
return {}
def save_users(users):
with open(DB_FILE, "w") as f:
json.dump(users, f)
def hash_password(password):
return hashlib.sha256(password.encode()).hexdigest()
def extract_name_from_email(email):
name_part = email.split("@")[0]
name_part = re.sub(r'\d+', '', name_part)
return name_part.capitalize()
# ================= SESSION STATE =================
if "logged_in" not in st.session_state:
st.session_state.logged_in = False
if "mode" not in st.session_state:
st.session_state.mode = "login"
if "page" not in st.session_state:
st.session_state.page = "welcome"
if "user_details_done" not in st.session_state:
st.session_state.user_details_done = False
if "current_user" not in st.session_state:
st.session_state.current_user = ""
if "name" not in st.session_state:
st.session_state.name = ""
if "age" not in st.session_state:
st.session_state.age = 0
if "gender" not in st.session_state:
st.session_state.gender = ""
if "height_cm" not in st.session_state:
st.session_state.height_cm = 0
if "weight_kg" not in st.session_state:
st.session_state.weight_kg = 0
if "goal" not in st.session_state:
st.session_state.goal = ""
if "level" not in st.session_state:
st.session_state.level = ""
if "equipment" not in st.session_state:
st.session_state.equipment = []
if "workout_plan" not in st.session_state:
st.session_state.workout_plan = ""
if "bmi_info" not in st.session_state:
st.session_state.bmi_info = ""
if "user_name" not in st.session_state:
st.session_state.user_name = ""
# ================= LOGIN PAGE (UNCHANGED UI) =================
def apply_pro_styles():
st.markdown("""
<style>
header, footer, [data-testid="stToolbar"] {visibility: hidden;}
.block-container { padding: 0 !important; margin: 0 !important; max-width: 100% !important; }
section.main { padding: 0 !important; }
.stApp { background-color: white !important; height: 100vh !important; width: 100vw; overflow: hidden; }
.left-panel {
flex: 1.2;
background: linear-gradient(rgba(139, 0, 0, 0.75), rgba(139, 0, 0, 0.85)),
url("https://images.unsplash.com/photo-1534438327276-14e5300c3a48?q=80&w=2070");
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5% 5%;
color: white;
height: 100vh;
}
.hero-text {
font-size: 3.5rem;
font-weight: 800;
line-height: 1.1;
text-transform: uppercase;
margin: 30px 0;
}
.stat-row { display: flex; gap: 15px; }
.stat-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
padding: 15px;
border-radius: 10px;
flex: 1;
text-align: center;
}
.form-content { width: 100%; max-width: 400px; }
h1 { color: #D2042D !important; font-weight: 800 !important; font-size: 2.8rem !important; margin:0 !important;}
p.sub { color: #333 !important; margin-bottom: 20px; font-weight: 700; font-size: 1rem;}
label { color: black !important; font-weight: 700 !important; font-size: 0.85rem !important; }
div[data-baseweb="input"] {
border-radius: 8px !important;
border: 1.5px solid #eee !important;
}
div[data-baseweb="input"] input {
background-color: #2b2d3a !important;
color: white !important;
}
div[data-baseweb="input"] input::placeholder {
color: #cccccc !important;
}
div[data-testid="stCheckbox"] label,
div[data-testid="stCheckbox"] label p {
color: black !important;
font-weight: 700 !important;
}
div.stButton > button {
background: #D2042D !important;
color: white !important;
border-radius: 50px !important;
height: 48px !important;
width: 100%;
font-weight: 700 !important;
border: none !important;
}
</style>
""", unsafe_allow_html=True)
def show_auth_page():
apply_pro_styles()
l_col, r_col = st.columns([1.2, 1])
with l_col:
st.markdown("""
<div class="left-panel">
<div>
<h3>πŸ‹οΈ FitPlan Pro</h3>
<p>PERSONALIZED FITNESS</p>
<div class="hero-text">Your Personalized<br>Fitness Journey<br>Starts Here.</div>
</div>
<div class="stat-row">
<div class="stat-card"><b>12K+</b><br><small>ACTIVE MEMBERS</small></div>
<div class="stat-card"><b>5K+</b><br><small>CUSTOM PLANS</small></div>
<div class="stat-card"><b>94%</b><br><small>SUCCESS RATE</small></div>
</div>
</div>
""", unsafe_allow_html=True)
with r_col:
st.markdown('<div class="form-content">', unsafe_allow_html=True)
if st.session_state.mode == "login":
st.markdown('<h1>WELCOME BACK!</h1>', unsafe_allow_html=True)
st.markdown('<p class="sub">LOGIN TO YOUR ACCOUNT.</p>', unsafe_allow_html=True)
email = st.text_input("EMAIL ADDRESS", key="l_email", placeholder="Enter your email")
password = st.text_input("PASSWORD", type="password", key="l_pass", placeholder="Enter your password")
st.checkbox("Remember me", value=True)
if st.button("LOGIN β†’"):
users = load_users()
if email in users and users[email] == hash_password(password):
st.session_state.logged_in = True
st.session_state.current_user = email
st.session_state.page = "welcome"
st.rerun()
else:
st.error("Invalid Details")
st.markdown("<div style='margin-top:30px;'></div>", unsafe_allow_html=True)
st.markdown("<div style='color:black; font-weight:700; font-size:14px; margin-bottom:15px;'>Don't have an account?</div>", unsafe_allow_html=True)
if st.button("SIGN UP FREE"):
# OR Divider
st.markdown("""
<div style="display:flex; align-items:center; text-align:center; margin:25px 0;">
<div style="flex:1; height:1px; background:#ccc;"></div>
<div style="padding:0 10px; font-size:12px; color:#888;">OR</div>
<div style="flex:1; height:1px; background:#ccc;"></div>
</div>
""", unsafe_allow_html=True)
# Google Button (UI only)
st.markdown("""
<div style="
border:2px solid #bbb;
border-radius:10px;
padding:12px;
display:flex;
align-items:center;
justify-content:center;
gap:10px;
cursor:pointer;
transition:0.2s;
">
<img src="https://www.gstatic.com/images/branding/product/1x/gsa_512dp.png" width="18">
<span style="color:black; font-weight:700;">
Continue with Google
</span>
</div>
""", unsafe_allow_html=True)
st.session_state.mode = "signup"
st.rerun()
else:
st.markdown('<h1>GET STARTED</h1>', unsafe_allow_html=True)
st.markdown('<p class="sub">CREATE YOUR NEW ACCOUNT.</p>', unsafe_allow_html=True)
new_email = st.text_input("EMAIL", key="s_email")
new_pass = st.text_input("PASSWORD", type="password", key="s_pass")
if st.button("REGISTER"):
users = load_users()
if new_email and new_pass:
users[new_email] = hash_password(new_pass)
save_users(users)
st.success("Account Created!")
st.session_state.mode = "login"
st.rerun()
if st.button("BACK TO LOGIN"):
st.session_state.mode = "login"
st.rerun()
st.markdown('</div>', unsafe_allow_html=True)
def welcome_page():
apply_pro_styles()
user_name = st.session_state.get("name", "")
st.markdown("""
<style>
.welcome-card {
background: rgba(255,255,255,0.15);
backdrop-filter: blur(12px);
padding: 50px;
border-radius: 20px;
margin-top: 100px;
text-align: center;
color: white;
}
</style>
""", unsafe_allow_html=True)
if user_name:
st.markdown(f"""
<div class="welcome-card">
<h1>Hi {user_name} πŸ‘‹</h1>
<h3>Ready to transform your fitness journey?</h3>
<p>Your AI trainer is ready to build a plan tailored just for you.</p>
</div>
""", unsafe_allow_html=True)
if st.button("START BUILDING MY PLAN"):
st.session_state.page = "dashboard"
st.rerun()
def user_details_page():
apply_pro_styles()
st.title("Tell Us About Yourself")
col1, col2 = st.columns(2)
with col1:
name = st.text_input("NAME")
gender = st.selectbox("GENDER", ["Male", "Female", "Other"])
height_cm = st.number_input("HEIGHT (CM)", min_value=1.0)
with col2:
age = st.number_input("AGE", min_value=1)
weight_kg = st.number_input("WEIGHT (KG)", min_value=1.0)
if st.button("NEXT ➜"):
st.session_state.name = name
st.session_state.gender = gender
st.session_state.height_cm = height_cm
st.session_state.weight_kg = weight_kg
st.session_state.age = age
st.session_state.user_details_done = True
st.session_state.page = "goals"
st.rerun()
def goal_page():
apply_pro_styles()
user_email = st.session_state.get("current_user", "")
user_name = extract_name_from_email(user_email)
st.title(f"Hi {user_name} πŸ‘‹")
st.header("Set Your Fitness Goal")
goal = st.selectbox(
"GOAL",
["Build Muscle", "Weight Loss", "Strength", "Abs", "Flexible"]
)
level = st.selectbox(
"LEVEL",
["Beginner", "Intermediate", "Advanced"]
)
equipment = st.multiselect(
"EQUIPMENT",
["Dumbbells", "Barbell", "Kettlebells", "Yoga Mat", "Pull-up Bar", "No Equipment"]
)
if st.button("SUBMIT PROFILE"):
st.session_state.goal = goal
st.session_state.level = level
st.session_state.equipment = equipment
st.session_state.page = "dashboard"
st.rerun()
# ================= DASHBOARD (EXACTLY YOUR ORIGINAL CODE) =================
def dashboard():
# Apply SAME style as login
apply_pro_styles()
st.markdown("""
<style>
.stApp {
background: linear-gradient(rgba(139, 0, 0, 0.85), rgba(139, 0, 0, 0.9));
}
h1, h2, h3, label, p, span {
color: white !important;
font-weight: 700 !important;
}
.stTabs [role="tab"] {
background: rgba(255,255,255,0.15) !important;
border-radius: 8px !important;
margin-right: 5px !important;
}
.stTabs [aria-selected="true"] {
background: white !important;
}
.stTabs [aria-selected="true"] p {
color: #8B0000 !important;
font-weight: 900 !important;
}
div.stButton > button:first-child {
background: white !important;
color: #8B0000 !important;
font-weight: 900 !important;
font-size: 1.1rem !important;
height: 55px !important;
border-radius: 50px !important;
border: none !important;
}
.workout-container {
background: rgba(255,255,255,0.15);
backdrop-filter: blur(8px);
padding: 25px;
border-radius: 15px;
color: white;
margin-top: 20px;
line-height: 1.6;
}
</style>
""", unsafe_allow_html=True)
if 'workout_plan' not in st.session_state:
st.session_state.workout_plan = ""
if 'bmi_info' not in st.session_state:
st.session_state.bmi_info = ""
if 'user_name' not in st.session_state:
st.session_state.user_name = ""
st.title("πŸ‹οΈ PERSONALIZED FITPLAN")
tab1, tab2 = st.tabs(["πŸ“ ATHLETE PROFILE", "πŸ† YOUR WORKOUT PLAN"])
with tab1:
if st.button("GENERATE MY PLAN"):
with st.spinner("GENERATING YOUR PLAN..."):
prompt, bmi, bmi_status = build_prompt(
st.session_state.name,
st.session_state.gender,
st.session_state.height_cm,
st.session_state.weight_kg,
st.session_state.goal,
st.session_state.level,
st.session_state.equipment,
st.session_state.age
)
raw_output = query_model(prompt)
clean_text = re.sub(r'\*', '', raw_output)
clean_text = re.sub(r'\n{3,}', '\n\n', clean_text)
clean_text = clean_text.strip()
st.session_state.workout_plan = clean_text
st.session_state.bmi_info = f"BMI: {bmi:.2f} | {bmi_status.upper()}"
st.session_state.user_name = st.session_state.name.upper()
st.success("PLAN GENERATED!")
if st.button("SUBMIT PROFILE"):
if not name or height_cm <= 1 or weight_kg <= 1:
st.error("PLEASE FILL IN ALL FIELDS.")
else:
with st.spinner("GENERATING YOUR PLAN..."):
prompt, bmi, bmi_status = build_prompt(
name, gender, height_cm, weight_kg,
goal, level, equipment, age
)
raw_output = query_model(prompt)
clean_text = re.sub(r'\*', '', raw_output)
clean_text = re.sub(r'\n{3,}', '\n\n', clean_text)
clean_text = clean_text.strip()
st.session_state.workout_plan = clean_text
st.session_state.bmi_info = f"BMI: {bmi:.2f} | {bmi_status.upper()}"
st.session_state.user_name = name.upper()
st.success("PROFILE SUBMITTED!")
with tab2:
if st.session_state.workout_plan:
st.header(f"πŸ”₯ HI {st.session_state.user_name} πŸ‘‹")
st.markdown(f"""
<div class="workout-container">
πŸ“Š {st.session_state.bmi_info}
<hr>
{st.session_state.workout_plan}
</div>
""", unsafe_allow_html=True)
else:
st.warning("PLEASE SUBMIT YOUR PROFILE FIRST.")
# ================= ROUTER =================
if st.session_state.logged_in:
if st.session_state.page == "welcome":
welcome_page()
elif st.session_state.page == "details":
user_details_page()
elif st.session_state.page == "goals":
goal_page()
elif st.session_state.page == "dashboard":
dashboard()
else:
show_auth_page()