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

Create thread run repository and usecase #89

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

Expand Down
3 changes: 1 addition & 2 deletions lib/presentation/chat/views/composites_tools.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import '../../settings/views/apply_expert_page.dart';
import '../../settings/views/login_page.dart';
import '../../settings/views/user_profile_page.dart';
import '../viewModels/chat_view_model.dart';
import 'aitool_creation.dart';
import 'chat_screen.dart';
import 'composites_tool_creation.dart';

class CompositesTools extends StatefulWidget {
@override
Expand Down
57 changes: 57 additions & 0 deletions packages/data/lib/repositories/assistants_repository_impl.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:convert';
import 'dart:io';

import 'package:domain/entities/assistant.dart';
import 'package:http/http.dart' as http;

import 'package:domain/repositories_abstract/assistants_repository.dart';

import '../utils/api_constants.dart';

class AssistantsRepositoryImp implements AssistantsRepository {
final http.Client client;

AssistantsRepositoryImp(
{required this.client});

@override
Future<Assistant> createCompositeAssistant() async {
final request =
http.Request('POST', Uri.parse(ApiConstants.assistantsEndpoint))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
})
..body = jsonEncode({
"model": "gpt-4o",
"name": "Composites AI",
'description':
"You are an expert in composite materials and structures. Please answer questions related to composites simulation, design and manufacturing."
});

// 2. Send the request
final http.StreamedResponse streamedResponse = await client.send(request);
final String responseBody = await streamedResponse.stream.bytesToString();

// 3. Handle success or throw an error
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
return Assistant.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to create assistant. '
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
);
}
}

@override
String getCompositeAssistantId() {
return "asst_pxUDI3A9Q8afCqT9cqgUkWQP";
}
}
82 changes: 75 additions & 7 deletions packages/data/lib/repositories/messages_repository_impl.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'dart:convert';
import 'dart:io';

import 'package:domain/entities/assistant_message.dart';
import 'package:domain/entities/message.dart';
import 'package:domain/entities/thread.dart';
import 'package:domain/entities/thread_message.dart';
import 'package:domain/repositories_abstract/messages_repository.dart';
import 'package:http/http.dart' as http;

Expand All @@ -15,17 +13,17 @@ class MessagesRepositoryImp implements MessagesRepository {
MessagesRepositoryImp({required this.client});

@override
Future<AssistantMessage> createMessage(Thread thread, Message message) async {
Future<ThreadMessage> createMessage(String threadId, String message) async {
final request = http.Request('POST',
Uri.parse(ApiConstants.threadsEndpoint + "/${thread.id}/messages"))
Uri.parse("${ApiConstants.threadsEndpoint}/$threadId/messages"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
})
..body = jsonEncode({
"role": "user",
"content": message.content,
"content": message,
});

// 2. Send the request
Expand All @@ -36,7 +34,7 @@ class MessagesRepositoryImp implements MessagesRepository {
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
return AssistantMessage.fromJson(jsonResponse);
return ThreadMessage.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
Expand All @@ -47,4 +45,74 @@ class MessagesRepositoryImp implements MessagesRepository {
);
}
}

@override
Future<List<ThreadMessage>> listMessage(String threadId) async {
final request = http.Request('GET',
Uri.parse("${ApiConstants.threadsEndpoint}/$threadId/messages"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
});

// 2. Send the request
final http.StreamedResponse streamedResponse = await client.send(request);
final String responseBody = await streamedResponse.stream.bytesToString();

// 3. Handle success or throw an error
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);

final List<dynamic> data = jsonResponse['data'];

// Map each JSON object to an AssistantMessage
final List<ThreadMessage> messages = data
.map((jsonItem) =>
ThreadMessage.fromJson(jsonItem as Map<String, dynamic>))
.toList();

return messages;
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to list messages.'
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
);
}
}

@override
Future<ThreadMessage> retrieveMessage(String threadId, String messageId) async {
final request = http.Request('GET',
Uri.parse("${ApiConstants.threadsEndpoint}/$threadId/messages/$messageId"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
});

// 2. Send the request
final http.StreamedResponse streamedResponse = await client.send(request);
final String responseBody = await streamedResponse.stream.bytesToString();

// 3. Handle success or throw an error
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);

return ThreadMessage.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to list messages.'
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,34 +1,30 @@
import 'dart:convert';
import 'dart:io';

import 'package:domain/entities/assistant.dart';
import 'package:domain/entities/thread.dart';
import 'package:domain/entities/thread_message.dart';
import 'package:domain/entities/thread_run.dart';
import 'package:domain/repositories_abstract/thread_runs_repository.dart';
import 'package:http/http.dart' as http;

import 'package:domain/repositories_abstract/assistant_repository.dart';

import '../utils/api_constants.dart';

class AssistantRepositoryImp implements AssistantRepository {
class ThreadRunsRepositoryImp implements ThreadRunsRepository {
final http.Client client;

AssistantRepositoryImp(
{required this.client});
ThreadRunsRepositoryImp({required this.client});

@override
Future<Assistant> createCompositeAssistant() async {
Future<ThreadRun> createRun(Assistant assistant) async {
final request =
http.Request('POST', Uri.parse(ApiConstants.assistantsEndpoint))
http.Request('POST', Uri.parse("${ApiConstants.threadsEndpoint}/runs"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
})
..body = jsonEncode({
"model": "gpt-4o",
"name": "Composites AI",
'description':
"You are an expert in composite materials and structures. Please answer questions related to composites simulation, design and manufacturing."
"assistant_id": assistant.id,
});

// 2. Send the request
Expand All @@ -39,31 +35,35 @@ class AssistantRepositoryImp implements AssistantRepository {
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
return Assistant.fromJson(jsonResponse);
return ThreadRun.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to create assistant. '
'Failed to thread run.'
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
);
}
}

@override
String getCompositeAssistantId() {
return "asst_pxUDI3A9Q8afCqT9cqgUkWQP";
}

@override
Future<Thread> createThread() async {
Future<ThreadRun> createMessageAndRun(
Assistant assistant, String message) async {
final request =
http.Request('POST', Uri.parse(ApiConstants.threadsEndpoint))
http.Request('POST', Uri.parse("${ApiConstants.threadsEndpoint}/runs"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
})
..body = jsonEncode({
"assistant_id": assistant.id,
"thread": {
"messages": [
{"role": "user", "content": message}
]
}
});

// 2. Send the request
Expand All @@ -74,11 +74,11 @@ class AssistantRepositoryImp implements AssistantRepository {
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
return Thread.fromJson(jsonResponse);
return ThreadRun.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to create a thread. '
'Failed to thread run.'
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
Expand Down
31 changes: 31 additions & 0 deletions packages/data/lib/repositories/threads_repository_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,35 @@ class ThreadsRepositoryImp implements ThreadsRepository {
);
}
}

@override
Future<Thread> retrieveThread(String threadId) async {
final request =
http.Request('POST', Uri.parse("${ApiConstants.threadsEndpoint}/$threadId"))
..headers.addAll({
'Content-Type': 'application/json',
'Authorization': 'Bearer ${ApiConstants.apiKey}',
'OpenAI-Beta': 'assistants=v2',
});

// 2. Send the request
final http.StreamedResponse streamedResponse = await client.send(request);
final String responseBody = await streamedResponse.stream.bytesToString();

// 3. Handle success or throw an error
if (streamedResponse.statusCode == 200 ||
streamedResponse.statusCode == 201) {
final Map<String, dynamic> jsonResponse = jsonDecode(responseBody);
return Thread.fromJson(jsonResponse);
} else {
// Provide as much detail as possible for debugging
throw HttpException(
'Failed to retrieve a thread. '
'Status: ${streamedResponse.statusCode}, '
'Response: $responseBody',
uri: request.url,
);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class AssistantMessage {
class ThreadMessage {
final String id;
final String object;
final int createdAt;
Expand All @@ -10,7 +10,7 @@ class AssistantMessage {
final List<dynamic> attachments;
final Map<String, dynamic> metadata;

AssistantMessage({
ThreadMessage({
required this.id,
required this.object,
required this.createdAt,
Expand All @@ -23,15 +23,15 @@ class AssistantMessage {
required this.metadata,
});

factory AssistantMessage.fromJson(Map<String, dynamic> json) {
factory ThreadMessage.fromJson(Map<String, dynamic> json) {
var contentList = <Content>[];
if (json['content'] != null) {
contentList = (json['content'] as List)
.map((i) => Content.fromJson(i))
.toList();
}

return AssistantMessage(
return ThreadMessage(
id: json['id'],
object: json['object'],
createdAt: json['created_at'],
Expand Down
Loading
Loading