bsayon commited on
Commit
eab15b2
Β·
1 Parent(s): b2ffd21

updated UI

Browse files
Files changed (2) hide show
  1. src/app.py +674 -674
  2. src/streamlit_app.py +738 -8
src/app.py CHANGED
@@ -1,742 +1,742 @@
1
- import streamlit as st
2
- import json
3
- from datetime import datetime
4
- from typing import Dict, Any, List
5
- import pandas as pd
6
- import hashlib
7
- import os
8
- from service import generate_ai_response, create_user_profile_prompt, create_workout_type_prompt, create_nutrition_type_prompt, create_conversation_chat_prompt
9
 
10
- # Configure page
11
- st.set_page_config(
12
- page_title="AI Fitness Coach",
13
- page_icon="πŸ’ͺ",
14
- layout="wide",
15
- initial_sidebar_state="expanded"
16
- )
17
 
18
- # Custom CSS for better styling
19
- st.markdown("""
20
- <style>
21
- .main-header {
22
- font-size: 2.5rem;
23
- font-weight: bold;
24
- color: #FF6B35;
25
- text-align: center;
26
- margin-bottom: 2rem;
27
- }
28
- .section-header {
29
- font-size: 1.5rem;
30
- font-weight: bold;
31
- color: #2E86AB;
32
- margin: 1rem 0;
33
- border-bottom: 2px solid #2E86AB;
34
- padding-bottom: 0.5rem;
35
- }
36
- .profile-card {
37
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38
- padding: 1rem;
39
- border-radius: 10px;
40
- color: white;
41
- margin: 1rem 0;
42
- }
43
- .chat-message {
44
- padding: 1rem;
45
- border-radius: 10px;
46
- margin: 0.5rem 0;
47
- border-left: 4px solid #FF6B35;
48
- background-color: #f8f9fa;
49
- }
50
- .success-box {
51
- background-color: #d4edda;
52
- border: 1px solid #c3e6cb;
53
- color: #155724;
54
- padding: 1rem;
55
- border-radius: 5px;
56
- margin: 1rem 0;
57
- }
58
- .login-container {
59
- max-width: 400px;
60
- margin: 2rem auto;
61
- padding: 2rem;
62
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
63
- border-radius: 15px;
64
- color: white;
65
- }
66
- .login-header {
67
- text-align: center;
68
- font-size: 2rem;
69
- font-weight: bold;
70
- margin-bottom: 2rem;
71
- color: white;
72
- }
73
- </style>
74
- """, unsafe_allow_html=True)
75
 
76
- def init_database():
77
- """Initialize in-memory database if it doesn't exist"""
78
- if 'users_db' not in st.session_state:
79
- st.session_state.users_db = {}
80
 
81
- # Authentication functions
82
- def hash_password(password: str) -> str:
83
- """Hash a password using SHA-256"""
84
- return hashlib.sha256(password.encode()).hexdigest()
85
 
86
- def load_users() -> Dict[str, Dict]:
87
- """Load users from in-memory database"""
88
- init_database()
89
- return st.session_state.users_db
90
 
91
- def save_users(users: Dict[str, Dict]):
92
- """Save users to in-memory database"""
93
- st.session_state.users_db = users
94
 
95
- def create_user(username: str, password: str, name: str = "") -> bool:
96
- """Create a new user account"""
97
- users = load_users()
98
-
99
- if username in users:
100
- return False # User already exists
101
-
102
- users[username] = {
103
- 'password_hash': hash_password(password),
104
- 'name': name,
105
- 'created_at': datetime.now().isoformat(),
106
- 'profile': {},
107
- 'chat_history': [],
108
- 'workout_plan': None,
109
- 'nutrition_plan': None
110
- }
111
- save_users(users)
112
- return True
113
 
114
- def authenticate_user(username: str, password: str) -> bool:
115
- """Authenticate user credentials"""
116
- users = load_users()
117
 
118
- if username not in users:
119
- return False
120
 
121
- return users[username]['password_hash'] == hash_password(password)
122
 
123
- def get_user_data(username: str) -> Dict:
124
- """Get user's stored data"""
125
- users = load_users()
126
- return users.get(username, {})
127
 
128
- def save_user_data(username: str, user_data: Dict):
129
- """Save user's data"""
130
- users = load_users()
131
- if username in users:
132
- users[username].update(user_data)
133
- save_users(users)
134
 
135
- # Initialize session state
136
- def init_session_state():
137
- """Initialize all session state variables"""
138
- init_database() # Initialize the in-memory database
139
-
140
- if 'authenticated' not in st.session_state:
141
- st.session_state.authenticated = False
142
- if 'username' not in st.session_state:
143
- st.session_state.username = ""
144
- if 'user_profile' not in st.session_state:
145
- st.session_state.user_profile = {}
146
- if 'chat_history' not in st.session_state:
147
- st.session_state.chat_history = []
148
- if 'workout_plan' not in st.session_state:
149
- st.session_state.workout_plan = None
150
- if 'nutrition_plan' not in st.session_state:
151
- st.session_state.nutrition_plan = None
152
- if 'profile_submitted' not in st.session_state:
153
- st.session_state.profile_submitted = False
154
- if 'current_session_id' not in st.session_state:
155
- st.session_state.current_session_id = None
156
 
157
- def load_user_session(username: str):
158
- """Load user's session data"""
159
- user_data = get_user_data(username)
160
-
161
- st.session_state.user_profile = user_data.get('profile', {})
162
- st.session_state.chat_history = user_data.get('chat_history', [])
163
- st.session_state.workout_plan = user_data.get('workout_plan', None)
164
- st.session_state.nutrition_plan = user_data.get('nutrition_plan', None)
165
- st.session_state.profile_submitted = bool(st.session_state.user_profile)
166
 
167
- def save_user_session(username: str):
168
- """Save current session data to user's account"""
169
- user_data = {
170
- 'profile': st.session_state.user_profile,
171
- 'chat_history': st.session_state.chat_history,
172
- 'workout_plan': st.session_state.workout_plan,
173
- 'nutrition_plan': st.session_state.nutrition_plan,
174
- 'last_updated': datetime.now().isoformat()
175
- }
176
- save_user_data(username, user_data)
177
 
178
- def login_page():
179
- """Display login/registration page"""
180
- st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
181
 
182
- # Create tabs for login and registration
183
- tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Register"])
184
 
185
- with tab1:
186
- st.markdown('<div class="login-header">Welcome!</div>', unsafe_allow_html=True)
187
 
188
- with st.form("login_form"):
189
- username = st.text_input("Username", placeholder="Enter your username")
190
- password = st.text_input("Password", type="password", placeholder="Enter your password")
191
 
192
- col1, col2 = st.columns([1, 2])
193
- with col1:
194
- login_button = st.form_submit_button("Login", type="primary", use_container_width=True)
195
 
196
- if login_button:
197
- if username and password:
198
- if authenticate_user(username, password):
199
- st.session_state.authenticated = True
200
- st.session_state.username = username
201
- load_user_session(username)
202
- st.success("βœ… Login successful!")
203
- st.rerun()
204
- else:
205
- st.error("❌ Invalid username or password!")
206
- else:
207
- st.warning("⚠️ Please enter both username and password!")
208
-
209
- st.markdown('</div>', unsafe_allow_html=True)
210
-
211
- with tab2:
212
- st.markdown('<div class="login-header">Create Account</div>', unsafe_allow_html=True)
213
-
214
- with st.form("register_form"):
215
- name = st.text_input("Name", placeholder="Enter your name")
216
- new_username = st.text_input("Choose Username", placeholder="Enter a unique username")
217
- new_password = st.text_input("Password", type="password", placeholder="Choose a strong password")
218
- confirm_password = st.text_input("Confirm Password", type="password", placeholder="Confirm your password")
219
 
220
- col1, col2 = st.columns([1, 2])
221
- with col1:
222
- register_button = st.form_submit_button("Register", type="primary", use_container_width=True)
223
 
224
- if register_button:
225
- if not name.strip():
226
- st.error("❌ Name is mandatory!")
227
- if new_username and new_password and confirm_password:
228
- if new_password != confirm_password:
229
- st.error("❌ Passwords do not match!")
230
- elif len(new_password) < 6:
231
- st.error("❌ Password must be at least 6 characters long!")
232
- elif len(new_username) < 3:
233
- st.error("❌ Username must be at least 3 characters long!")
234
- else:
235
- if create_user(new_username, new_password, name):
236
- st.success("βœ… Account created successfully! Please login.")
237
- st.balloons()
238
- else:
239
- st.error("❌ Username already exists! Please choose a different username.")
240
- else:
241
- st.warning("⚠️ Please fill in all required fields!")
242
-
243
- st.markdown('</div>', unsafe_allow_html=True)
244
 
245
- def call_backend_service(request_type: str, user_profile: Dict[str, Any], additional_message: str = "") -> Dict[str, Any]:
246
- """Call the backend LangChain service using generateResponse method"""
247
- try:
248
- # Generate session_id based on user profile (you can modify this logic)
249
- import hashlib
250
- profile_hash = hashlib.md5(str(user_profile.get('timestamp', 'default')).encode()).hexdigest()[:8]
251
- session_id = f"user_{profile_hash}"
252
 
253
- # Format the user prompt based on request type
254
- profile_prompt = create_user_profile_prompt(user_profile)
255
 
256
- if request_type == 'workout':
257
- user_prompt = create_workout_type_prompt(profile_prompt)
258
 
259
- elif request_type == 'nutrition':
260
- user_prompt = create_nutrition_type_prompt(profile_prompt)
261
 
262
- elif request_type == 'chat':
263
- user_prompt = create_conversation_chat_prompt(profile_prompt, additional_message)
264
 
265
- else:
266
- user_prompt = additional_message
267
 
268
- response = generate_ai_response(user_prompt, session_id)
269
-
270
- if response:
271
- return {
272
- 'response': str(response),
273
- 'session_id': session_id
274
- }
275
- else:
276
- return {'error': f'Backend error: {response.status_code} - {response.text}'}
277
 
278
- except Exception as e:
279
- return {'error': f'Unexpected error: {str(e)}'}
280
 
281
- def collect_user_profile():
282
- """Collect user profile information"""
283
- st.markdown('<div class="section-header">πŸ‘€ User Profile Information</div>', unsafe_allow_html=True)
284
 
285
- # Get the user's name from the database
286
- user_data = get_user_data(st.session_state.username)
287
- user_name = user_data.get('name', '')
288
 
289
- col1, col2 = st.columns(2)
290
-
291
- with col1:
292
- age = st.number_input("Age", min_value=13, max_value=100, value=25)
293
- weight = st.number_input("Weight (kg)", min_value=30.0, max_value=300.0, value=70.0, step=0.1)
294
- height = st.number_input("Height (cm)", min_value=100.0, max_value=250.0, value=170.0, step=0.1)
295
- gender = st.selectbox("Gender", ["Male", "Female", "Other", "Prefer not to say"])
296
-
297
- with col2:
298
- workout_preference = st.multiselect(
299
- "Workout Preferences",
300
- ["Cardio", "Strength Training", "Yoga", "Pilates", "HIIT", "CrossFit", "Swimming", "Running", "Cycling", "Dancing"],
301
- default=["Cardio", "Strength Training"]
302
- )
303
-
304
- workout_time = st.selectbox(
305
- "Preferred Workout Duration",
306
- ["15-30 minutes", "30-45 minutes", "45-60 minutes", "60-90 minutes", "90+ minutes"]
307
- )
308
-
309
- fitness_level = st.selectbox(
310
- "Current Fitness Level",
311
- ["Beginner", "Intermediate", "Advanced"]
312
- )
313
-
314
- fitness_goal = st.selectbox(
315
- "Primary Fitness Goal",
316
- ["Weight Loss", "Muscle Gain", "Endurance", "Strength", "Flexibility", "General Health"]
317
- )
318
-
319
- st.markdown('<div class="section-header">πŸ“… Weekly Schedule</div>', unsafe_allow_html=True)
320
-
321
- days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
322
- schedule = {}
323
-
324
- cols = st.columns(7)
325
- for i, day in enumerate(days_of_week):
326
- with cols[i]:
327
- available = st.checkbox(f"{day[:3]}", key=f"day_{i}")
328
- if available:
329
- time_slot = st.selectbox(
330
- "Time",
331
- ["Morning (6-10 AM)", "Afternoon (12-4 PM)", "Evening (5-8 PM)", "Night (8-10 PM)"],
332
- key=f"time_{i}"
333
- )
334
- schedule[day] = time_slot
335
- else:
336
- schedule[day] = "Not Available"
337
-
338
- st.markdown('<div class="section-header">🍽️ Dietary Preferences & Health</div>', unsafe_allow_html=True)
339
-
340
- col1, col2 = st.columns(2)
341
-
342
- with col1:
343
- food_preferences = st.multiselect(
344
- "Dietary Preferences",
345
- ["Vegetarian", "Vegan", "Pescatarian", "Keto", "Paleo", "Mediterranean", "Low-carb", "High-protein", "Gluten-free", "No restrictions"],
346
- default=["No restrictions"]
347
- )
348
-
349
- allergies = st.text_area("Food Allergies/Intolerances", placeholder="e.g., nuts, dairy, shellfish")
350
-
351
- with col2:
352
- health_issues = st.text_area(
353
- "Health Issues/Medical Conditions",
354
- placeholder="e.g., diabetes, hypertension, joint problems, injuries"
355
- )
356
-
357
- medications = st.text_area("Current Medications", placeholder="List any medications that might affect exercise or diet")
358
-
359
- # Water intake and sleep
360
- col1, col2 = st.columns(2)
361
- with col1:
362
- water_intake = st.slider("Daily Water Intake (glasses)", 1, 15, 8)
363
- with col2:
364
- sleep_hours = st.slider("Average Sleep Hours", 4, 12, 7)
365
-
366
- user_profile = {
367
- 'name': user_name,
368
- 'age': age,
369
- 'weight': weight,
370
- 'height': height,
371
- 'gender': gender,
372
- 'workout_preference': workout_preference,
373
- 'workout_time': workout_time,
374
- 'fitness_level': fitness_level,
375
- 'fitness_goal': fitness_goal,
376
- 'schedule': schedule,
377
- 'food_preferences': food_preferences,
378
- 'allergies': allergies,
379
- 'health_issues': health_issues,
380
- 'medications': medications,
381
- 'water_intake': water_intake,
382
- 'sleep_hours': sleep_hours,
383
- 'timestamp': datetime.now().isoformat()
384
- }
385
-
386
- return user_profile
387
 
388
- def display_profile_summary():
389
- """Display user profile summary"""
390
- if st.session_state.user_profile:
391
- profile = st.session_state.user_profile
392
 
393
- st.markdown('<div class="section-header">πŸ“‹ Profile Summary</div>', unsafe_allow_html=True)
394
 
395
- # Calculate BMI
396
- height_m = profile['height'] / 100
397
- bmi = profile['weight'] / (height_m ** 2)
398
 
399
- col1, col2, col3, col4 = st.columns(4)
400
 
401
- with col1:
402
- st.metric("Age", f"{profile['age']} years")
403
- st.metric("Weight", f"{profile['weight']} kg")
404
 
405
- with col2:
406
- st.metric("Height", f"{profile['height']} cm")
407
- st.metric("BMI", f"{bmi:.1f}")
408
 
409
- with col3:
410
- st.metric("Fitness Level", profile['fitness_level'])
411
- st.metric("Primary Goal", profile['fitness_goal'])
412
 
413
- with col4:
414
- available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
415
- st.metric("Available Days", f"{available_days}/7")
416
- st.metric("Water Intake", f"{profile['water_intake']} glasses/day")
417
 
418
- def generate_plans():
419
- """Generate workout and nutrition plans"""
420
- if not st.session_state.user_profile:
421
- st.error("Please complete your profile first!")
422
- return
423
-
424
- col1, col2 = st.columns(2)
425
-
426
- with col1:
427
- if st.button("πŸ‹οΈ Generate Workout Plan", type="primary", use_container_width=True):
428
- with st.spinner("Creating your personalized workout plan..."):
429
- response = call_backend_service('workout', st.session_state.user_profile)
430
 
431
- if 'error' in response:
432
- st.error(f"Error generating workout plan: {response['error']}")
433
- else:
434
- st.session_state.workout_plan = response
435
- st.session_state.current_session_id = response.get('session_id')
436
- # Add to chat history
437
- st.session_state.chat_history.append({
438
- 'type': 'workout_request',
439
- 'user_profile': st.session_state.user_profile,
440
- 'response': response,
441
- 'session_id': response.get('session_id'),
442
- 'timestamp': datetime.now().isoformat()
443
- })
444
- # Save to user account
445
- save_user_session(st.session_state.username)
446
- st.success("βœ… Workout plan generated successfully!")
447
- st.rerun()
448
-
449
- with col2:
450
- if st.button("πŸ₯— Generate Nutrition Plan", type="primary", use_container_width=True):
451
- with st.spinner("Creating your personalized nutrition plan..."):
452
- response = call_backend_service('nutrition', st.session_state.user_profile)
453
 
454
- if 'error' in response:
455
- st.error(f"Error generating nutrition plan: {response['error']}")
456
- else:
457
- st.session_state.nutrition_plan = response
458
- st.session_state.current_session_id = response.get('session_id')
459
- # Add to chat history
460
- st.session_state.chat_history.append({
461
- 'type': 'nutrition_request',
462
- 'user_profile': st.session_state.user_profile,
463
- 'response': response,
464
- 'session_id': response.get('session_id'),
465
- 'timestamp': datetime.now().isoformat()
466
- })
467
- # Save to user account
468
- save_user_session(st.session_state.username)
469
- st.success("βœ… Nutrition plan generated successfully!")
470
- st.rerun()
471
 
472
- def display_workout_plan():
473
- """Display the generated workout plan"""
474
- if st.session_state.workout_plan:
475
- st.markdown('<div class="section-header">πŸ‹οΈ Your Workout Plan</div>', unsafe_allow_html=True)
476
-
477
- # Display the response content
478
- workout_data = st.session_state.workout_plan
479
-
480
- if isinstance(workout_data, dict) and 'response' in workout_data:
481
- st.markdown(workout_data['response'])
482
- elif isinstance(workout_data, dict) and 'content' in workout_data:
483
- st.markdown(workout_data['content'])
484
- else:
485
- st.markdown(str(workout_data))
486
-
487
- # Download option
488
- col1, col2 = st.columns([1, 4])
489
- with col1:
490
- download_content = workout_data.get('response', workout_data.get('content', str(workout_data)))
491
- st.download_button(
492
- "πŸ“₯ Download Plan",
493
- data=download_content,
494
- file_name=f"workout_plan_{datetime.now().strftime('%Y%m%d')}.txt",
495
- mime="text/plain"
496
- )
497
 
498
- def display_nutrition_plan():
499
- """Display the generated nutrition plan"""
500
- if st.session_state.nutrition_plan:
501
- st.markdown('<div class="section-header">πŸ₯— Your Nutrition Plan</div>', unsafe_allow_html=True)
502
-
503
- # Display the response content
504
- nutrition_data = st.session_state.nutrition_plan
505
-
506
- if isinstance(nutrition_data, dict) and 'response' in nutrition_data:
507
- st.markdown(nutrition_data['response'])
508
- elif isinstance(nutrition_data, dict) and 'content' in nutrition_data:
509
- st.markdown(nutrition_data['content'])
510
- else:
511
- st.markdown(str(nutrition_data))
512
-
513
- # Download option
514
- col1, col2 = st.columns([1, 4])
515
- with col1:
516
- download_content = nutrition_data.get('response', nutrition_data.get('content', str(nutrition_data)))
517
- st.download_button(
518
- "πŸ“₯ Download Plan",
519
- data=download_content,
520
- file_name=f"nutrition_plan_{datetime.now().strftime('%Y%m%d')}.txt",
521
- mime="text/plain"
522
- )
523
 
524
- def chat_interface():
525
- """Chat interface for follow-up questions"""
526
- st.markdown('<div class="section-header">πŸ’¬ Chat with Your AI Coach</div>', unsafe_allow_html=True)
527
-
528
- # Display chat history
529
- for i, message in enumerate(st.session_state.chat_history):
530
- if message['type'] in ['user_message', 'assistant_message']:
531
- with st.chat_message(message['type'].replace('_message', '')):
532
- st.write(message['content'])
533
-
534
- # Chat input
535
- if prompt := st.chat_input("Ask questions about your workout or nutrition plan..."):
536
- # Add user message to chat
537
- st.session_state.chat_history.append({
538
- 'type': 'user_message',
539
- 'content': prompt,
540
- 'timestamp': datetime.now().isoformat()
541
- })
542
-
543
- with st.chat_message("user"):
544
- st.write(prompt)
545
-
546
- # Get response from backend
547
- with st.chat_message("assistant"):
548
- with st.spinner("Thinking..."):
549
- response = call_backend_service('chat', st.session_state.user_profile, prompt)
550
 
551
- if 'error' in response:
552
- assistant_response = f"I apologize, but I encountered an error: {response['error']}. Please try again."
553
- else:
554
- assistant_response = response.get('response', 'I apologize, but I couldn\'t process your request.')
555
 
556
- st.write(assistant_response)
557
 
558
- # Add assistant response to chat history
559
- st.session_state.chat_history.append({
560
- 'type': 'assistant_message',
561
- 'content': assistant_response,
562
- 'session_id': response.get('session_id'),
563
- 'timestamp': datetime.now().isoformat()
564
- })
565
 
566
- # Save to user account
567
- save_user_session(st.session_state.username)
568
 
569
- def sidebar_navigation():
570
- """Sidebar navigation and settings"""
571
- with st.sidebar:
572
- st.markdown("### πŸƒβ€β™€οΈ AI Fitness Coach")
573
-
574
- # User info and logout
575
- if st.session_state.authenticated:
576
- user_name = st.session_state.username
577
- # if users[user_name]['name']:
578
- # user_name = st.session_state.user_profile['name']
579
- st.markdown(f"**πŸ‘€ Welcome, {user_name}!**")
580
- if st.button("πŸšͺ Logout", type="secondary", use_container_width=True):
581
- # Save session before logout
582
- save_user_session(st.session_state.username)
583
 
