Code improvements, changed language to english, changed eeg from cubit to service

This commit is contained in:
Dawid Pietrykowski 2024-08-08 17:52:50 +02:00
parent 7158824ffa
commit ff9cdc02d8
9 changed files with 285 additions and 151 deletions

102
assets/lessons/cells.json Normal file
View File

@ -0,0 +1,102 @@
[
{
"question": "Which part of the cell is known as the 'powerhouse'?",
"options": [
"Nucleus",
"Ribosome",
"Mitochondria",
"Golgi Apparatus"
],
"correctAnswer": 2
},
{
"question": "What is the main function of ribosomes?",
"options": [
"DNA replication",
"Protein synthesis",
"Energy production",
"Waste removal"
],
"correctAnswer": 1
},
{
"question": "Which organelle is responsible for packaging and transporting proteins?",
"options": [
"Endoplasmic Reticulum",
"Nucleus",
"Golgi Apparatus",
"Lysosome"
],
"correctAnswer": 2
},
{
"question": "Which structure in the cell controls its activities and contains genetic material?",
"options": [
"Cytoplasm",
"Nucleus",
"Mitochondria",
"Cell Membrane"
],
"correctAnswer": 1
},
{
"question": "What is the semi-fluid substance inside the cell that contains the organelles?",
"options": [
"Cytoplasm",
"Nucleoplasm",
"Plasma",
"Protoplasm"
],
"correctAnswer": 0
},
{
"question": "Which organelle is responsible for breaking down waste materials and cellular debris?",
"options": [
"Ribosome",
"Lysosome",
"Mitochondria",
"Endoplasmic Reticulum"
],
"correctAnswer": 1
},
{
"question": "What is the function of the cell membrane?",
"options": [
"Protects the cell and controls what enters and exits",
"Stores genetic information",
"Produces energy",
"Synthesizes proteins"
],
"correctAnswer": 0
},
{
"question": "Which type of cell contains a nucleus?",
"options": [
"Prokaryotic",
"Eukaryotic",
"Both",
"Neither"
],
"correctAnswer": 1
},
{
"question": "Which organelle is involved in the synthesis of lipids and detoxification?",
"options": [
"Rough Endoplasmic Reticulum",
"Smooth Endoplasmic Reticulum",
"Golgi Apparatus",
"Ribosome"
],
"correctAnswer": 1
},
{
"question": "What is transported by vesicles that bud off from the Golgi apparatus?",
"options": [
"DNA",
"Proteins",
"RNA",
"Lipids"
],
"correctAnswer": 1
}
]

47
assets/lessons/cells.md Normal file
View File

@ -0,0 +1,47 @@
Topic: Basics of Cell Structure and Function
1. Introduction (5 Minutes)
Objective: Provide an overview of what the student will learn in the session.
Engagement Question: "Have you ever wondered what the smallest unit of life looks like and how it functions?"
2. Overview of Cells (10 Minutes)
Definition: Explain what a cell is and its importance.
Types of Cells: Differentiate between prokaryotic and eukaryotic cells with simple examples (e.g., bacteria vs. human cells).
Scale and Visualization: Show images/diagrams of cells under a microscope.
3. Cell Structure (15 Minutes)
Cell Membrane: Describe its function as a protective barrier and its role in regulating what enters and leaves the cell.
Cytoplasm: Explain it as the 'factory floor' where most cellular activities occur.
Nucleus: Introduce it as the 'control center' of the cell, containing DNA.
Mitochondria: Explain its role as the 'powerhouse' of the cell, generating energy.
Ribosomes: Describe their function in protein synthesis.
Other Organelles:
Endoplasmic Reticulum (ER): Differentiate between rough ER and smooth ER.
Golgi Apparatus: Explain its role in packaging and transporting proteins.
Lysosomes: Describe their function in waste removal.
4. Interactive Activity (10 Minutes)
Virtual Tour: Use an interactive 3D model of a cell to explore different organelles.
Quiz Questions:
"What is the function of the mitochondria?"
"Where are proteins synthesized in the cell?"
Q&A: Allow the student to ask questions and clarify any doubts.
5. Real-World Application (5 Minutes)
Relate to Everyday Life: Discuss how understanding cells can help us learn about diseases, develop medicines, and comprehend how our bodies work.
Current Research: Briefly mention exciting advancements in cell biology (e.g., stem cell research or cancer treatment).
6. Conclusion and Review (5 Minutes)
Summary: Recap the key points covered in the session.
Take-Home Message: Emphasize the importance of cells as the building blocks of life.
Homework/Next Steps: Suggest a short reading or video to reinforce the concepts learned.
7. Feedback (5 Minutes)
Student Reflection: Ask the student what they found most interesting or challenging.
Tutor Feedback: Provide positive feedback and areas for improvement.

View File

@ -1,103 +0,0 @@
import 'dart:async';
import 'package:gemini_app/config.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_bloc/flutter_bloc.dart';
class EegState {
final double mind_wandering;
final double focus;
EegState({
required this.mind_wandering,
required this.focus,
});
String getJsonString() {
return '{"mind_wandering": $mind_wandering, "focus": $focus}';
}
}
class EegCubit extends Cubit<EegState> {
EegCubit() : super(EegState(mind_wandering: 0.9, focus: 0.1)) {
// Start the timer when the cubit is created
if (!isDebug) {
startPolling();
}
}
Timer? _timer;
void startPolling() {
// Poll every 1 second (adjust the duration as needed)
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
// Simulate getting new EEG data
// In a real application, you would fetch this data from your EEG device or API
// double newMindWandering = (DateTime.now().millisecondsSinceEpoch % 100) / 100;
// double newFocus = 1 - newMindWandering;
fetchEegData().then((data) {
double newMindWandering = data[0];
double newFocus = data[1];
// Update the state with the new EEG data
updateEegData(newMindWandering, newFocus);
});
// updateEegData(newMindWandering, newFocus);
});
}
Future<List<double>> fetchEegData() async {
if (isDebug) {
return [0.9, 0.1]; // Placeholder ret
}
final url = Uri.parse('http://192.168.83.153:1234');
try {
final response = await http.get(url);
if (response.statusCode == 200) {
// Split the response body by newline and parse as floats
List<String> values = response.body.trim().split('\n');
if (values.length == 2) {
return [
double.parse(values[0]),
double.parse(values[1]),
];
} else {
throw Exception('Unexpected response format');
}
} else {
throw Exception('Failed to load EEG data: ${response.statusCode}');
}
} catch (e) {
throw Exception('Error fetching EEG data: $e');
}
}
void stopPolling() {
_timer?.cancel();
_timer = null;
}
void updateEegData(double mindWandering, double focus) {
emit(EegState(mind_wandering: mindWandering, focus: focus));
print('Mind Wandering: $mindWandering, Focus: $focus');
}
@override
Future<void> close() {
stopPolling();
return super.close();
}
void toggleState() {
// Toggle the state between mind_wandering and focus
if (state.mind_wandering > state.focus) {
updateEegData(state.focus, state.mind_wandering);
} else {
updateEegData(state.mind_wandering, state.focus);
}
}
}

View File

@ -4,13 +4,14 @@ import 'package:bloc/bloc.dart';
import 'package:flutter/services.dart';
import 'package:gemini_app/config.dart';
import 'package:gemini_app/bloc/eeg_state.dart';
import 'package:gemini_app/eeg/eeg_service.dart';
import 'package:get_it/get_it.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
const String systemPrmpt =
"""You are an AI tutor helping students understand topics with help of biometric data. You will be supplied with a json containing data extracted from an EEG device, use that data to modify your approach and help the student learn more effectively.
At the start you will be provided a script with a lesson to cover.
Keep the analysis and responses short.
Use language: POLISH
After completing the theoretical part there's a quiz, you can start it yourself at the appropriate time or react to users' request by including <QUIZ_START_TOKEN> at the start of your response
@ -42,18 +43,6 @@ class QuizMessage {
});
}
// class Message {
// final String text;
// final MessageType type;
// final MessageSource source;
// Message({
// required this.text,
// required this.type,
// required this.source,
// });
// }
enum MessageType { text, lessonScript, quizQuestion, quizAnswer }
class Message {
@ -148,11 +137,7 @@ class GeminiState {
static GeminiState get initialState => GeminiState(
status: GeminiStatus.initial,
// messages: [Message(text: "Hello, I'm Gemini Pro. How can I help you?", type: MessageType.text, source: MessageSource.agent)],
messages: [
// Message.fromGeminiContent(Content.model(
// [TextPart("Hello, I'm Gemini Pro. How can I help you?")]))
],
messages: [],
error: '',
);
}
@ -160,11 +145,13 @@ class GeminiState {
class GeminiCubit extends Cubit<GeminiState> {
GeminiCubit() : super(GeminiState.initialState);
void startLesson(EegState eegState) async {
void startLesson() async {
final quizQuestions = await loadQuizQuestions();
final String rjp = await rootBundle.loadString('assets/lessons/rjp.md');
final String prompt =
"Jesteś nauczycielem/chatbotem prowadzącym zajęcia z jednym uczniem. Uczeń ma możliwość zadawania pytań w trakcie, natomiast jesteś odpowiedzialny za prowadzenie lekcji i przedstawienie tematu. Zacznij prowadzić lekcje dla jednego ucznia na podstawie poniszego skryptu:\n$rjp";
final String lessonScript = await rootBundle.loadString('assets/lessons/cells.md');
// final String prompt =
// "Jesteś nauczycielem/chatbotem prowadzącym zajęcia z jednym uczniem. Uczeń ma możliwość zadawania pytań w trakcie, natomiast jesteś odpowiedzialny za prowadzenie lekcji i przedstawienie tematu. Zacznij prowadzić lekcje dla jednego ucznia na podstawie poniszego skryptu:\n$rjp";
final String prompt =
"You are a teacher/chatbot conducting a class with one student. The student has the ability to ask questions during the lesson, while you are responsible for leading the class and presenting the topic. Start conducting the lesson for one student based on the script below:\n$lessonScript";
final safetySettings = [
SafetySetting(HarmCategory.harassment, HarmBlockThreshold.none),
@ -197,7 +184,7 @@ class GeminiCubit extends Cubit<GeminiState> {
try {
final chat = state.model!.startChat(history: [Content.text(prompt)]);
final stream = chat.sendMessageStream(Content.text(
"EEG DATA:\n${eegState.getJsonString()}\nPytanie:\n$prompt"));
"EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nMessage:\n$prompt"));
String responseText = '';
@ -221,13 +208,9 @@ class GeminiCubit extends Cubit<GeminiState> {
error: e.toString(),
));
}
// enterQuizMode();
// sendMessage(prompt, eegState);
}
void sendMessage(String prompt, EegState eegState) async {
void sendMessage(String prompt) async {
List<Message> messagesWithoutPrompt = state.messages;
var messagesWithPrompt = state.messages +
[
@ -246,7 +229,7 @@ class GeminiCubit extends Cubit<GeminiState> {
.map((mess) => mess.toGeminiContent())
.toList());
final stream = chat.sendMessageStream(Content.text(
"EEG DATA:\n${eegState.getJsonString()}\nWiadomość od ucznia:\n$prompt"));
"EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nUser message:\n$prompt"));
String responseText = '';
@ -298,7 +281,7 @@ class GeminiCubit extends Cubit<GeminiState> {
Future<List<QuizQuestion>> loadQuizQuestions() async {
final String quizJson =
await rootBundle.loadString('assets/lessons/rjp.json');
await rootBundle.loadString('assets/lessons/cells.json');
final List<dynamic> quizData = json.decode(quizJson);
return quizData

99
lib/eeg/eeg_service.dart Normal file
View File

@ -0,0 +1,99 @@
import 'dart:async';
import 'package:gemini_app/config.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_bloc/flutter_bloc.dart';
class EegState {
final double mind_wandering;
final double focus;
EegState({
required this.mind_wandering,
required this.focus,
});
String getJsonString() {
return '{"mind_wandering": $mind_wandering, "focus": $focus}';
}
}
class EegService {
EegState state;
EegService() : state = EegState(mind_wandering: 0.9, focus: 0.1) {
// Start the timer when the cubit is created
if (!isDebug) {
startPolling();
}
}
Timer? _timer;
void startPolling() {
// Poll every 1 second (adjust the duration as needed)
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
// Simulate getting new EEG data
// In a real application, you would fetch this data from your EEG device or API
// double newMindWandering = (DateTime.now().millisecondsSinceEpoch % 100) / 100;
// double newFocus = 1 - newMindWandering;
fetchEegData().then((data) {
double newMindWandering = data[0];
double newFocus = data[1];
// Update the state with the new EEG data
updateEegData(newMindWandering, newFocus);
});
// updateEegData(newMindWandering, newFocus);
});
}
Future<List<double>> fetchEegData() async {
if (isDebug) {
return [0.9, 0.1]; // Placeholder ret
}
final url = Uri.parse('http://192.168.83.153:1234');
try {
final response = await http.get(url);
if (response.statusCode == 200) {
// Split the response body by newline and parse as floats
List<String> values = response.body.trim().split('\n');
if (values.length == 2) {
return [
double.parse(values[0]),
double.parse(values[1]),
];
} else {
throw Exception('Unexpected response format');
}
} else {
throw Exception('Failed to load EEG data: ${response.statusCode}');
}
} catch (e) {
throw Exception('Error fetching EEG data: $e');
}
}
void stopPolling() {
_timer?.cancel();
_timer = null;
}
void updateEegData(double mindWandering, double focus) {
state = EegState(mind_wandering: mindWandering, focus: focus);
print('Mind Wandering: $mindWandering, Focus: $focus');
}
void toggleState() {
// Toggle the state between mind_wandering and focus
if (state.mind_wandering > state.focus) {
updateEegData(state.focus, state.mind_wandering);
} else {
updateEegData(state.mind_wandering, state.focus);
}
}
}

View File

@ -1,7 +1,10 @@
import 'package:flutter/material.dart';
import 'package:gemini_app/eeg/eeg_service.dart';
import 'package:gemini_app/screens/gemini_chat_screen.dart';
import 'package:get_it/get_it.dart';
void main() {
GetIt.I.registerSingleton<EegService>(EegService());
runApp(const MyApp());
}

View File

@ -1,10 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gemini_app/bloc/eeg_state.dart';
import 'package:gemini_app/bloc/gemini_state.dart';
import 'package:google_generative_ai/google_generative_ai.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gemini_app/eeg/eeg_service.dart';
import 'package:get_it/get_it.dart';
class GeminiScreen extends StatelessWidget {
const GeminiScreen({super.key});
@ -14,7 +13,6 @@ class GeminiScreen extends StatelessWidget {
return MultiBlocProvider(
providers: [
BlocProvider(create: (context) => GeminiCubit()),
BlocProvider(create: (context) => EegCubit()),
],
child: const GeminiChat(),
);
@ -31,6 +29,7 @@ class GeminiChat extends StatefulWidget {
class GeminiChatState extends State<GeminiChat> {
final _textController = TextEditingController();
bool _quizMode = false; // Add this line
final EegService _eegService = GetIt.instance<EegService>();
@override
void initState() {
@ -50,23 +49,23 @@ class GeminiChatState extends State<GeminiChat> {
@override
void dispose() {
context.read<EegCubit>().stopPolling();
_eegService.stopPolling();
super.dispose();
}
void _startConversation() async {
context.read<GeminiCubit>().startLesson(context.read<EegCubit>().state);
context.read<GeminiCubit>().startLesson();
}
void _sendMessage() async {
context
.read<GeminiCubit>()
.sendMessage(_textController.text, context.read<EegCubit>().state);
.sendMessage(_textController.text);
_textController.clear();
}
void _toggleEegState() {
context.read<EegCubit>().toggleState();
_eegService.toggleState();
}
void _resetConversation() {
@ -93,23 +92,19 @@ class GeminiChatState extends State<GeminiChat> {
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
BlocBuilder<EegCubit, EegState>(
builder: (context, eegState) {
return Card(
Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Mind Wandering: ${eegState.mind_wandering.toStringAsFixed(2)}'),
Text('Focus: ${eegState.focus.toStringAsFixed(2)}'),
'Mind Wandering: ${_eegService.state.mind_wandering.toStringAsFixed(2)}'),
Text('Focus: ${_eegService.state.focus.toStringAsFixed(2)}'),
],
),
),
);
},
),
),
Expanded(
child: BlocBuilder<GeminiCubit, GeminiState>(
builder: (context, state) {

View File

@ -107,6 +107,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
get_it:
dependency: "direct main"
description:
name: get_it
sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1
url: "https://pub.dev"
source: hosted
version: "7.7.0"
google_generative_ai:
dependency: "direct main"
description:

View File

@ -41,6 +41,7 @@ dependencies:
flutter_lints: ^3.0.0
flutter_markdown: ^0.7.3
flutter_bloc: ^8.0.1
get_it: ^7.7.0
dev_dependencies:
flutter_test:
@ -69,8 +70,7 @@ flutter:
# - images/a_dot_ham.jpeg
assets:
- assets/lessons/rjp.md
- assets/lessons/rjp.json
- assets/lessons/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware