Added Artifact Handling for Chat Messages

- Enhanced the `Chat` model to include an `artifacts` field to hold associated artifacts.
- Updated the `AgentMessageTile` widget to display the number of artifacts and added functionality to trigger artifact downloads upon button press.
- Introduced a method in `ChatViewModel` to leverage the `ChatService` for artifact downloads.
This commit is contained in:
hunteraraujo
2023-09-27 22:37:06 -07:00
parent c814fc4edd
commit b04f4e0f55
5 changed files with 75 additions and 42 deletions

View File

@@ -8,6 +8,7 @@ class Chat {
final DateTime timestamp; final DateTime timestamp;
final MessageType messageType; final MessageType messageType;
final Map<String, dynamic>? jsonResponse; final Map<String, dynamic>? jsonResponse;
final List<dynamic> artifacts;
Chat({ Chat({
required this.id, required this.id,
@@ -16,6 +17,7 @@ class Chat {
required this.timestamp, required this.timestamp,
required this.messageType, required this.messageType,
this.jsonResponse, this.jsonResponse,
required this.artifacts,
}); });
// Convert a Map (usually from JSON) to a Chat object // Convert a Map (usually from JSON) to a Chat object
@@ -27,6 +29,7 @@ class Chat {
timestamp: DateTime.parse(map['timestamp']), timestamp: DateTime.parse(map['timestamp']),
messageType: MessageType.values.firstWhere( messageType: MessageType.values.firstWhere(
(e) => e.toString() == 'MessageType.${map['messageType']}'), (e) => e.toString() == 'MessageType.${map['messageType']}'),
artifacts: List<dynamic>.from(map['artifacts'] ?? []),
); );
} }
@@ -39,7 +42,8 @@ class Chat {
taskId == other.taskId && taskId == other.taskId &&
message == other.message && message == other.message &&
timestamp == other.timestamp && timestamp == other.timestamp &&
messageType == other.messageType; messageType == other.messageType &&
artifacts == other.artifacts;
@override @override
int get hashCode => int get hashCode =>
@@ -47,9 +51,10 @@ class Chat {
taskId.hashCode ^ taskId.hashCode ^
message.hashCode ^ message.hashCode ^
timestamp.hashCode ^ timestamp.hashCode ^
messageType.hashCode; messageType.hashCode ^
artifacts.hashCode;
@override @override
String toString() => String toString() =>
'Chat(id: $id, taskId: $taskId, message: $message, timestamp: $timestamp, messageType: $messageType)'; 'Chat(id: $id, taskId: $taskId, message: $message, timestamp: $timestamp, messageType: $messageType, artifacts: $artifacts)'; // Added artifacts in toString method
} }

View File

@@ -8,6 +8,7 @@ class Step {
final String status; final String status;
final String output; final String output;
final Map<String, dynamic> additionalOutput; final Map<String, dynamic> additionalOutput;
// TODO: Create an actual artifact object
final List<dynamic> artifacts; final List<dynamic> artifacts;
final bool isLast; final bool isLast;

View File

@@ -73,7 +73,7 @@ class ChatViewModel with ChangeNotifier {
message: step.input, message: step.input,
timestamp: currentTimestamp, timestamp: currentTimestamp,
messageType: MessageType.user, messageType: MessageType.user,
)); artifacts: step.artifacts));
} }
// Create a Chat object for 'output' // Create a Chat object for 'output'
@@ -83,9 +83,8 @@ class ChatViewModel with ChangeNotifier {
message: step.output, message: step.output,
timestamp: currentTimestamp, timestamp: currentTimestamp,
messageType: MessageType.agent, messageType: MessageType.agent,
jsonResponse: jsonResponse: stepsJsonList[i],
stepsJsonList[i], // Include the specific step's JSON here artifacts: step.artifacts));
));
} }
// Assign the chats list // Assign the chats list
@@ -128,7 +127,7 @@ class ChatViewModel with ChangeNotifier {
message: executedStep.input, message: executedStep.input,
timestamp: DateTime.now(), timestamp: DateTime.now(),
messageType: MessageType.user, messageType: MessageType.user,
); artifacts: executedStep.artifacts);
_chats.add(userChat); _chats.add(userChat);
} }
@@ -140,7 +139,8 @@ class ChatViewModel with ChangeNotifier {
message: executedStep.output, message: executedStep.output,
timestamp: DateTime.now(), timestamp: DateTime.now(),
messageType: MessageType.agent, messageType: MessageType.agent,
jsonResponse: executedStepResponse); jsonResponse: executedStepResponse,
artifacts: executedStep.artifacts);
_chats.add(agentChat); _chats.add(agentChat);
@@ -165,4 +165,20 @@ class ChatViewModel with ChangeNotifier {
// TODO: Handle additional error scenarios or log them as required // TODO: Handle additional error scenarios or log them as required
} }
} }
/// Downloads an artifact associated with a specific chat.
///
/// [taskId] is the ID of the task.
/// [artifactId] is the ID of the artifact to be downloaded.
Future<void> downloadArtifact(String taskId, String artifactId) async {
try {
// Call the downloadArtifact method from the ChatService class
await _chatService.downloadArtifact(taskId, artifactId);
print("Artifact $artifactId downloaded successfully for task $taskId!");
} catch (error) {
print("Error downloading artifact: $error");
// TODO: Handle the error appropriately, perhaps notify the user
}
}
} }

View File

@@ -6,10 +6,12 @@ import 'package:flutter/material.dart';
class AgentMessageTile extends StatefulWidget { class AgentMessageTile extends StatefulWidget {
final Chat chat; final Chat chat;
final VoidCallback onArtifactsButtonPressed;
const AgentMessageTile({ const AgentMessageTile({
Key? key, Key? key,
required this.chat, // The agent message to be displayed required this.chat,
required this.onArtifactsButtonPressed,
}) : super(key: key); }) : super(key: key);
@override @override
@@ -22,12 +24,12 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
String jsonString = jsonEncode(widget.chat.jsonResponse); String jsonString = jsonEncode(widget.chat.jsonResponse);
int artifactsCount = widget.chat.artifacts.length;
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
double chatViewWidth = constraints.maxWidth; // Get the chat view width double chatViewWidth = constraints.maxWidth;
double tileWidth = (chatViewWidth >= 1000) double tileWidth = (chatViewWidth >= 1000) ? 900 : chatViewWidth - 40;
? 900
: chatViewWidth - 40; // Determine tile width
return Align( return Align(
alignment: Alignment.center, alignment: Alignment.center,
@@ -43,13 +45,11 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
// Container for Agent title, message, and controls
Container( Container(
constraints: const BoxConstraints(minHeight: 50), constraints: const BoxConstraints(minHeight: 50),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
// Agent title
const Text( const Text(
"Agent", "Agent",
style: TextStyle( style: TextStyle(
@@ -59,7 +59,6 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
), ),
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
// Message content
Expanded( Expanded(
child: Container( child: Container(
padding: const EdgeInsets.fromLTRB(0, 10, 20, 10), padding: const EdgeInsets.fromLTRB(0, 10, 20, 10),
@@ -69,9 +68,8 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
), ),
), ),
), ),
// Artifacts button (static for now)
ElevatedButton( ElevatedButton(
onPressed: () {}, onPressed: widget.onArtifactsButtonPressed,
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: Colors.white,
foregroundColor: Colors.black, foregroundColor: Colors.black,
@@ -80,7 +78,7 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
child: const Text("2 Artifacts"), child: Text('$artifactsCount Artifacts'),
), ),
const SizedBox(width: 20), const SizedBox(width: 20),
// Expand/Collapse button // Expand/Collapse button
@@ -91,7 +89,7 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
: Icons.keyboard_arrow_down), : Icons.keyboard_arrow_down),
onPressed: () { onPressed: () {
setState(() { setState(() {
isExpanded = !isExpanded; // Toggle expanded view isExpanded = !isExpanded;
}); });
}, },
), ),
@@ -105,10 +103,8 @@ class _AgentMessageTileState extends State<AgentMessageTile> {
child: SizedBox( child: SizedBox(
height: 200, height: 200,
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(right: 20),
right: 20), // Padding for the right side
child: JsonCodeSnippetView( child: JsonCodeSnippetView(
// JSON code snippet view
jsonString: jsonString, jsonString: jsonString,
), ),
), ),

View File

@@ -8,8 +8,6 @@ import 'package:flutter/material.dart';
import 'package:auto_gpt_flutter_client/viewmodels/chat_viewmodel.dart'; import 'package:auto_gpt_flutter_client/viewmodels/chat_viewmodel.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
// TODO: Implement artifacts
class ChatView extends StatefulWidget { class ChatView extends StatefulWidget {
final ChatViewModel viewModel; final ChatViewModel viewModel;
@@ -84,7 +82,24 @@ class _ChatViewState extends State<ChatView> {
if (chat.messageType == MessageType.user) { if (chat.messageType == MessageType.user) {
return UserMessageTile(message: chat.message); return UserMessageTile(message: chat.message);
} else { } else {
return AgentMessageTile(chat: chat); return AgentMessageTile(
chat: chat,
onArtifactsButtonPressed: () {
// TODO: Create an actual artifact object
// Loop through each artifact and download it using the artifact_id
for (var artifact in chat.artifacts) {
if (artifact is Map) {
final artifactMap = artifact.cast<String,
dynamic>(); // Cast each item to Map<String, dynamic>
final artifactId = artifactMap['artifact_id']
.toString(); // Get the artifact_id
widget.viewModel.downloadArtifact(
chat.taskId, artifactId); // Download the artifact
}
}
},
);
} }
}, },
), ),