584
- # Clear session
585
- st.session_state.authenticated = False
586
- st.session_state.username = ""
587
- st.session_state.user_profile = {}
588
- st.session_state.chat_history = []
589
- st.session_state.workout_plan = None
590
- st.session_state.nutrition_plan = None
591
- st.session_state.profile_submitted = False
592
- st.session_state.current_session_id = None
593
- st.rerun()
594
-
595
- st.markdown("---")
596
-
597
- # Navigation
598
- page = st.radio(
599
- "Navigation",
600
- ["πŸ‘€ Profile Setup", "πŸ“Š Dashboard", "πŸ’¬ Chat Coach", "βš™οΈ Settings"]
601
- )
602
 
603
- # Quick stats if profile exists
604
- if st.session_state.user_profile:
605
- st.markdown("### πŸ“ˆ Quick Stats")
606
- profile = st.session_state.user_profile
607
- # BMI calculation
608
- height_m = profile['height'] / 100
609
- bmi = profile['weight'] / (height_m ** 2)
610
 
611
- if bmi < 18.5:
612
- bmi_status = "Underweight"
613
- bmi_color = "blue"
614
- elif bmi < 25:
615
- bmi_status = "Normal"
616
- bmi_color = "green"
617
- elif bmi < 30:
618
- bmi_status = "Overweight"
619
- bmi_color = "orange"
620
- else:
621
- bmi_status = "Obese"
622
- bmi_color = "red"
623
 
624
- st.markdown(f"**BMI:** <span style='color:{bmi_color}'>{bmi:.1f} ({bmi_status})</span>", unsafe_allow_html=True)
625
- st.markdown(f"**Goal:** {profile['fitness_goal']}")
626
- st.markdown(f"**Level:** {profile['fitness_level']}")
627
 
628
- available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
629
- st.markdown(f"**Available Days:** {available_days}/7")
630
 
631
- # Show current session ID if available
632
- if st.session_state.current_session_id:
633
- st.markdown(f"**Session:** {st.session_state.current_session_id}")
634
 
635
- st.markdown("---")
636
- st.markdown(
637
- "<div style='text-align: left; color: #888; font-size: 1em; margin-top: 2rem;'>"
638
- "Created by Sayon"
639
- "</div>",
640
- unsafe_allow_html=True
641
- )
642
- return page
643
 
644
- def main():
645
- """Main application function"""
646
- init_session_state()
647
-
648
- # Check authentication
649
- if not st.session_state.authenticated:
650
- login_page()
651
- return
652
-
653
- # Header
654
- st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
655
- st.markdown("*Your personalized fitness and nutrition companion powered by AI*")
656
- st.markdown("---")
657
-
658
- # Sidebar navigation
659
- current_page = sidebar_navigation()
660
-
661
- if current_page == "πŸ‘€ Profile Setup":
662
- user_profile = collect_user_profile()
663
-
664
- st.markdown("---")
665
-
666
- if st.button("πŸ’Ύ Save Profile & Continue", type="primary", use_container_width=True):
667
- st.session_state.user_profile = user_profile
668
- st.session_state.profile_submitted = True
669
- # Save to user account
670
- save_user_session(st.session_state.username)
671
- st.success("βœ… Profile saved successfully!")
672
- st.balloons()
673
- st.rerun()
674
-
675
- elif current_page == "πŸ“Š Dashboard":
676
- if not st.session_state.user_profile:
677
- st.warning("⚠️ Please complete your profile setup first!")
678
- if st.button("Go to Profile Setup"):
679
- st.rerun()
680
- else:
681
- display_profile_summary()
682
- st.markdown("---")
683
- generate_plans()
684
 
685
- col1, col2 = st.columns(2)
686
- with col1:
687
- display_workout_plan()
688
- with col2:
689
- display_nutrition_plan()
690
-
691
- elif current_page == "πŸ’¬ Chat Coach":
692
- if not st.session_state.user_profile:
693
- st.warning("⚠️ Please complete your profile setup first!")
694
- else:
695
- chat_interface()
696
-
697
- elif current_page == "βš™οΈ Settings":
698
- st.markdown('<div class="section-header">βš™οΈ Application Settings</div>', unsafe_allow_html=True)
699
-
700
- # Account Information
701
- st.subheader("πŸ‘€ Account Information")
702
- user_data = get_user_data(st.session_state.username)
703
-
704
- col1, col2 = st.columns(2)
705
- with col1:
706
- st.info(f"**Username:** {st.session_state.username}")
707
- st.info(f"**Account Created:** {user_data.get('created_at', 'Unknown')[:10]}")
708
- with col2:
709
- st.info(f"**Name:** {user_data.get('name', 'Not provided')}")
710
- if user_data.get('last_updated'):
711
- st.info(f"**Last Updated:** {user_data.get('last_updated')[:10]}")
712
 
713
- # Danger Zone
714
- st.subheader("🚨 Danger Zone")
715
- with st.expander("Delete Account"):
716
- st.error("⚠️ **Warning**: This action cannot be undone!")
717
- st.write("This will permanently delete your account and all associated data.")
718
 
719
- confirm_delete = st.text_input("Type 'DELETE' to confirm account deletion:")
720
 
721
- if st.button("πŸ—‘οΈ Delete Account", type="secondary") and confirm_delete == "DELETE":
722
- # Delete user from users.json
723
- users = load_users()
724
- if st.session_state.username in users:
725
- del users[st.session_state.username]
726
- save_users(users)
727
 
728
- # Clear session and logout
729
- st.session_state.authenticated = False
730
- st.session_state.username = ""
731
- st.session_state.user_profile = {}
732
- st.session_state.chat_history = []
733
- st.session_state.workout_plan = None
734
- st.session_state.nutrition_plan = None
735
- st.session_state.profile_submitted = False
736
- st.session_state.current_session_id = None
737
 
738
- st.success("Account deleted successfully. You will be redirected to the login page.")
739
- st.rerun()
740
 
741
- if __name__ == "__main__":
742
- main()
 
1
+ # import streamlit as st
2
+ # import json
3
+ # from datetime import datetime
4
+ # from typing import Dict, Any, List
5
+ # import pandas as pd
6
+ # import hashlib
7
+ # import os
8
+ # from service import generate_ai_response, create_user_profile_prompt, create_workout_type_prompt, create_nutrition_type_prompt, create_conversation_chat_prompt
9
 
10
+ # # Configure page
11
+ # st.set_page_config(
12
+ # page_title="AI Fitness Coach",
13
+ # page_icon="πŸ’ͺ",
14
+ # layout="wide",
15
+ # initial_sidebar_state="expanded"
16
+ # )
17
 
18
+ # # Custom CSS for better styling
19
+ # st.markdown("""
20
+ # <style>
21
+ # .main-header {
22
+ # font-size: 2.5rem;
23
+ # font-weight: bold;
24
+ # color: #FF6B35;
25
+ # text-align: center;
26
+ # margin-bottom: 2rem;
27
+ # }
28
+ # .section-header {
29
+ # font-size: 1.5rem;
30
+ # font-weight: bold;
31
+ # color: #2E86AB;
32
+ # margin: 1rem 0;
33
+ # border-bottom: 2px solid #2E86AB;
34
+ # padding-bottom: 0.5rem;
35
+ # }
36
+ # .profile-card {
37
+ # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38
+ # padding: 1rem;
39
+ # border-radius: 10px;
40
+ # color: white;
41
+ # margin: 1rem 0;
42
+ # }
43
+ # .chat-message {
44
+ # padding: 1rem;
45
+ # border-radius: 10px;
46
+ # margin: 0.5rem 0;
47
+ # border-left: 4px solid #FF6B35;
48
+ # background-color: #f8f9fa;
49
+ # }
50
+ # .success-box {
51
+ # background-color: #d4edda;
52
+ # border: 1px solid #c3e6cb;
53
+ # color: #155724;
54
+ # padding: 1rem;
55
+ # border-radius: 5px;
56
+ # margin: 1rem 0;
57
+ # }
58
+ # .login-container {
59
+ # max-width: 400px;
60
+ # margin: 2rem auto;
61
+ # padding: 2rem;
62
+ # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
63
+ # border-radius: 15px;
64
+ # color: white;
65
+ # }
66
+ # .login-header {
67
+ # text-align: center;
68
+ # font-size: 2rem;
69
+ # font-weight: bold;
70
+ # margin-bottom: 2rem;
71
+ # color: white;
72
+ # }
73
+ # </style>
74
+ # """, unsafe_allow_html=True)
75
 
76
+ # def init_database():
77
+ # """Initialize in-memory database if it doesn't exist"""
78
+ # if 'users_db' not in st.session_state:
79
+ # st.session_state.users_db = {}
80
 
81
+ # # Authentication functions
82
+ # def hash_password(password: str) -> str:
83
+ # """Hash a password using SHA-256"""
84
+ # return hashlib.sha256(password.encode()).hexdigest()
85
 
86
+ # def load_users() -> Dict[str, Dict]:
87
+ # """Load users from in-memory database"""
88
+ # init_database()
89
+ # return st.session_state.users_db
90
 
91
+ # def save_users(users: Dict[str, Dict]):
92
+ # """Save users to in-memory database"""
93
+ # st.session_state.users_db = users
94
 
95
+ # def create_user(username: str, password: str, name: str = "") -> bool:
96
+ # """Create a new user account"""
97
+ # users = load_users()
98
+
99
+ # if username in users:
100
+ # return False # User already exists
101
+
102
+ # users[username] = {
103
+ # 'password_hash': hash_password(password),
104
+ # 'name': name,
105
+ # 'created_at': datetime.now().isoformat(),
106
+ # 'profile': {},
107
+ # 'chat_history': [],
108
+ # 'workout_plan': None,
109
+ # 'nutrition_plan': None
110
+ # }
111
+ # save_users(users)
112
+ # return True
113
 
114
+ # def authenticate_user(username: str, password: str) -> bool:
115
+ # """Authenticate user credentials"""
116
+ # users = load_users()
117
 
118
+ # if username not in users:
119
+ # return False
120
 
121
+ # return users[username]['password_hash'] == hash_password(password)
122
 
123
+ # def get_user_data(username: str) -> Dict:
124
+ # """Get user's stored data"""
125
+ # users = load_users()
126
+ # return users.get(username, {})
127
 
128
+ # def save_user_data(username: str, user_data: Dict):
129
+ # """Save user's data"""
130
+ # users = load_users()
131
+ # if username in users:
132
+ # users[username].update(user_data)
133
+ # save_users(users)
134
 
135
+ # # Initialize session state
136
+ # def init_session_state():
137
+ # """Initialize all session state variables"""
138
+ # init_database() # Initialize the in-memory database
139
+
140
+ # if 'authenticated' not in st.session_state:
141
+ # st.session_state.authenticated = False
142
+ # if 'username' not in st.session_state:
143
+ # st.session_state.username = ""
144
+ # if 'user_profile' not in st.session_state:
145
+ # st.session_state.user_profile = {}
146
+ # if 'chat_history' not in st.session_state:
147
+ # st.session_state.chat_history = []
148
+ # if 'workout_plan' not in st.session_state:
149
+ # st.session_state.workout_plan = None
150
+ # if 'nutrition_plan' not in st.session_state:
151
+ # st.session_state.nutrition_plan = None
152
+ # if 'profile_submitted' not in st.session_state:
153
+ # st.session_state.profile_submitted = False
154
+ # if 'current_session_id' not in st.session_state:
155
+ # st.session_state.current_session_id = None
156
 
157
+ # def load_user_session(username: str):
158
+ # """Load user's session data"""
159
+ # user_data = get_user_data(username)
160
+
161
+ # st.session_state.user_profile = user_data.get('profile', {})
162
+ # st.session_state.chat_history = user_data.get('chat_history', [])
163
+ # st.session_state.workout_plan = user_data.get('workout_plan', None)
164
+ # st.session_state.nutrition_plan = user_data.get('nutrition_plan', None)
165
+ # st.session_state.profile_submitted = bool(st.session_state.user_profile)
166
 
167
+ # def save_user_session(username: str):
168
+ # """Save current session data to user's account"""
169
+ # user_data = {
170
+ # 'profile': st.session_state.user_profile,
171
+ # 'chat_history': st.session_state.chat_history,
172
+ # 'workout_plan': st.session_state.workout_plan,
173
+ # 'nutrition_plan': st.session_state.nutrition_plan,
174
+ # 'last_updated': datetime.now().isoformat()
175
+ # }
176
+ # save_user_data(username, user_data)
177
 
178
+ # def login_page():
179
+ # """Display login/registration page"""
180
+ # st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
181
 
182
+ # # Create tabs for login and registration
183
+ # tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Register"])
184
 
185
+ # with tab1:
186
+ # st.markdown('<div class="login-header">Welcome!</div>', unsafe_allow_html=True)
187
 
188
+ # with st.form("login_form"):
189
+ # username = st.text_input("Username", placeholder="Enter your username")
190
+ # password = st.text_input("Password", type="password", placeholder="Enter your password")
191
 
192
+ # col1, col2 = st.columns([1, 2])
193
+ # with col1:
194
+ # login_button = st.form_submit_button("Login", type="primary", use_container_width=True)
195
 
196
+ # if login_button:
197
+ # if username and password:
198
+ # if authenticate_user(username, password):
199
+ # st.session_state.authenticated = True
200
+ # st.session_state.username = username
201
+ # load_user_session(username)
202
+ # st.success("βœ… Login successful!")
203
+ # st.rerun()
204
+ # else:
205
+ # st.error("❌ Invalid username or password!")
206
+ # else:
207
+ # st.warning("⚠️ Please enter both username and password!")
208
+
209
+ # st.markdown('</div>', unsafe_allow_html=True)
210
+
211
+ # with tab2:
212
+ # st.markdown('<div class="login-header">Create Account</div>', unsafe_allow_html=True)
213
+
214
+ # with st.form("register_form"):
215
+ # name = st.text_input("Name", placeholder="Enter your name")
216
+ # new_username = st.text_input("Choose Username", placeholder="Enter a unique username")
217
+ # new_password = st.text_input("Password", type="password", placeholder="Choose a strong password")
218
+ # confirm_password = st.text_input("Confirm Password", type="password", placeholder="Confirm your password")
219
 
220
+ # col1, col2 = st.columns([1, 2])
221
+ # with col1:
222
+ # register_button = st.form_submit_button("Register", type="primary", use_container_width=True)
223
 
224
+ # if register_button:
225
+ # if not name.strip():
226
+ # st.error("❌ Name is mandatory!")
227
+ # if new_username and new_password and confirm_password:
228
+ # if new_password != confirm_password:
229
+ # st.error("❌ Passwords do not match!")
230
+ # elif len(new_password) < 6:
231
+ # st.error("❌ Password must be at least 6 characters long!")
232
+ # elif len(new_username) < 3:
233
+ # st.error("❌ Username must be at least 3 characters long!")
234
+ # else:
235
+ # if create_user(new_username, new_password, name):
236
+ # st.success("βœ… Account created successfully! Please login.")
237
+ # st.balloons()
238
+ # else:
239
+ # st.error("❌ Username already exists! Please choose a different username.")
240
+ # else:
241
+ # st.warning("⚠️ Please fill in all required fields!")
242
+
243
+ # st.markdown('</div>', unsafe_allow_html=True)
244
 
245
+ # def call_backend_service(request_type: str, user_profile: Dict[str, Any], additional_message: str = "") -> Dict[str, Any]:
246
+ # """Call the backend LangChain service using generateResponse method"""
247
+ # try:
248
+ # # Generate session_id based on user profile (you can modify this logic)
249
+ # import hashlib
250
+ # profile_hash = hashlib.md5(str(user_profile.get('timestamp', 'default')).encode()).hexdigest()[:8]
251
+ # session_id = f"user_{profile_hash}"
252
 
253
+ # # Format the user prompt based on request type
254
+ # profile_prompt = create_user_profile_prompt(user_profile)
255
 
256
+ # if request_type == 'workout':
257
+ # user_prompt = create_workout_type_prompt(profile_prompt)
258
 
259
+ # elif request_type == 'nutrition':
260
+ # user_prompt = create_nutrition_type_prompt(profile_prompt)
261
 
262
+ # elif request_type == 'chat':
263
+ # user_prompt = create_conversation_chat_prompt(profile_prompt, additional_message)
264
 
265
+ # else:
266
+ # user_prompt = additional_message
267
 
268
+ # response = generate_ai_response(user_prompt, session_id)
269
+
270
+ # if response:
271
+ # return {
272
+ # 'response': str(response),
273
+ # 'session_id': session_id
274
+ # }
275
+ # else:
276
+ # return {'error': f'Backend error: {response.status_code} - {response.text}'}
277
 
278
+ # except Exception as e:
279
+ # return {'error': f'Unexpected error: {str(e)}'}
280
 
281
+ # def collect_user_profile():
282
+ # """Collect user profile information"""
283
+ # st.markdown('<div class="section-header">πŸ‘€ User Profile Information</div>', unsafe_allow_html=True)
284
 
285
+ # # Get the user's name from the database
286
+ # user_data = get_user_data(st.session_state.username)
287
+ # user_name = user_data.get('name', '')
288
 
289
+ # col1, col2 = st.columns(2)
290
+
291
+ # with col1:
292
+ # age = st.number_input("Age", min_value=13, max_value=100, value=25)
293
+ # weight = st.number_input("Weight (kg)", min_value=30.0, max_value=300.0, value=70.0, step=0.1)
294
+ # height = st.number_input("Height (cm)", min_value=100.0, max_value=250.0, value=170.0, step=0.1)
295
+ # gender = st.selectbox("Gender", ["Male", "Female", "Other", "Prefer not to say"])
296
+
297
+ # with col2:
298
+ # workout_preference = st.multiselect(
299
+ # "Workout Preferences",
300
+ # ["Cardio", "Strength Training", "Yoga", "Pilates", "HIIT", "CrossFit", "Swimming", "Running", "Cycling", "Dancing"],
301
+ # default=["Cardio", "Strength Training"]
302
+ # )
303
+
304
+ # workout_time = st.selectbox(
305
+ # "Preferred Workout Duration",
306
+ # ["15-30 minutes", "30-45 minutes", "45-60 minutes", "60-90 minutes", "90+ minutes"]
307
+ # )
308
+
309
+ # fitness_level = st.selectbox(
310
+ # "Current Fitness Level",
311
+ # ["Beginner", "Intermediate", "Advanced"]
312
+ # )
313
+
314
+ # fitness_goal = st.selectbox(
315
+ # "Primary Fitness Goal",
316
+ # ["Weight Loss", "Muscle Gain", "Endurance", "Strength", "Flexibility", "General Health"]
317
+ # )
318
+
319
+ # st.markdown('<div class="section-header">πŸ“… Weekly Schedule</div>', unsafe_allow_html=True)
320
+
321
+ # days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
322
+ # schedule = {}
323
+
324
+ # cols = st.columns(7)
325
+ # for i, day in enumerate(days_of_week):
326
+ # with cols[i]:
327
+ # available = st.checkbox(f"{day[:3]}", key=f"day_{i}")
328
+ # if available:
329
+ # time_slot = st.selectbox(
330
+ # "Time",
331
+ # ["Morning (6-10 AM)", "Afternoon (12-4 PM)", "Evening (5-8 PM)", "Night (8-10 PM)"],
332
+ # key=f"time_{i}"
333
+ # )
334
+ # schedule[day] = time_slot
335
+ # else:
336
+ # schedule[day] = "Not Available"
337
+
338
+ # st.markdown('<div class="section-header">🍽️ Dietary Preferences & Health</div>', unsafe_allow_html=True)
339
+
340
+ # col1, col2 = st.columns(2)
341
+
342
+ # with col1:
343
+ # food_preferences = st.multiselect(
344
+ # "Dietary Preferences",
345
+ # ["Vegetarian", "Vegan", "Pescatarian", "Keto", "Paleo", "Mediterranean", "Low-carb", "High-protein", "Gluten-free", "No restrictions"],
346
+ # default=["No restrictions"]
347
+ # )
348
+
349
+ # allergies = st.text_area("Food Allergies/Intolerances", placeholder="e.g., nuts, dairy, shellfish")
350
+
351
+ # with col2:
352
+ # health_issues = st.text_area(
353
+ # "Health Issues/Medical Conditions",
354
+ # placeholder="e.g., diabetes, hypertension, joint problems, injuries"
355
+ # )
356
+
357
+ # medications = st.text_area("Current Medications", placeholder="List any medications that might affect exercise or diet")
358
+
359
+ # # Water intake and sleep
360
+ # col1, col2 = st.columns(2)
361
+ # with col1:
362
+ # water_intake = st.slider("Daily Water Intake (glasses)", 1, 15, 8)
363
+ # with col2:
364
+ # sleep_hours = st.slider("Average Sleep Hours", 4, 12, 7)
365
+
366
+ # user_profile = {
367
+ # 'name': user_name,
368
+ # 'age': age,
369
+ # 'weight': weight,
370
+ # 'height': height,
371
+ # 'gender': gender,
372
+ # 'workout_preference': workout_preference,
373
+ # 'workout_time': workout_time,
374
+ # 'fitness_level': fitness_level,
375
+ # 'fitness_goal': fitness_goal,
376
+ # 'schedule': schedule,
377
+ # 'food_preferences': food_preferences,
378
+ # 'allergies': allergies,
379
+ # 'health_issues': health_issues,
380
+ # 'medications': medications,
381
+ # 'water_intake': water_intake,
382
+ # 'sleep_hours': sleep_hours,
383
+ # 'timestamp': datetime.now().isoformat()
384
+ # }
385
+
386
+ # return user_profile
387
 
388
+ # def display_profile_summary():
389
+ # """Display user profile summary"""
390
+ # if st.session_state.user_profile:
391
+ # profile = st.session_state.user_profile
392
 
393
+ # st.markdown('<div class="section-header">πŸ“‹ Profile Summary</div>', unsafe_allow_html=True)
394
 
395
+ # # Calculate BMI
396
+ # height_m = profile['height'] / 100
397
+ # bmi = profile['weight'] / (height_m ** 2)
398
 
399
+ # col1, col2, col3, col4 = st.columns(4)
400
 
401
+ # with col1:
402
+ # st.metric("Age", f"{profile['age']} years")
403
+ # st.metric("Weight", f"{profile['weight']} kg")
404
 
405
+ # with col2:
406
+ # st.metric("Height", f"{profile['height']} cm")
407
+ # st.metric("BMI", f"{bmi:.1f}")
408
 
409
+ # with col3:
410
+ # st.metric("Fitness Level", profile['fitness_level'])
411
+ # st.metric("Primary Goal", profile['fitness_goal'])
412
 
413
+ # with col4:
414
+ # available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
415
+ # st.metric("Available Days", f"{available_days}/7")
416
+ # st.metric("Water Intake", f"{profile['water_intake']} glasses/day")
417
 
418
+ # def generate_plans():
419
+ # """Generate workout and nutrition plans"""
420
+ # if not st.session_state.user_profile:
421
+ # st.error("Please complete your profile first!")
422
+ # return
423
+
424
+ # col1, col2 = st.columns(2)
425
+
426
+ # with col1:
427
+ # if st.button("πŸ‹οΈ Generate Workout Plan", type="primary", use_container_width=True):
428
+ # with st.spinner("Creating your personalized workout plan..."):
429
+ # response = call_backend_service('workout', st.session_state.user_profile)
430
 
431
+ # if 'error' in response:
432
+ # st.error(f"Error generating workout plan: {response['error']}")
433
+ # else:
434
+ # st.session_state.workout_plan = response
435
+ # st.session_state.current_session_id = response.get('session_id')
436
+ # # Add to chat history
437
+ # st.session_state.chat_history.append({
438
+ # 'type': 'workout_request',
439
+ # 'user_profile': st.session_state.user_profile,
440
+ # 'response': response,
441
+ # 'session_id': response.get('session_id'),
442
+ # 'timestamp': datetime.now().isoformat()
443
+ # })
444
+ # # Save to user account
445
+ # save_user_session(st.session_state.username)
446
+ # st.success("βœ… Workout plan generated successfully!")
447
+ # st.rerun()
448
+
449
+ # with col2:
450
+ # if st.button("πŸ₯— Generate Nutrition Plan", type="primary", use_container_width=True):
451
+ # with st.spinner("Creating your personalized nutrition plan..."):
452
+ # response = call_backend_service('nutrition', st.session_state.user_profile)
453
 
454
+ # if 'error' in response:
455
+ # st.error(f"Error generating nutrition plan: {response['error']}")
456
+ # else:
457
+ # st.session_state.nutrition_plan = response
458
+ # st.session_state.current_session_id = response.get('session_id')
459
+ # # Add to chat history
460
+ # st.session_state.chat_history.append({
461
+ # 'type': 'nutrition_request',
462
+ # 'user_profile': st.session_state.user_profile,
463
+ # 'response': response,
464
+ # 'session_id': response.get('session_id'),
465
+ # 'timestamp': datetime.now().isoformat()
466
+ # })
467
+ # # Save to user account
468
+ # save_user_session(st.session_state.username)
469
+ # st.success("βœ… Nutrition plan generated successfully!")
470
+ # st.rerun()
471
 
472
+ # def display_workout_plan():
473
+ # """Display the generated workout plan"""
474
+ # if st.session_state.workout_plan:
475
+ # st.markdown('<div class="section-header">πŸ‹οΈ Your Workout Plan</div>', unsafe_allow_html=True)
476
+
477
+ # # Display the response content
478
+ # workout_data = st.session_state.workout_plan
479
+
480
+ # if isinstance(workout_data, dict) and 'response' in workout_data:
481
+ # st.markdown(workout_data['response'])
482
+ # elif isinstance(workout_data, dict) and 'content' in workout_data:
483
+ # st.markdown(workout_data['content'])
484
+ # else:
485
+ # st.markdown(str(workout_data))
486
+
487
+ # # Download option
488
+ # col1, col2 = st.columns([1, 4])
489
+ # with col1:
490
+ # download_content = workout_data.get('response', workout_data.get('content', str(workout_data)))
491
+ # st.download_button(
492
+ # "πŸ“₯ Download Plan",
493
+ # data=download_content,
494
+ # file_name=f"workout_plan_{datetime.now().strftime('%Y%m%d')}.txt",
495
+ # mime="text/plain"
496
+ # )
497
 
498
+ # def display_nutrition_plan():
499
+ # """Display the generated nutrition plan"""
500
+ # if st.session_state.nutrition_plan:
501
+ # st.markdown('<div class="section-header">πŸ₯— Your Nutrition Plan</div>', unsafe_allow_html=True)
502
+
503
+ # # Display the response content
504
+ # nutrition_data = st.session_state.nutrition_plan
505
+
506
+ # if isinstance(nutrition_data, dict) and 'response' in nutrition_data:
507
+ # st.markdown(nutrition_data['response'])
508
+ # elif isinstance(nutrition_data, dict) and 'content' in nutrition_data:
509
+ # st.markdown(nutrition_data['content'])
510
+ # else:
511
+ # st.markdown(str(nutrition_data))
512
+
513
+ # # Download option
514
+ # col1, col2 = st.columns([1, 4])
515
+ # with col1:
516
+ # download_content = nutrition_data.get('response', nutrition_data.get('content', str(nutrition_data)))
517
+ # st.download_button(
518
+ # "πŸ“₯ Download Plan",
519
+ # data=download_content,
520
+ # file_name=f"nutrition_plan_{datetime.now().strftime('%Y%m%d')}.txt",
521
+ # mime="text/plain"
522
+ # )
523
 
524
+ # def chat_interface():
525
+ # """Chat interface for follow-up questions"""
526
+ # st.markdown('<div class="section-header">πŸ’¬ Chat with Your AI Coach</div>', unsafe_allow_html=True)
527
+
528
+ # # Display chat history
529
+ # for i, message in enumerate(st.session_state.chat_history):
530
+ # if message['type'] in ['user_message', 'assistant_message']:
531
+ # with st.chat_message(message['type'].replace('_message', '')):
532
+ # st.write(message['content'])
533
+
534
+ # # Chat input
535
+ # if prompt := st.chat_input("Ask questions about your workout or nutrition plan..."):
536
+ # # Add user message to chat
537
+ # st.session_state.chat_history.append({
538
+ # 'type': 'user_message',
539
+ # 'content': prompt,
540
+ # 'timestamp': datetime.now().isoformat()
541
+ # })
542
+
543
+ # with st.chat_message("user"):
544
+ # st.write(prompt)
545
+
546
+ # # Get response from backend
547
+ # with st.chat_message("assistant"):
548
+ # with st.spinner("Thinking..."):
549
+ # response = call_backend_service('chat', st.session_state.user_profile, prompt)
550
 
551
+ # if 'error' in response:
552
+ # assistant_response = f"I apologize, but I encountered an error: {response['error']}. Please try again."
553
+ # else:
554
+ # assistant_response = response.get('response', 'I apologize, but I couldn\'t process your request.')
555
 
556
+ # st.write(assistant_response)
557
 
558
+ # # Add assistant response to chat history
559
+ # st.session_state.chat_history.append({
560
+ # 'type': 'assistant_message',
561
+ # 'content': assistant_response,
562
+ # 'session_id': response.get('session_id'),
563
+ # 'timestamp': datetime.now().isoformat()
564
+ # })
565
 
566
+ # # Save to user account
567
+ # save_user_session(st.session_state.username)
568
 
569
+ # def sidebar_navigation():
570
+ # """Sidebar navigation and settings"""
571
+ # with st.sidebar:
572
+ # st.markdown("### πŸƒβ€β™€οΈ AI Fitness Coach")
573
+
574
+ # # User info and logout
575
+ # if st.session_state.authenticated:
576
+ # user_name = st.session_state.username
577
+ # # if users[user_name]['name']:
578
+ # # user_name = st.session_state.user_profile['name']
579
+ # st.markdown(f"**πŸ‘€ Welcome, {user_name}!**")
580
+ # if st.button("πŸšͺ Logout", type="secondary", use_container_width=True):
581
+ # # Save session before logout
582
+ # save_user_session(st.session_state.username)
583
 
584
+ # # Clear session
585
+ # st.session_state.authenticated = False
586
+ # st.session_state.username = ""
587
+ # st.session_state.user_profile = {}
588
+ # st.session_state.chat_history = []
589
+ # st.session_state.workout_plan = None
590
+ # st.session_state.nutrition_plan = None
591
+ # st.session_state.profile_submitted = False
592
+ # st.session_state.current_session_id = None
593
+ # st.rerun()
594
+
595
+ # st.markdown("---")
596
+
597
+ # # Navigation
598
+ # page = st.radio(
599
+ # "Navigation",
600
+ # ["πŸ‘€ Profile Setup", "πŸ“Š Dashboard", "πŸ’¬ Chat Coach", "βš™οΈ Settings"]
601
+ # )
602
 
603
+ # # Quick stats if profile exists
604
+ # if st.session_state.user_profile:
605
+ # st.markdown("### πŸ“ˆ Quick Stats")
606
+ # profile = st.session_state.user_profile
607
+ # # BMI calculation
608
+ # height_m = profile['height'] / 100
609
+ # bmi = profile['weight'] / (height_m ** 2)
610
 
611
+ # if bmi < 18.5:
612
+ # bmi_status = "Underweight"
613
+ # bmi_color = "blue"
614
+ # elif bmi < 25:
615
+ # bmi_status = "Normal"
616
+ # bmi_color = "green"
617
+ # elif bmi < 30:
618
+ # bmi_status = "Overweight"
619
+ # bmi_color = "orange"
620
+ # else:
621
+ # bmi_status = "Obese"
622
+ # bmi_color = "red"
623
 
624
+ # st.markdown(f"**BMI:** <span style='color:{bmi_color}'>{bmi:.1f} ({bmi_status})</span>", unsafe_allow_html=True)
625
+ # st.markdown(f"**Goal:** {profile['fitness_goal']}")
626
+ # st.markdown(f"**Level:** {profile['fitness_level']}")
627
 
628
+ # available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
629
+ # st.markdown(f"**Available Days:** {available_days}/7")
630
 
631
+ # # Show current session ID if available
632
+ # if st.session_state.current_session_id:
633
+ # st.markdown(f"**Session:** {st.session_state.current_session_id}")
634
 
635
+ # st.markdown("---")
636
+ # st.markdown(
637
+ # "<div style='text-align: left; color: #888; font-size: 1em; margin-top: 2rem;'>"
638
+ # "Created by Sayon"
639
+ # "</div>",
640
+ # unsafe_allow_html=True
641
+ # )
642
+ # return page
643
 
