Code fixes, style, analysis separation

This commit is contained in:
Dawid Pietrykowski 2024-08-08 18:18:01 +02:00
parent ff9cdc02d8
commit ebededacc1
8 changed files with 169 additions and 103 deletions

1
lib/api_key.dart Normal file
View File

@ -0,0 +1 @@
const String geminiApiKey = '';

View File

@ -0,0 +1 @@

View File

@ -2,8 +2,8 @@ import 'dart:convert';
import 'package:bloc/bloc.dart';
import 'package:flutter/services.dart';
import 'package:gemini_app/api_key.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';
@ -23,6 +23,10 @@ here describe what is the state of the student and how to best approach them
here continue with the lesson, respond to answers, etc
""";
const String LESSON_START_TOKEN = "<LESSON_START_TOKEN>";
const String ANALYSIS_START_TOKEN = "<ANALYSIS_START_TOKEN>";
const String QUIZ_START_TOKEN = "<QUIZ_START_TOKEN>";
enum GeminiStatus { initial, loading, success, error }
// enum MessageType { text, image, audio, video }
@ -147,7 +151,8 @@ class GeminiCubit extends Cubit<GeminiState> {
void startLesson() async {
final quizQuestions = await loadQuizQuestions();
final String lessonScript = await rootBundle.loadString('assets/lessons/cells.md');
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 =
@ -181,42 +186,51 @@ class GeminiCubit extends Cubit<GeminiState> {
model: model);
emit(initialState);
try {
final chat = state.model!.startChat(history: [Content.text(prompt)]);
final stream = chat.sendMessageStream(Content.text(
"EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nMessage:\n$prompt"));
sendMessage("");
String responseText = '';
// try {
// final chat = state.model!.startChat(history: [Content.text(prompt)]);
// final stream = chat.sendMessageStream(Content.text(
// "EEG DATA:\n${GetIt.instance<EegService>().state.getJsonString()}\nMessage:\n$prompt"));
await for (final chunk in stream) {
responseText += chunk.text ?? '';
emit(initialState.copyWith(
status: GeminiStatus.success,
messages: [
lessonScriptMessage,
Message(
source: MessageSource.agent,
text: responseText,
type: MessageType.text)
],
model: model));
}
} catch (e) {
emit(GeminiState(
status: GeminiStatus.error,
messages: state.messages,
error: e.toString(),
));
}
// String responseText = '';
// await for (final chunk in stream) {
// responseText += chunk.text ?? '';
// emit(initialState.copyWith(
// status: GeminiStatus.success,
// messages: [
// lessonScriptMessage,
// Message(
// source: MessageSource.agent,
// text: responseText,
// type: MessageType.text)
// ],
// model: model));
// }
// } catch (e) {
// emit(GeminiState(
// status: GeminiStatus.error,
// messages: state.messages,
// error: e.toString(),
// ));
// }
}
void sendMessage(String prompt) async {
List<Message> messagesWithoutPrompt = state.messages;
var messagesWithPrompt = state.messages +
List<Message> messagesWithPrompt;
if (prompt == "") {
messagesWithPrompt = state.messages;
} else {
messagesWithPrompt = state.messages +
[
Message(
text: prompt, type: MessageType.text, source: MessageSource.user)
text: prompt,
type: MessageType.text,
source: MessageSource.user)
];
}
emit(state.copyWith(
status: GeminiStatus.loading,
@ -233,8 +247,20 @@ class GeminiCubit extends Cubit<GeminiState> {
String responseText = '';
bool isAnalysisDone = false;
await for (final chunk in stream) {
responseText += chunk.text ?? '';
if (responseText.contains(LESSON_START_TOKEN)) {
isAnalysisDone = true;
var startIndex = responseText.indexOf(LESSON_START_TOKEN) +
LESSON_START_TOKEN.length;
var analysisData = responseText.substring(0, startIndex);
print("ANALYSIS DATA: $analysisData");
responseText =
responseText.substring(startIndex, responseText.length);
}
if (isAnalysisDone) {
emit(state.copyWith(
status: GeminiStatus.success,
messages: messagesWithPrompt +
@ -245,6 +271,7 @@ class GeminiCubit extends Cubit<GeminiState> {
type: MessageType.text)
]));
}
}
if (responseText.contains("<QUIZ_START_TOKEN>")) {
enterQuizMode();

View File

@ -1,2 +1,2 @@
const String geminiApiKey = '';
const String geminiApiKey = 'AIzaSyBU-vIDA4IUfRReXcu7Vdw53gnrnroJjzI';
const bool isDebug = true;

View File

@ -2,26 +2,24 @@ 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 mindWandering;
final double focus;
EegState({
required this.mind_wandering,
required this.mindWandering,
required this.focus,
});
String getJsonString() {
return '{"mind_wandering": $mind_wandering, "focus": $focus}';
return '{"mind_wandering": $mindWandering, "focus": $focus}';
}
}
class EegService {
EegState state;
EegService() : state = EegState(mind_wandering: 0.9, focus: 0.1) {
EegService() : state = EegState(mindWandering: 0.9, focus: 0.1) {
// Start the timer when the cubit is created
if (!isDebug) {
startPolling();
@ -32,7 +30,7 @@ class EegService {
void startPolling() {
// Poll every 1 second (adjust the duration as needed)
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
_timer = Timer.periodic(const 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;
@ -84,16 +82,16 @@ class EegService {
}
void updateEegData(double mindWandering, double focus) {
state = EegState(mind_wandering: mindWandering, focus: focus);
state = EegState(mindWandering: 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);
if (state.mindWandering > state.focus) {
updateEegData(state.focus, state.mindWandering);
} else {
updateEegData(state.mind_wandering, state.focus);
updateEegData(state.mindWandering, state.focus);
}
}
}

View File

@ -58,14 +58,14 @@ class GeminiChatState extends State<GeminiChat> {
}
void _sendMessage() async {
context
.read<GeminiCubit>()
.sendMessage(_textController.text);
context.read<GeminiCubit>().sendMessage(_textController.text);
_textController.clear();
}
void _toggleEegState() {
setState(() {
_eegService.toggleState();
});
}
void _resetConversation() {
@ -91,20 +91,23 @@ class GeminiChatState extends State<GeminiChat> {
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Mind Wandering: ${_eegService.state.mind_wandering.toStringAsFixed(2)}'),
Text('Focus: ${_eegService.state.focus.toStringAsFixed(2)}'),
'Mind Wandering: ${_eegService.state.mindWandering.toStringAsFixed(2)}'),
Text(
'Focus: ${_eegService.state.focus.toStringAsFixed(2)}'),
],
),
),
),
const SizedBox(height: 16),
Expanded(
child: BlocBuilder<GeminiCubit, GeminiState>(
builder: (context, state) {
@ -118,54 +121,87 @@ class GeminiChatState extends State<GeminiChat> {
},
),
),
const SizedBox(height: 16),
BlocBuilder<GeminiCubit, GeminiState>(
builder: (context, state) {
return state.isQuizMode
? Container() // Hide text input in quiz mode
? Container()
: TextField(
controller: _textController,
decoration: const InputDecoration(
decoration: InputDecoration(
hintText: 'Enter your message',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
filled: true,
fillColor: Colors.grey[200],
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 12.0),
),
onSubmitted: (_) => _sendMessage(),
);
},
),
const SizedBox(height: 16),
Row(
children: [
BlocBuilder<GeminiCubit, GeminiState>(
builder: (context, state) {
return state.isQuizMode
? Container()
: Expanded(
child: ElevatedButton(
// BlocBuilder<GeminiCubit, GeminiState>(
// builder: (context, state) {
// return state.isQuizMode
// ? Container()
// : Expanded(
// child: ElevatedButton(
// onPressed: _sendMessage,
// child: const Text('Send'),
// ),
// );
// },
// ),
ElevatedButton(
onPressed: _sendMessage,
child: const Text('Send'),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.send),
SizedBox(width: 3),
Text('Send'),
],
),
);
},
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _resetConversation,
child: const Text('Reset'),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.refresh),
SizedBox(width: 3),
Text('Reset'),
],
),
),
const SizedBox(width: 8),
ElevatedButton(
onPressed: _toggleEegState,
child: const Text('Toggle State'),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.toggle_on),
SizedBox(width: 3),
Text('Toggle State'),
],
),
const SizedBox(width: 8),
BlocBuilder<GeminiCubit, GeminiState>(
builder: (context, state) {
return state.isQuizMode
? Container()
: ElevatedButton(
onPressed: _enterQuizMode,
child: const Text('Start Quiz'),
);
},
),
// ElevatedButton(
// onPressed: _enterQuizMode,
// child: const Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Icon(Icons.quiz),
// SizedBox(width: 8),
// Text('Start Quiz'),
// ],
// ),
// ),
],
),
],
@ -302,12 +338,13 @@ class BouncingDotsState extends State<BouncingDots>
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(3, (index) {
return AnimatedBuilder(
animation: _controllers[index],
builder: (context, child) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 4.0),
padding: const EdgeInsets.all(2.5),
child: Transform.translate(
offset: Offset(0, _animations[index].value),

View File

@ -18,7 +18,7 @@ packages:
source: hosted
version: "2.11.0"
bloc:
dependency: transitive
dependency: "direct main"
description:
name: bloc
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
@ -124,13 +124,13 @@ packages:
source: hosted
version: "0.4.3"
http:
dependency: transitive
dependency: "direct main"
description:
name: http
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
http_parser:
dependency: transitive
description:

View File

@ -42,6 +42,8 @@ dependencies:
flutter_markdown: ^0.7.3
flutter_bloc: ^8.0.1
get_it: ^7.7.0
http: ^1.2.2
bloc: ^8.1.4
dev_dependencies:
flutter_test: