@@ -196,7 +196,6 @@ steps:
196196
197197 import 'dart:async';
198198
199- import 'package:colorist_ui/models/message.dart';
200199 import 'package:colorist_ui/providers/chat_state_notifier.dart';
201200 import 'package:colorist_ui/providers/log_state_notifier.dart';
202201 import 'package:firebase_vertexai/firebase_vertexai.dart';
@@ -218,13 +217,20 @@ steps:
218217
219218 chatStateNotifier.addUserMessage(message);
220219 logStateNotifier.logUserText(message);
220+ final llmMessage = chatStateNotifier.createLlmMessage();
221221 try {
222222 final response = await chatSession.sendMessage(Content.text(message));
223223 final responseText = response.text?.trim() ?? 'No text response received';
224224 logStateNotifier.logLlmText(responseText);
225- chatStateNotifier.addLlmMessage(responseText, MessageState.complete );
225+ chatStateNotifier.appendToMessage(llmMessage.id, responseText );
226226 } catch (e, st) {
227227 logStateNotifier.logError(e, st: st);
228+ chatStateNotifier.appendToMessage(
229+ llmMessage.id,
230+ "\nI'm sorry, I encountered an error processing your request. Please try again.",
231+ );
232+ } finally {
233+ chatStateNotifier.finalizeMessage(llmMessage.id);
228234 }
229235 }
230236 }
@@ -654,7 +660,7 @@ steps:
654660 patch-u : |
655661 --- b/colorist/step_05/lib/services/gemini_chat_service.dart
656662 +++ a/colorist/step_05/lib/services/gemini_chat_service.dart
657- @@ -12 ,6 +12 ,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
663+ @@ -11 ,6 +11 ,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
658664 import 'package:riverpod_annotation/riverpod_annotation.dart';
659665
660666 import '../providers/gemini.dart';
@@ -665,7 +671,7 @@ steps:
665671 @@ -31,6 +32,13 @@ class GeminiChatService {
666672 final responseText = response.text?.trim() ?? 'No text response received';
667673 logStateNotifier.logLlmText(responseText);
668- chatStateNotifier.addLlmMessage(responseText, MessageState.complete );
674+ chatStateNotifier.appendToMessage(llmMessage.id, responseText );
669675 +
670676 + if (response.functionCalls.isNotEmpty) {
671677 + final geminiTools = ref.read(geminiToolsProvider);
@@ -675,7 +681,7 @@ steps:
675681 + }
676682 } catch (e, st) {
677683 logStateNotifier.logError(e, st: st);
678- }
684+ chatStateNotifier.appendToMessage(
679685 - name : Patch lib/services/gemini_tools.dart
680686 path : colorist/lib/services/gemini_tools.dart
681687 patch-u : |
@@ -750,7 +756,117 @@ steps:
750756 steps :
751757 - name : Remove generated code
752758 rmdir : step_06
753-
759+ - name : Patch lib/services/gemini_chat_service.dart
760+ path : colorist/lib/services/gemini_chat_service.dart
761+ patch-u : |
762+ --- b/colorist/step_06/lib/services/gemini_chat_service.dart
763+ +++ a/colorist/step_06/lib/services/gemini_chat_service.dart
764+ @@ -4,6 +4,7 @@
765+
766+ import 'dart:async';
767+
768+ +import 'package:colorist_ui/models/conversation_state.dart';
769+ import 'package:colorist_ui/providers/chat_state_notifier.dart';
770+ import 'package:colorist_ui/providers/log_state_notifier.dart';
771+ import 'package:firebase_vertexai/firebase_vertexai.dart';
772+ @@ -15,29 +16,41 @@ import 'gemini_tools.dart';
773+
774+ part 'gemini_chat_service.g.dart';
775+
776+ +final conversationStateProvider = StateProvider(
777+ + (ref) => ConversationState.idle,
778+ +);
779+ +
780+ class GeminiChatService {
781+ GeminiChatService(this.ref);
782+ final Ref ref;
783+
784+ Future<void> sendMessage(String message) async {
785+ final chatSession = await ref.read(chatSessionProvider.future);
786+ + final conversationState = ref.read(conversationStateProvider);
787+ final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
788+ final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
789+
790+ + if (conversationState == ConversationState.busy) {
791+ + logStateNotifier.logWarning(
792+ + "Can't send a message while a conversation is in progress",
793+ + );
794+ + throw Exception(
795+ + "Can't send a message while a conversation is in progress",
796+ + );
797+ + }
798+ + final conversationStateNotifier = ref.read(
799+ + conversationStateProvider.notifier,
800+ + );
801+ + conversationStateNotifier.state = ConversationState.busy;
802+ chatStateNotifier.addUserMessage(message);
803+ logStateNotifier.logUserText(message);
804+ final llmMessage = chatStateNotifier.createLlmMessage();
805+ try {
806+ - final response = await chatSession.sendMessage(Content.text(message));
807+ - final responseText = response.text?.trim() ?? 'No text response received';
808+ - logStateNotifier.logLlmText(responseText);
809+ - chatStateNotifier.appendToMessage(llmMessage.id, responseText);
810+ -
811+ - if (response.functionCalls.isNotEmpty) {
812+ - final geminiTools = ref.read(geminiToolsProvider);
813+ - for (final functionCall in response.functionCalls) {
814+ - geminiTools.handleFunctionCall(functionCall.name, functionCall.args);
815+ - }
816+ + final responseStream = chatSession.sendMessageStream(
817+ + Content.text(message),
818+ + );
819+ + await for (final block in responseStream) {
820+ + _processBlock(block, llmMessage.id);
821+ }
822+ } catch (e, st) {
823+ logStateNotifier.logError(e, st: st);
824+ @@ -47,6 +60,24 @@ class GeminiChatService {
825+ );
826+ } finally {
827+ chatStateNotifier.finalizeMessage(llmMessage.id);
828+ + conversationStateNotifier.state = ConversationState.idle;
829+ + }
830+ + }
831+ +
832+ + void _processBlock(GenerateContentResponse block, String llmMessageId) {
833+ + var blockText = block.text;
834+ + if (blockText != null) {
835+ + final chatStateNotifier = ref.read(chatStateNotifierProvider.notifier);
836+ + final logStateNotifier = ref.read(logStateNotifierProvider.notifier);
837+ + logStateNotifier.logLlmText(blockText);
838+ + chatStateNotifier.appendToMessage(llmMessageId, blockText);
839+ + }
840+ +
841+ + if (block.functionCalls.isNotEmpty) {
842+ + final geminiTools = ref.read(geminiToolsProvider);
843+ + for (final functionCall in block.functionCalls) {
844+ + geminiTools.handleFunctionCall(functionCall.name, functionCall.args);
845+ + }
846+ }
847+ }
848+ }
849+ - name : Patch lib/main.dart
850+ path : colorist/lib/main.dart
851+ patch-u : |
852+ --- b/colorist/step_06/lib/main.dart
853+ +++ a/colorist/step_06/lib/main.dart
854+ @@ -33,6 +33,7 @@ class MainApp extends ConsumerWidget {
855+ @override
856+ Widget build(BuildContext context, WidgetRef ref) {
857+ final model = ref.watch(geminiModelProvider);
858+ + final conversationState = ref.watch(conversationStateProvider);
859+
860+ return MaterialApp(
861+ theme: ThemeData(
862+ @@ -41,6 +42,7 @@ class MainApp extends ConsumerWidget {
863+ home: model.when(
864+ data:
865+ (data) => MainScreen(
866+ + conversationState: conversationState,
867+ sendMessage: (text) {
868+ ref.read(geminiChatServiceProvider).sendMessage(text);
869+ },
754870 - name : Run build_runner
755871 path : colorist
756872 dart : run build_runner build --delete-conflicting-outputs
0 commit comments