Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate Continuous Mode in Chat System #5167

Merged
merged 9 commits into from
Sep 6, 2023
5 changes: 4 additions & 1 deletion frontend/lib/models/step_request_body.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
class StepRequestBody {
final String input;
final String? input;
final Map<String, dynamic>? additionalInput;

StepRequestBody({required this.input, this.additionalInput});

Map<String, dynamic> toJson() {
if (input == null && additionalInput == null) {
return {};
}
return {'input': input, 'additional_input': additionalInput};
}
}
34 changes: 24 additions & 10 deletions frontend/lib/viewmodels/chat_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ class ChatViewModel with ChangeNotifier {
List<Chat> _chats = [];
String? _currentTaskId;

bool _isContinuousMode = false;

bool get isContinuousMode => _isContinuousMode;
set isContinuousMode(bool value) {
_isContinuousMode = value;
notifyListeners();
}

ChatViewModel(this._chatService);

/// Returns the current list of chats.
Expand Down Expand Up @@ -95,7 +103,7 @@ class ChatViewModel with ChangeNotifier {
}

/// Sends a chat message for a specific task.
void sendChatMessage(String message) async {
void sendChatMessage(String? message) async {
if (_currentTaskId == null) {
print("Error: Task ID is not set.");
return;
Expand All @@ -112,13 +120,17 @@ class ChatViewModel with ChangeNotifier {
Step executedStep = Step.fromMap(executedStepResponse);

// Create a Chat object for the user message
final userChat = Chat(
id: executedStep.stepId,
taskId: executedStep.taskId,
message: executedStep.input,
timestamp: DateTime.now(),
messageType: MessageType.user,
);
if (executedStep.input.isNotEmpty) {
final userChat = Chat(
id: executedStep.stepId,
taskId: executedStep.taskId,
message: executedStep.input,
timestamp: DateTime.now(),
messageType: MessageType.user,
);

_chats.add(userChat);
}

// Create a Chat object for the agent message
final agentChat = Chat(
Expand All @@ -129,13 +141,15 @@ class ChatViewModel with ChangeNotifier {
messageType: MessageType.agent,
jsonResponse: executedStepResponse);

// Add the user and agent chats to the list
_chats.add(userChat);
_chats.add(agentChat);

// Notify UI of the new chats
notifyListeners();

if (_isContinuousMode) {
sendChatMessage(null);
}

print("Chats added for task ID: $_currentTaskId");
} catch (error) {
// TODO: Bubble up errors to UI
Expand Down
7 changes: 7 additions & 0 deletions frontend/lib/viewmodels/task_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,11 @@ class TaskViewModel with ChangeNotifier {
throw ArgumentError(errorMessage);
}
}

/// Deselects the currently selected task.
void deselectTask() {
_selectedTask = null;
print("Deselected the current task.");
notifyListeners(); // Notify listeners to rebuild UI
}
}
68 changes: 58 additions & 10 deletions frontend/lib/views/chat/chat_input_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import 'package:flutter/material.dart';
class ChatInputField extends StatefulWidget {
// Callback to be triggered when the send button is pressed
final Function(String) onSendPressed;
final Function() onContinuousModePressed;
final bool isContinuousMode;

const ChatInputField({
Key? key,
required this.onSendPressed,
required this.onContinuousModePressed,
this.isContinuousMode = false,
}) : super(key: key);

@override
Expand All @@ -16,6 +20,23 @@ class ChatInputField extends StatefulWidget {
class _ChatInputFieldState extends State<ChatInputField> {
// Controller for the TextField to manage its content
final TextEditingController _controller = TextEditingController();
final FocusNode _focusNode = FocusNode();

@override
void initState() {
super.initState();
_focusNode.addListener(() {
if (_focusNode.hasFocus && widget.isContinuousMode) {
widget.onContinuousModePressed();
}
});
}

@override
void dispose() {
_focusNode.dispose(); // Dispose of the FocusNode when you're done.
super.dispose();
}

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -51,21 +72,48 @@ class _ChatInputFieldState extends State<ChatInputField> {
reverse: true,
child: TextField(
controller: _controller,
focusNode: _focusNode,
// Allowing the TextField to expand vertically and accommodate multiple lines
maxLines: null,
decoration: InputDecoration(
hintText: 'Type a message...',
border: InputBorder.none,
suffixIcon: IconButton(
splashRadius: 0.1,
icon: const Icon(Icons.send),
onPressed: () {
// TODO: We allow empty messages?
if (_controller.text.isNotEmpty) {
widget.onSendPressed(_controller.text);
_controller.clear();
}
},
suffixIcon: Row(
mainAxisSize: MainAxisSize.min, // Set to minimum space
children: [
if (!widget.isContinuousMode)
Tooltip(
message: 'Send a single message',
child: IconButton(
splashRadius: 0.1,
icon: const Icon(Icons.send),
onPressed: () {
widget.onSendPressed(_controller.text);
_controller.clear();
},
),
),
// TODO: Include pop up to explain continuous mode reprecussions
Tooltip(
message: widget.isContinuousMode
? ''
: 'Enable continuous mode',
child: IconButton(
splashRadius: 0.1,
icon: Icon(widget.isContinuousMode
? Icons.pause
: Icons.fast_forward),
onPressed: () {
if (!widget.isContinuousMode) {
widget.onSendPressed(_controller.text);
_controller.clear();
_focusNode.unfocus();
}
widget.onContinuousModePressed();
},
),
)
],
),
),
),
Expand Down
11 changes: 9 additions & 2 deletions frontend/lib/views/chat/chat_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,20 @@ class _ChatViewState extends State<ChatView> {
child: ChatInputField(
onSendPressed: (message) async {
if (widget.viewModel.currentTaskId != null) {
widget.viewModel.sendChatMessage(message);
widget.viewModel
.sendChatMessage((message == "") ? null : message);
} else {
String newTaskId = await taskViewModel.createTask(message);
widget.viewModel.setCurrentTaskId(newTaskId);
widget.viewModel.sendChatMessage(message);
widget.viewModel
.sendChatMessage((message == "") ? null : message);
}
},
onContinuousModePressed: () {
widget.viewModel.isContinuousMode =
!widget.viewModel.isContinuousMode;
},
isContinuousMode: widget.viewModel.isContinuousMode,
),
),
],
Expand Down
1 change: 1 addition & 0 deletions frontend/lib/views/task/task_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class _TaskViewState extends State<TaskView> {
final chatViewModel =
Provider.of<ChatViewModel>(context, listen: false);
chatViewModel.clearCurrentTaskAndChats();
widget.viewModel.deselectTask();
print(
'New Task button pressed, cleared current task ID and chats');
},
Expand Down
Loading