Skip to content

Commit d0210ee

Browse files
Unic-XR0gue-one
authored andcommitted
added ai coach
1 parent 1c7a521 commit d0210ee

File tree

6 files changed

+180
-62
lines changed

6 files changed

+180
-62
lines changed
1.76 KB
Loading
511 Bytes
Loading
3.36 KB
Loading
7.78 KB
Loading
13.2 KB
Loading

frontend/lib/Screens/user.dart

Lines changed: 180 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:fl_chart/fl_chart.dart';
55
import 'package:hack_space_temp/Screens/components/bottom_nav_bar.dart';
66
// import 'package:hack_space_temp/Screens/components/my_button.dart';
77
import 'package:intl/intl.dart';
8+
import 'package:google_generative_ai/google_generative_ai.dart';
89

910
class UserProfilePage extends StatefulWidget {
1011
final String userName;
@@ -21,6 +22,46 @@ class UserProfilePage extends StatefulWidget {
2122
@override
2223
State<UserProfilePage> createState() => _UserProfilePageState();
2324
}
25+
String advice = '';
26+
Future<String> generateAdvice({
27+
required double todayDist,
28+
required int todayTime,
29+
required Map<String, dynamic> weekAc,
30+
required int height,
31+
required int weight,
32+
}) async {
33+
String userDataSummary = '''
34+
Today, you ran a distance of $todayDist meters in $todayTime seconds.
35+
Your weekly activity summary is: ${weekAc.map((key, value) => MapEntry(key, '${value.toString()} meters'))}.
36+
Your height is ${height.toStringAsFixed(2)} meters and your weight is ${weight.toStringAsFixed(2)} kilograms.
37+
''';
38+
39+
final model = GenerativeModel(
40+
model: 'gemini-1.5-pro',
41+
apiKey: 'AIzaSyACou9Lb1KnQ4GHZtK-ci4_WGZNlfgD2pE',
42+
);
43+
44+
final prompt = '''
45+
Based on the following user data, provide personalized health and fitness advice:
46+
47+
$userDataSummary
48+
49+
Please include recommendations for improving fitness, diet tips, and any suggestions for running efficiency.
50+
''';
51+
52+
try {
53+
final result = await model.generateContent([Content.text(prompt)]);
54+
return result.text ?? 'No advice generated.';
55+
} catch (e) {
56+
print('Error generating content: $e');
57+
return 'Failed to generate advice. Please try again later.';
58+
}
59+
}
60+
61+
62+
// void main() async {
63+
// await generateAdvice();
64+
// }
2465

2566
List<FriendData> friendLeaderboard = [];
2667

@@ -35,6 +76,8 @@ class _UserProfilePageState extends State<UserProfilePage> {
3576
List<RunningData> runningData = [];
3677
bool isLoading = true;
3778
String errorMessage = '';
79+
String aiAdvice = '';
80+
bool isGeneratingAdvice = false;
3881

3982
@override
4083
void initState() {
@@ -432,76 +475,151 @@ class _UserProfilePageState extends State<UserProfilePage> {
432475
}
433476

434477
Widget _buildLeaderboard() {
435-
// Create a combined leaderboard list with the user and friends
436-
List<FriendData> fullLeaderboard = [
437-
FriendData(username: userName, todayDist: today_dist, todayTime: today_time)
438-
]..addAll(friendLeaderboard);
439-
440-
// Sort the leaderboard based on distance
441-
fullLeaderboard.sort((a, b) => b.todayDist.compareTo(a.todayDist));
442-
443-
return Container(
444-
decoration: BoxDecoration(
445-
color: Colors.white, // Background color for the leaderboard
446-
borderRadius: BorderRadius.circular(12), // Rounded corners
447-
boxShadow: [
448-
BoxShadow(
449-
color: Colors.grey.withOpacity(0.5), // Shadow color
450-
spreadRadius: 2, // Spread radius
451-
blurRadius: 5, // Blur radius
452-
offset: const Offset(0, 3), // Shadow offset
478+
// Create a combined leaderboard list with the user and friends
479+
List<FriendData> fullLeaderboard = [
480+
FriendData(username: userName, todayDist: today_dist, todayTime: today_time)
481+
]..addAll(friendLeaderboard);
482+
483+
// Sort the leaderboard based on distance
484+
fullLeaderboard.sort((a, b) => b.todayDist.compareTo(a.todayDist));
485+
486+
return Container(
487+
decoration: BoxDecoration(
488+
color: Colors.white, // Background color for the leaderboard
489+
borderRadius: BorderRadius.circular(12), // Rounded corners
490+
boxShadow: [
491+
BoxShadow(
492+
color: Colors.grey.withOpacity(0.5), // Shadow color
493+
spreadRadius: 2, // Spread radius
494+
blurRadius: 5, // Blur radius
495+
offset: const Offset(0, 3), // Shadow offset
496+
),
497+
],
498+
),
499+
padding: const EdgeInsets.all(16), // Padding for the container
500+
child: Column(
501+
crossAxisAlignment: CrossAxisAlignment.start,
502+
children: [
503+
const Text(
504+
'Leaderboard',
505+
style: TextStyle(
506+
fontSize: 24,
507+
fontWeight: FontWeight.bold,
508+
color: Colors.black,
453509
),
454-
],
455-
),
456-
padding: const EdgeInsets.all(16), // Padding for the container
457-
child: Column(
458-
crossAxisAlignment: CrossAxisAlignment.start,
459-
children: [
460-
const Text(
461-
'Leaderboard',
462-
style: TextStyle(
463-
fontSize: 24,
464-
fontWeight: FontWeight.bold,
465-
color: Colors.black,
510+
),
511+
const SizedBox(height: 10),
512+
fullLeaderboard.isEmpty
513+
? const Text(
514+
"No data to show.",
515+
style: TextStyle(color: Colors.grey),
516+
)
517+
: ListView.builder(
518+
shrinkWrap: true,
519+
physics: const NeverScrollableScrollPhysics(),
520+
itemCount: fullLeaderboard.length,
521+
itemBuilder: (context, index) {
522+
final participant = fullLeaderboard[index];
523+
return ListTile(
524+
leading: Text(
525+
'#${index + 1}',
526+
style: const TextStyle(fontWeight: FontWeight.bold),
527+
),
528+
title: Text(
529+
participant.username == userName
530+
? 'You'
531+
: participant.username,
532+
),
533+
subtitle: Text(
534+
'Distance: ${formatDistance(participant.todayDist)}, Time: ${formatTime(participant.todayTime)}',
535+
),
536+
tileColor: participant.username == userName
537+
? Colors.yellow.withOpacity(0.2) // Highlight the user
538+
: null,
539+
);
540+
},
541+
),
542+
const SizedBox(height: 20),
543+
Center(
544+
child: TextButton(
545+
onPressed: isGeneratingAdvice ? null : () async {
546+
setState(() {
547+
isGeneratingAdvice = true;
548+
});
549+
try {
550+
DocumentSnapshot userDoc =
551+
await FirebaseFirestore.instance.collection('users').doc(uid).get();
552+
Map<String, dynamic> data = userDoc.data() as Map<String, dynamic>;
553+
String generatedAdvice = await generateAdvice(
554+
todayDist: today_dist,
555+
todayTime: today_time,
556+
weekAc: data['week_ac'],
557+
height: data['height'],
558+
weight: data['weight'],
559+
);
560+
setState(() {
561+
aiAdvice = generatedAdvice;
562+
isGeneratingAdvice = false;
563+
});
564+
} catch (e) {
565+
print('Error generating advice: $e');
566+
setState(() {
567+
aiAdvice = 'Failed to generate advice. Please try again later.';
568+
isGeneratingAdvice = false;
569+
});
570+
}
571+
},
572+
style: TextButton.styleFrom(
573+
backgroundColor: const Color(0xFF229DAB),
574+
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
575+
),
576+
child: isGeneratingAdvice
577+
? const CircularProgressIndicator(color: Colors.white)
578+
: const Text(
579+
'AI Coach',
580+
style: TextStyle(
581+
color: Colors.white,
582+
fontSize: 18,
583+
fontWeight: FontWeight.bold,
584+
),
585+
),
466586
),
467587
),
468-
const SizedBox(height: 10),
469-
fullLeaderboard.isEmpty
470-
? const Text(
471-
"No data to show.",
472-
style: TextStyle(color: Colors.grey),
473-
)
474-
: ListView.builder(
475-
shrinkWrap: true,
476-
physics: const NeverScrollableScrollPhysics(),
477-
itemCount: fullLeaderboard.length,
478-
itemBuilder: (context, index) {
479-
final participant = fullLeaderboard[index];
480-
return ListTile(
481-
leading: Text(
482-
'#${index + 1}',
483-
style: const TextStyle(fontWeight: FontWeight.bold),
484-
),
485-
title: Text(
486-
participant.username == userName
487-
? 'You'
488-
: participant.username,
489-
),
490-
subtitle: Text(
491-
'Distance: ${formatDistance(participant.todayDist)}, Time: ${formatTime(participant.todayTime)}',
492-
),
493-
tileColor: participant.username == userName
494-
? Colors.yellow.withOpacity(0.2) // Highlight the user
495-
: null,
496-
);
497-
},
498-
),
588+
if (aiAdvice.isNotEmpty) ...[
589+
const SizedBox(height: 20),
590+
Container(
591+
padding: const EdgeInsets.all(16),
592+
decoration: BoxDecoration(
593+
color: Colors.grey[200],
594+
borderRadius: BorderRadius.circular(8),
595+
),
596+
child: Column(
597+
crossAxisAlignment: CrossAxisAlignment.start,
598+
children: [
599+
const Text(
600+
'AI Coach Advice:',
601+
style: TextStyle(
602+
fontWeight: FontWeight.bold,
603+
fontSize: 18,
604+
),
605+
),
606+
const SizedBox(height: 8),
607+
Text(
608+
aiAdvice,
609+
style: const TextStyle(fontSize: 16),
610+
),
611+
],
612+
),
613+
),
614+
],
499615
],
500616
),
501617
);
502618
}
503619

504620

621+
622+
505623
}
506624

507625
class FriendData {
@@ -527,4 +645,4 @@ class RunningData {
527645

528646
@override
529647
String toString() => 'RunningData(date: $date, distance: $distance)';
530-
}
648+
}

0 commit comments

Comments
 (0)