644
+ # def main():
645
+ # """Main application function"""
646
+ # init_session_state()
647
+
648
+ # # Check authentication
649
+ # if not st.session_state.authenticated:
650
+ # login_page()
651
+ # return
652
+
653
+ # # Header
654
+ # st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
655
+ # st.markdown("*Your personalized fitness and nutrition companion powered by AI*")
656
+ # st.markdown("---")
657
+
658
+ # # Sidebar navigation
659
+ # current_page = sidebar_navigation()
660
+
661
+ # if current_page == "πŸ‘€ Profile Setup":
662
+ # user_profile = collect_user_profile()
663
+
664
+ # st.markdown("---")
665
+
666
+ # if st.button("πŸ’Ύ Save Profile & Continue", type="primary", use_container_width=True):
667
+ # st.session_state.user_profile = user_profile
668
+ # st.session_state.profile_submitted = True
669
+ # # Save to user account
670
+ # save_user_session(st.session_state.username)
671
+ # st.success("βœ… Profile saved successfully!")
672
+ # st.balloons()
673
+ # st.rerun()
674
+
675
+ # elif current_page == "πŸ“Š Dashboard":
676
+ # if not st.session_state.user_profile:
677
+ # st.warning("⚠️ Please complete your profile setup first!")
678
+ # if st.button("Go to Profile Setup"):
679
+ # st.rerun()
680
+ # else:
681
+ # display_profile_summary()
682
+ # st.markdown("---")
683
+ # generate_plans()
684
 
685
+ # col1, col2 = st.columns(2)
686
+ # with col1:
687
+ # display_workout_plan()
688
+ # with col2:
689
+ # display_nutrition_plan()
690
+
691
+ # elif current_page == "πŸ’¬ Chat Coach":
692
+ # if not st.session_state.user_profile:
693
+ # st.warning("⚠️ Please complete your profile setup first!")
694
+ # else:
695
+ # chat_interface()
696
+
697
+ # elif current_page == "βš™οΈ Settings":
698
+ # st.markdown('<div class="section-header">βš™οΈ Application Settings</div>', unsafe_allow_html=True)
699
+
700
+ # # Account Information
701
+ # st.subheader("πŸ‘€ Account Information")
702
+ # user_data = get_user_data(st.session_state.username)
703
+
704
+ # col1, col2 = st.columns(2)
705
+ # with col1:
706
+ # st.info(f"**Username:** {st.session_state.username}")
707
+ # st.info(f"**Account Created:** {user_data.get('created_at', 'Unknown')[:10]}")
708
+ # with col2:
709
+ # st.info(f"**Name:** {user_data.get('name', 'Not provided')}")
710
+ # if user_data.get('last_updated'):
711
+ # st.info(f"**Last Updated:** {user_data.get('last_updated')[:10]}")
712
 
713
+ # # Danger Zone
714
+ # st.subheader("🚨 Danger Zone")
715
+ # with st.expander("Delete Account"):
716
+ # st.error("⚠️ **Warning**: This action cannot be undone!")
717
+ # st.write("This will permanently delete your account and all associated data.")
718
 
719
+ # confirm_delete = st.text_input("Type 'DELETE' to confirm account deletion:")
720
 
721
+ # if st.button("πŸ—‘οΈ Delete Account", type="secondary") and confirm_delete == "DELETE":
722
+ # # Delete user from users.json
723
+ # users = load_users()
724
+ # if st.session_state.username in users:
725
+ # del users[st.session_state.username]
726
+ # save_users(users)
727
 
728
+ # # Clear session and logout
729
+ # st.session_state.authenticated = False
730
+ # st.session_state.username = ""
731
+ # st.session_state.user_profile = {}
732
+ # st.session_state.chat_history = []
733
+ # st.session_state.workout_plan = None
734
+ # st.session_state.nutrition_plan = None
735
+ # st.session_state.profile_submitted = False
736
+ # st.session_state.current_session_id = None
737
 
738
+ # st.success("Account deleted successfully. You will be redirected to the login page.")
739
+ # st.rerun()
740
 
741
+ # if __name__ == "__main__":
742
+ # main()
src/streamlit_app.py CHANGED
@@ -1,12 +1,742 @@
1
  import streamlit as st
2
- import service as service
 
 
 
 
 
 
3
 
4
- st.title("Sayon Fitness QA BOT")
 
 
 
 
 
 
5
 
6
- session_id = st.text_input("Enter session_id")
7
- if session_id:
8
- user_q = st.chat_input("Enter Question")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- if user_q:
11
- response = service.generateResponse(user_q, session_id)
12
- st.write(response)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import json
3
+ from datetime import datetime
4
+ from typing import Dict, Any, List
5
+ import pandas as pd
6
+ import hashlib
7
+ import os
8
+ from service import generate_ai_response, create_user_profile_prompt, create_workout_type_prompt, create_nutrition_type_prompt, create_conversation_chat_prompt
9
 
10
+ # Configure page
11
+ st.set_page_config(
12
+ page_title="AI Fitness Coach",
13
+ page_icon="πŸ’ͺ",
14
+ layout="wide",
15
+ initial_sidebar_state="expanded"
16
+ )
17
 
18
+ # Custom CSS for better styling
19
+ st.markdown("""
20
+ <style>
21
+ .main-header {
22
+ font-size: 2.5rem;
23
+ font-weight: bold;
24
+ color: #FF6B35;
25
+ text-align: center;
26
+ margin-bottom: 2rem;
27
+ }
28
+ .section-header {
29
+ font-size: 1.5rem;
30
+ font-weight: bold;
31
+ color: #2E86AB;
32
+ margin: 1rem 0;
33
+ border-bottom: 2px solid #2E86AB;
34
+ padding-bottom: 0.5rem;
35
+ }
36
+ .profile-card {
37
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
38
+ padding: 1rem;
39
+ border-radius: 10px;
40
+ color: white;
41
+ margin: 1rem 0;
42
+ }
43
+ .chat-message {
44
+ padding: 1rem;
45
+ border-radius: 10px;
46
+ margin: 0.5rem 0;
47
+ border-left: 4px solid #FF6B35;
48
+ background-color: #f8f9fa;
49
+ }
50
+ .success-box {
51
+ background-color: #d4edda;
52
+ border: 1px solid #c3e6cb;
53
+ color: #155724;
54
+ padding: 1rem;
55
+ border-radius: 5px;
56
+ margin: 1rem 0;
57
+ }
58
+ .login-container {
59
+ max-width: 400px;
60
+ margin: 2rem auto;
61
+ padding: 2rem;
62
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
63
+ border-radius: 15px;
64
+ color: white;
65
+ }
66
+ .login-header {
67
+ text-align: center;
68
+ font-size: 2rem;
69
+ font-weight: bold;
70
+ margin-bottom: 2rem;
71
+ color: white;
72
+ }
73
+ </style>
74
+ """, unsafe_allow_html=True)
75
 
76
+ def init_database():
77
+ """Initialize in-memory database if it doesn't exist"""
78
+ if 'users_db' not in st.session_state:
79
+ st.session_state.users_db = {}
80
+
81
+ # Authentication functions
82
+ def hash_password(password: str) -> str:
83
+ """Hash a password using SHA-256"""
84
+ return hashlib.sha256(password.encode()).hexdigest()
85
+
86
+ def load_users() -> Dict[str, Dict]:
87
+ """Load users from in-memory database"""
88
+ init_database()
89
+ return st.session_state.users_db
90
+
91
+ def save_users(users: Dict[str, Dict]):
92
+ """Save users to in-memory database"""
93
+ st.session_state.users_db = users
94
+
95
+ def create_user(username: str, password: str, name: str = "") -> bool:
96
+ """Create a new user account"""
97
+ users = load_users()
98
+
99
+ if username in users:
100
+ return False # User already exists
101
+
102
+ users[username] = {
103
+ 'password_hash': hash_password(password),
104
+ 'name': name,
105
+ 'created_at': datetime.now().isoformat(),
106
+ 'profile': {},
107
+ 'chat_history': [],
108
+ 'workout_plan': None,
109
+ 'nutrition_plan': None
110
+ }
111
+ save_users(users)
112
+ return True
113
+
114
+ def authenticate_user(username: str, password: str) -> bool:
115
+ """Authenticate user credentials"""
116
+ users = load_users()
117
+
118
+ if username not in users:
119
+ return False
120
+
121
+ return users[username]['password_hash'] == hash_password(password)
122
+
123
+ def get_user_data(username: str) -> Dict:
124
+ """Get user's stored data"""
125
+ users = load_users()
126
+ return users.get(username, {})
127
+
128
+ def save_user_data(username: str, user_data: Dict):
129
+ """Save user's data"""
130
+ users = load_users()
131
+ if username in users:
132
+ users[username].update(user_data)
133
+ save_users(users)
134
+
135
+ # Initialize session state
136
+ def init_session_state():
137
+ """Initialize all session state variables"""
138
+ init_database() # Initialize the in-memory database
139
+
140
+ if 'authenticated' not in st.session_state:
141
+ st.session_state.authenticated = False
142
+ if 'username' not in st.session_state:
143
+ st.session_state.username = ""
144
+ if 'user_profile' not in st.session_state:
145
+ st.session_state.user_profile = {}
146
+ if 'chat_history' not in st.session_state:
147
+ st.session_state.chat_history = []
148
+ if 'workout_plan' not in st.session_state:
149
+ st.session_state.workout_plan = None
150
+ if 'nutrition_plan' not in st.session_state:
151
+ st.session_state.nutrition_plan = None
152
+ if 'profile_submitted' not in st.session_state:
153
+ st.session_state.profile_submitted = False
154
+ if 'current_session_id' not in st.session_state:
155
+ st.session_state.current_session_id = None
156
+
157
+ def load_user_session(username: str):
158
+ """Load user's session data"""
159
+ user_data = get_user_data(username)
160
+
161
+ st.session_state.user_profile = user_data.get('profile', {})
162
+ st.session_state.chat_history = user_data.get('chat_history', [])
163
+ st.session_state.workout_plan = user_data.get('workout_plan', None)
164
+ st.session_state.nutrition_plan = user_data.get('nutrition_plan', None)
165
+ st.session_state.profile_submitted = bool(st.session_state.user_profile)
166
+
167
+ def save_user_session(username: str):
168
+ """Save current session data to user's account"""
169
+ user_data = {
170
+ 'profile': st.session_state.user_profile,
171
+ 'chat_history': st.session_state.chat_history,
172
+ 'workout_plan': st.session_state.workout_plan,
173
+ 'nutrition_plan': st.session_state.nutrition_plan,
174
+ 'last_updated': datetime.now().isoformat()
175
+ }
176
+ save_user_data(username, user_data)
177
+
178
+ def login_page():
179
+ """Display login/registration page"""
180
+ st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
181
+
182
+ # Create tabs for login and registration
183
+ tab1, tab2 = st.tabs(["πŸ” Login", "πŸ“ Register"])
184
+
185
+ with tab1:
186
+ st.markdown('<div class="login-header">Welcome!</div>', unsafe_allow_html=True)
187
+
188
+ with st.form("login_form"):
189
+ username = st.text_input("Username", placeholder="Enter your username")
190
+ password = st.text_input("Password", type="password", placeholder="Enter your password")
191
+
192
+ col1, col2 = st.columns([1, 2])
193
+ with col1:
194
+ login_button = st.form_submit_button("Login", type="primary", use_container_width=True)
195
+
196
+ if login_button:
197
+ if username and password:
198
+ if authenticate_user(username, password):
199
+ st.session_state.authenticated = True
200
+ st.session_state.username = username
201
+ load_user_session(username)
202
+ st.success("βœ… Login successful!")
203
+ st.rerun()
204
+ else:
205
+ st.error("❌ Invalid username or password!")
206
+ else:
207
+ st.warning("⚠️ Please enter both username and password!")
208
+
209
+ st.markdown('</div>', unsafe_allow_html=True)
210
+
211
+ with tab2:
212
+ st.markdown('<div class="login-header">Create Account</div>', unsafe_allow_html=True)
213
+
214
+ with st.form("register_form"):
215
+ name = st.text_input("Name", placeholder="Enter your name")
216
+ new_username = st.text_input("Choose Username", placeholder="Enter a unique username")
217
+ new_password = st.text_input("Password", type="password", placeholder="Choose a strong password")
218
+ confirm_password = st.text_input("Confirm Password", type="password", placeholder="Confirm your password")
219
+
220
+ col1, col2 = st.columns([1, 2])
221
+ with col1:
222
+ register_button = st.form_submit_button("Register", type="primary", use_container_width=True)
223
+
224
+ if register_button:
225
+ if not name.strip():
226
+ st.error("❌ Name is mandatory!")
227
+ if new_username and new_password and confirm_password:
228
+ if new_password != confirm_password:
229
+ st.error("❌ Passwords do not match!")
230
+ elif len(new_password) < 6:
231
+ st.error("❌ Password must be at least 6 characters long!")
232
+ elif len(new_username) < 3:
233
+ st.error("❌ Username must be at least 3 characters long!")
234
+ else:
235
+ if create_user(new_username, new_password, name):
236
+ st.success("βœ… Account created successfully! Please login.")
237
+ st.balloons()
238
+ else:
239
+ st.error("❌ Username already exists! Please choose a different username.")
240
+ else:
241
+ st.warning("⚠️ Please fill in all required fields!")
242
+
243
+ st.markdown('</div>', unsafe_allow_html=True)
244
+
245
+ def call_backend_service(request_type: str, user_profile: Dict[str, Any], additional_message: str = "") -> Dict[str, Any]:
246
+ """Call the backend LangChain service using generateResponse method"""
247
+ try:
248
+ # Generate session_id based on user profile (you can modify this logic)
249
+ import hashlib
250
+ profile_hash = hashlib.md5(str(user_profile.get('timestamp', 'default')).encode()).hexdigest()[:8]
251
+ session_id = f"user_{profile_hash}"
252
+
253
+ # Format the user prompt based on request type
254
+ profile_prompt = create_user_profile_prompt(user_profile)
255
+
256
+ if request_type == 'workout':
257
+ user_prompt = create_workout_type_prompt(profile_prompt)
258
+
259
+ elif request_type == 'nutrition':
260
+ user_prompt = create_nutrition_type_prompt(profile_prompt)
261
+
262
+ elif request_type == 'chat':
263
+ user_prompt = create_conversation_chat_prompt(profile_prompt, additional_message)
264
+
265
+ else:
266
+ user_prompt = additional_message
267
+
268
+ response = generate_ai_response(user_prompt, session_id)
269
+
270
+ if response:
271
+ return {
272
+ 'response': str(response),
273
+ 'session_id': session_id
274
+ }
275
+ else:
276
+ return {'error': f'Backend error: {response.status_code} - {response.text}'}
277
+
278
+ except Exception as e:
279
+ return {'error': f'Unexpected error: {str(e)}'}
280
+
281
+ def collect_user_profile():
282
+ """Collect user profile information"""
283
+ st.markdown('<div class="section-header">πŸ‘€ User Profile Information</div>', unsafe_allow_html=True)
284
+
285
+ # Get the user's name from the database
286
+ user_data = get_user_data(st.session_state.username)
287
+ user_name = user_data.get('name', '')
288
+
289
+ col1, col2 = st.columns(2)
290
+
291
+ with col1:
292
+ age = st.number_input("Age", min_value=13, max_value=100, value=25)
293
+ weight = st.number_input("Weight (kg)", min_value=30.0, max_value=300.0, value=70.0, step=0.1)
294
+ height = st.number_input("Height (cm)", min_value=100.0, max_value=250.0, value=170.0, step=0.1)
295
+ gender = st.selectbox("Gender", ["Male", "Female", "Other", "Prefer not to say"])
296
+
297
+ with col2:
298
+ workout_preference = st.multiselect(
299
+ "Workout Preferences",
300
+ ["Cardio", "Strength Training", "Yoga", "Pilates", "HIIT", "CrossFit", "Swimming", "Running", "Cycling", "Dancing"],
301
+ default=["Cardio", "Strength Training"]
302
+ )
303
+
304
+ workout_time = st.selectbox(
305
+ "Preferred Workout Duration",
306
+ ["15-30 minutes", "30-45 minutes", "45-60 minutes", "60-90 minutes", "90+ minutes"]
307
+ )
308
+
309
+ fitness_level = st.selectbox(
310
+ "Current Fitness Level",
311
+ ["Beginner", "Intermediate", "Advanced"]
312
+ )
313
+
314
+ fitness_goal = st.selectbox(
315
+ "Primary Fitness Goal",
316
+ ["Weight Loss", "Muscle Gain", "Endurance", "Strength", "Flexibility", "General Health"]
317
+ )
318
+
319
+ st.markdown('<div class="section-header">πŸ“… Weekly Schedule</div>', unsafe_allow_html=True)
320
+
321
+ days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
322
+ schedule = {}
323
+
324
+ cols = st.columns(7)
325
+ for i, day in enumerate(days_of_week):
326
+ with cols[i]:
327
+ available = st.checkbox(f"{day[:3]}", key=f"day_{i}")
328
+ if available:
329
+ time_slot = st.selectbox(
330
+ "Time",
331
+ ["Morning (6-10 AM)", "Afternoon (12-4 PM)", "Evening (5-8 PM)", "Night (8-10 PM)"],
332
+ key=f"time_{i}"
333
+ )
334
+ schedule[day] = time_slot
335
+ else:
336
+ schedule[day] = "Not Available"
337
+
338
+ st.markdown('<div class="section-header">🍽️ Dietary Preferences & Health</div>', unsafe_allow_html=True)
339
+
340
+ col1, col2 = st.columns(2)
341
+
342
+ with col1:
343
+ food_preferences = st.multiselect(
344
+ "Dietary Preferences",
345
+ ["Vegetarian", "Vegan", "Pescatarian", "Keto", "Paleo", "Mediterranean", "Low-carb", "High-protein", "Gluten-free", "No restrictions"],
346
+ default=["No restrictions"]
347
+ )
348
+
349
+ allergies = st.text_area("Food Allergies/Intolerances", placeholder="e.g., nuts, dairy, shellfish")
350
+
351
+ with col2:
352
+ health_issues = st.text_area(
353
+ "Health Issues/Medical Conditions",
354
+ placeholder="e.g., diabetes, hypertension, joint problems, injuries"
355
+ )
356
+
357
+ medications = st.text_area("Current Medications", placeholder="List any medications that might affect exercise or diet")
358
+
359
+ # Water intake and sleep
360
+ col1, col2 = st.columns(2)
361
+ with col1:
362
+ water_intake = st.slider("Daily Water Intake (glasses)", 1, 15, 8)
363
+ with col2:
364
+ sleep_hours = st.slider("Average Sleep Hours", 4, 12, 7)
365
+
366
+ user_profile = {
367
+ 'name': user_name,
368
+ 'age': age,
369
+ 'weight': weight,
370
+ 'height': height,
371
+ 'gender': gender,
372
+ 'workout_preference': workout_preference,
373
+ 'workout_time': workout_time,
374
+ 'fitness_level': fitness_level,
375
+ 'fitness_goal': fitness_goal,
376
+ 'schedule': schedule,
377
+ 'food_preferences': food_preferences,
378
+ 'allergies': allergies,
379
+ 'health_issues': health_issues,
380
+ 'medications': medications,
381
+ 'water_intake': water_intake,
382
+ 'sleep_hours': sleep_hours,
383
+ 'timestamp': datetime.now().isoformat()
384
+ }
385
+
386
+ return user_profile
387
+
388
+ def display_profile_summary():
389
+ """Display user profile summary"""
390
+ if st.session_state.user_profile:
391
+ profile = st.session_state.user_profile
392
+
393
+ st.markdown('<div class="section-header">πŸ“‹ Profile Summary</div>', unsafe_allow_html=True)
394
+
395
+ # Calculate BMI
396
+ height_m = profile['height'] / 100
397
+ bmi = profile['weight'] / (height_m ** 2)
398
+
399
+ col1, col2, col3, col4 = st.columns(4)
400
+
401
+ with col1:
402
+ st.metric("Age", f"{profile['age']} years")
403
+ st.metric("Weight", f"{profile['weight']} kg")
404
+
405
+ with col2:
406
+ st.metric("Height", f"{profile['height']} cm")
407
+ st.metric("BMI", f"{bmi:.1f}")
408
+
409
+ with col3:
410
+ st.metric("Fitness Level", profile['fitness_level'])
411
+ st.metric("Primary Goal", profile['fitness_goal'])
412
+
413
+ with col4:
414
+ available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
415
+ st.metric("Available Days", f"{available_days}/7")
416
+ st.metric("Water Intake", f"{profile['water_intake']} glasses/day")
417
+
418
+ def generate_plans():
419
+ """Generate workout and nutrition plans"""
420
+ if not st.session_state.user_profile:
421
+ st.error("Please complete your profile first!")
422
+ return
423
+
424
+ col1, col2 = st.columns(2)
425
+
426
+ with col1:
427
+ if st.button("πŸ‹οΈ Generate Workout Plan", type="primary", use_container_width=True):
428
+ with st.spinner("Creating your personalized workout plan..."):
429
+ response = call_backend_service('workout', st.session_state.user_profile)
430
+
431
+ if 'error' in response:
432
+ st.error(f"Error generating workout plan: {response['error']}")
433
+ else:
434
+ st.session_state.workout_plan = response
435
+ st.session_state.current_session_id = response.get('session_id')
436
+ # Add to chat history
437
+ st.session_state.chat_history.append({
438
+ 'type': 'workout_request',
439
+ 'user_profile': st.session_state.user_profile,
440
+ 'response': response,
441
+ 'session_id': response.get('session_id'),
442
+ 'timestamp': datetime.now().isoformat()
443
+ })
444
+ # Save to user account
445
+ save_user_session(st.session_state.username)
446
+ st.success("βœ… Workout plan generated successfully!")
447
+ st.rerun()
448
+
449
+ with col2:
450
+ if st.button("πŸ₯— Generate Nutrition Plan", type="primary", use_container_width=True):
451
+ with st.spinner("Creating your personalized nutrition plan..."):
452
+ response = call_backend_service('nutrition', st.session_state.user_profile)
453
+
454
+ if 'error' in response:
455
+ st.error(f"Error generating nutrition plan: {response['error']}")
456
+ else:
457
+ st.session_state.nutrition_plan = response
458
+ st.session_state.current_session_id = response.get('session_id')
459
+ # Add to chat history
460
+ st.session_state.chat_history.append({
461
+ 'type': 'nutrition_request',
462
+ 'user_profile': st.session_state.user_profile,
463
+ 'response': response,
464
+ 'session_id': response.get('session_id'),
465
+ 'timestamp': datetime.now().isoformat()
466
+ })
467
+ # Save to user account
468
+ save_user_session(st.session_state.username)
469
+ st.success("βœ… Nutrition plan generated successfully!")
470
+ st.rerun()
471
+
472
+ def display_workout_plan():
473
+ """Display the generated workout plan"""
474
+ if st.session_state.workout_plan:
475
+ st.markdown('<div class="section-header">πŸ‹οΈ Your Workout Plan</div>', unsafe_allow_html=True)
476
+
477
+ # Display the response content
478
+ workout_data = st.session_state.workout_plan
479
+
480
+ if isinstance(workout_data, dict) and 'response' in workout_data:
481
+ st.markdown(workout_data['response'])
482
+ elif isinstance(workout_data, dict) and 'content' in workout_data:
483
+ st.markdown(workout_data['content'])
484
+ else:
485
+ st.markdown(str(workout_data))
486
+
487
+ # Download option
488
+ col1, col2 = st.columns([1, 4])
489
+ with col1:
490
+ download_content = workout_data.get('response', workout_data.get('content', str(workout_data)))
491
+ st.download_button(
492
+ "πŸ“₯ Download Plan",
493
+ data=download_content,
494
+ file_name=f"workout_plan_{datetime.now().strftime('%Y%m%d')}.txt",
495
+ mime="text/plain"
496
+ )
497
+
498
+ def display_nutrition_plan():
499
+ """Display the generated nutrition plan"""
500
+ if st.session_state.nutrition_plan:
501
+ st.markdown('<div class="section-header">πŸ₯— Your Nutrition Plan</div>', unsafe_allow_html=True)
502
+
503
+ # Display the response content
504
+ nutrition_data = st.session_state.nutrition_plan
505
+
506
+ if isinstance(nutrition_data, dict) and 'response' in nutrition_data:
507
+ st.markdown(nutrition_data['response'])
508
+ elif isinstance(nutrition_data, dict) and 'content' in nutrition_data:
509
+ st.markdown(nutrition_data['content'])
510
+ else:
511
+ st.markdown(str(nutrition_data))
512
+
513
+ # Download option
514
+ col1, col2 = st.columns([1, 4])
515
+ with col1:
516
+ download_content = nutrition_data.get('response', nutrition_data.get('content', str(nutrition_data)))
517
+ st.download_button(
518
+ "πŸ“₯ Download Plan",
519
+ data=download_content,
520
+ file_name=f"nutrition_plan_{datetime.now().strftime('%Y%m%d')}.txt",
521
+ mime="text/plain"
522
+ )
523
+
524
+ def chat_interface():
525
+ """Chat interface for follow-up questions"""
526
+ st.markdown('<div class="section-header">πŸ’¬ Chat with Your AI Coach</div>', unsafe_allow_html=True)
527
+
528
+ # Display chat history
529
+ for i, message in enumerate(st.session_state.chat_history):
530
+ if message['type'] in ['user_message', 'assistant_message']:
531
+ with st.chat_message(message['type'].replace('_message', '')):
532
+ st.write(message['content'])
533
+
534
+ # Chat input
535
+ if prompt := st.chat_input("Ask questions about your workout or nutrition plan..."):
536
+ # Add user message to chat
537
+ st.session_state.chat_history.append({
538
+ 'type': 'user_message',
539
+ 'content': prompt,
540
+ 'timestamp': datetime.now().isoformat()
541
+ })
542
+
543
+ with st.chat_message("user"):
544
+ st.write(prompt)
545
+
546
+ # Get response from backend
547
+ with st.chat_message("assistant"):
548
+ with st.spinner("Thinking..."):
549
+ response = call_backend_service('chat', st.session_state.user_profile, prompt)
550
+
551
+ if 'error' in response:
552
+ assistant_response = f"I apologize, but I encountered an error: {response['error']}. Please try again."
553
+ else:
554
+ assistant_response = response.get('response', 'I apologize, but I couldn\'t process your request.')
555
+
556
+ st.write(assistant_response)
557
+
558
+ # Add assistant response to chat history
559
+ st.session_state.chat_history.append({
560
+ 'type': 'assistant_message',
561
+ 'content': assistant_response,
562
+ 'session_id': response.get('session_id'),
563
+ 'timestamp': datetime.now().isoformat()
564
+ })
565
+
566
+ # Save to user account
567
+ save_user_session(st.session_state.username)
568
+
569
+ def sidebar_navigation():
570
+ """Sidebar navigation and settings"""
571
+ with st.sidebar:
572
+ st.markdown("### πŸƒβ€β™€οΈ AI Fitness Coach")
573
+
574
+ # User info and logout
575
+ if st.session_state.authenticated:
576
+ user_name = st.session_state.username
577
+ # if users[user_name]['name']:
578
+ # user_name = st.session_state.user_profile['name']
579
+ st.markdown(f"**πŸ‘€ Welcome, {user_name}!**")
580
+ if st.button("πŸšͺ Logout", type="secondary", use_container_width=True):
581
+ # Save session before logout
582
+ save_user_session(st.session_state.username)
583
+
584
+ # Clear session
585
+ st.session_state.authenticated = False
586
+ st.session_state.username = ""
587
+ st.session_state.user_profile = {}
588
+ st.session_state.chat_history = []
589
+ st.session_state.workout_plan = None
590
+ st.session_state.nutrition_plan = None
591
+ st.session_state.profile_submitted = False
592
+ st.session_state.current_session_id = None
593
+ st.rerun()
594
+
595
+ st.markdown("---")
596
+
597
+ # Navigation
598
+ page = st.radio(
599
+ "Navigation",
600
+ ["πŸ‘€ Profile Setup", "πŸ“Š Dashboard", "πŸ’¬ Chat Coach", "βš™οΈ Settings"]
601
+ )
602
+
603
+ # Quick stats if profile exists
604
+ if st.session_state.user_profile:
605
+ st.markdown("### πŸ“ˆ Quick Stats")
606
+ profile = st.session_state.user_profile
607
+ # BMI calculation
608
+ height_m = profile['height'] / 100
609
+ bmi = profile['weight'] / (height_m ** 2)
610
+
611
+ if bmi < 18.5:
612
+ bmi_status = "Underweight"
613
+ bmi_color = "blue"
614
+ elif bmi < 25:
615
+ bmi_status = "Normal"
616
+ bmi_color = "green"
617
+ elif bmi < 30:
618
+ bmi_status = "Overweight"
619
+ bmi_color = "orange"
620
+ else:
621
+ bmi_status = "Obese"
622
+ bmi_color = "red"
623
+
624
+ st.markdown(f"**BMI:** <span style='color:{bmi_color}'>{bmi:.1f} ({bmi_status})</span>", unsafe_allow_html=True)
625
+ st.markdown(f"**Goal:** {profile['fitness_goal']}")
626
+ st.markdown(f"**Level:** {profile['fitness_level']}")
627
+
628
+ available_days = len([day for day, time in profile['schedule'].items() if time != "Not Available"])
629
+ st.markdown(f"**Available Days:** {available_days}/7")
630
+
631
+ # Show current session ID if available
632
+ if st.session_state.current_session_id:
633
+ st.markdown(f"**Session:** {st.session_state.current_session_id}")
634
+
635
+ st.markdown("---")
636
+ st.markdown(
637
+ "<div style='text-align: left; color: #888; font-size: 1em; margin-top: 2rem;'>"
638
+ "Created by Sayon"
639
+ "</div>",
640
+ unsafe_allow_html=True
641
+ )
642
+ return page
643
+
644
+ def main():
645
+ """Main application function"""
646
+ init_session_state()
647
+
648
+ # Check authentication
649
+ if not st.session_state.authenticated:
650
+ login_page()
651
+ return
652
+
653
+ # Header
654
+ st.markdown('<div class="main-header">πŸ‹οΈ AI Fitness Coach</div>', unsafe_allow_html=True)
655
+ st.markdown("*Your personalized fitness and nutrition companion powered by AI*")
656
+ st.markdown("---")
657
+
658
+ # Sidebar navigation
659
+ current_page = sidebar_navigation()
660
+
661
+ if current_page == "πŸ‘€ Profile Setup":
662
+ user_profile = collect_user_profile()
663
+
664
+ st.markdown("---")
665
+
666
+ if st.button("πŸ’Ύ Save Profile & Continue", type="primary", use_container_width=True):
667
+ st.session_state.user_profile = user_profile
668
+ st.session_state.profile_submitted = True
669
+ # Save to user account
670
+ save_user_session(st.session_state.username)
671
+ st.success("βœ… Profile saved successfully!")
672
+ st.balloons()
673
+ st.rerun()
674
+
675
+ elif current_page == "πŸ“Š Dashboard":
676
+ if not st.session_state.user_profile:
677
+ st.warning("⚠️ Please complete your profile setup first!")
678
+ if st.button("Go to Profile Setup"):
679
+ st.rerun()
680
+ else:
681
+ display_profile_summary()
682
+ st.markdown("---")
683
+ generate_plans()
684
+
685
+ col1, col2 = st.columns(2)
686
+ with col1:
687
+ display_workout_plan()
688
+ with col2:
689
+ display_nutrition_plan()
690
+
691
+ elif current_page == "πŸ’¬ Chat Coach":
692
+ if not st.session_state.user_profile:
693
+ st.warning("⚠️ Please complete your profile setup first!")
694
+ else:
695
+ chat_interface()
696
+
697
+ elif current_page == "βš™οΈ Settings":
698
+ st.markdown('<div class="section-header">βš™οΈ Application Settings</div>', unsafe_allow_html=True)
699
+
700
+ # Account Information
701
+ st.subheader("πŸ‘€ Account Information")
702
+ user_data = get_user_data(st.session_state.username)
703
+
704
+ col1, col2 = st.columns(2)
705
+ with col1:
706
+ st.info(f"**Username:** {st.session_state.username}")
707
+ st.info(f"**Account Created:** {user_data.get('created_at', 'Unknown')[:10]}")
708
+ with col2:
709
+ st.info(f"**Name:** {user_data.get('name', 'Not provided')}")
710
+ if user_data.get('last_updated'):
711
+ st.info(f"**Last Updated:** {user_data.get('last_updated')[:10]}")
712
+
713
+ # Danger Zone
714
+ st.subheader("🚨 Danger Zone")
715
+ with st.expander("Delete Account"):
716
+ st.error("⚠️ **Warning**: This action cannot be undone!")
717
+ st.write("This will permanently delete your account and all associated data.")
718
+
719
+ confirm_delete = st.text_input("Type 'DELETE' to confirm account deletion:")
720
+
721
+ if st.button("πŸ—‘οΈ Delete Account", type="secondary") and confirm_delete == "DELETE":
722
+ # Delete user from users.json
723
+ users = load_users()
724
+ if st.session_state.username in users:
725
+ del users[st.session_state.username]
726
+ save_users(users)
727
+
728
+ # Clear session and logout
729
+ st.session_state.authenticated = False
730
+ st.session_state.username = ""
731
+ st.session_state.user_profile = {}
732
+ st.session_state.chat_history = []
733
+ st.session_state.workout_plan = None
734
+ st.session_state.nutrition_plan = None
735
+ st.session_state.profile_submitted = False
736
+ st.session_state.current_session_id = None
737
+
738
+ st.success("Account deleted successfully. You will be redirected to the login page.")
739
+ st.rerun()
740
+
741
+ if __name__ == "__main__":
742
+ main()