-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor chat screen using clean architecture
- Loading branch information
1 parent
9c14443
commit e67079e
Showing
26 changed files
with
625 additions
and
369 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import 'package:swiftcomp/data/core/chat_config.dart'; | ||
|
||
class ApiConstants { | ||
static const String baseUrl = 'https://api.openai.com/v1'; | ||
static const String chatEndpoint = '$baseUrl/chat/completions'; | ||
static String apiKey = ChatConfig.apiKey; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class NetworkException implements Exception { | ||
final String message; | ||
|
||
NetworkException(this.message); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import 'dart:convert'; | ||
import 'package:http/http.dart' as http; | ||
import '../../domain/entities/chat_session.dart'; | ||
import '../../domain/entities/message.dart'; | ||
import '../core/api_constants.dart'; | ||
import '../core/network_exceptions.dart'; | ||
|
||
abstract class ChatRemoteDataSource { | ||
Stream<String> sendMessages(List<Message> messages); | ||
} | ||
|
||
class ChatRemoteDataSourceImpl implements ChatRemoteDataSource { | ||
final http.Client client; | ||
|
||
ChatRemoteDataSourceImpl({required this.client}); | ||
|
||
@override | ||
Stream<String> sendMessages(List<Message> messages) async* { | ||
final request = http.Request('POST', Uri.parse(ApiConstants.chatEndpoint)) | ||
..headers.addAll({ | ||
'Content-Type': 'application/json', | ||
'Authorization': 'Bearer ${ApiConstants.apiKey}', | ||
}) | ||
..body = jsonEncode({ | ||
"model": "gpt-4o", | ||
"stream": true, | ||
'messages': messages, | ||
}); | ||
|
||
final response = await client.send(request); | ||
|
||
if (response.statusCode == 200) { | ||
final utf8DecodedStream = response.stream.transform(utf8.decoder); | ||
String buffer = ''; | ||
|
||
await for (var chunk in utf8DecodedStream) { | ||
buffer += chunk; | ||
List<String> lines = buffer.split('\n'); | ||
buffer = lines.removeLast(); | ||
|
||
for (var line in lines) { | ||
if (line.startsWith('data:')) { | ||
var jsonString = line.replaceFirst('data: ', '').trim(); | ||
|
||
if (jsonString == '[DONE]') { | ||
return; | ||
} | ||
|
||
try { | ||
final data = jsonDecode(jsonString); | ||
final content = data['choices'][0]['delta']['content'] ?? ''; | ||
if (content.isNotEmpty) { | ||
yield content; | ||
} | ||
} catch (_) { | ||
// Handle JSON parsing errors | ||
continue; | ||
} | ||
} | ||
} | ||
} | ||
} else { | ||
throw NetworkException('Failed to send message: ${response.statusCode}'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import '../../domain/entities/chat_session.dart'; | ||
import '../../domain/entities/message.dart'; | ||
import '../../domain/repositories_abstract/chat_repository.dart'; | ||
import '../data_sources/chat_remote_data_source.dart'; | ||
|
||
class ChatRepositoryImp implements ChatRepository { | ||
final ChatRemoteDataSource remoteDataSource; | ||
|
||
ChatRepositoryImp({required this.remoteDataSource}); | ||
|
||
@override | ||
Stream<String> sendMessages(List<Message> messages) { | ||
return remoteDataSource.sendMessages(messages); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import '../../domain/entities/chat_session.dart'; | ||
import '../../domain/repositories_abstract/chat_session_repository.dart'; | ||
|
||
class ChatSessionRepositoryImpl implements ChatSessionRepository { | ||
@override | ||
Future<List<ChatSession>> getAllSessions() async { | ||
// Fetch sessions from data source (e.g., local storage, API) | ||
return []; | ||
} | ||
|
||
@override | ||
Future<void> createSession(ChatSession session) async { | ||
// Create session to a data source | ||
} | ||
|
||
@override | ||
Future<void> saveSession(ChatSession session) async { | ||
// Save session to a data source | ||
} | ||
|
||
@override | ||
Future<void> deleteSession(String id) async { | ||
// Delete session from data source | ||
} | ||
|
||
@override | ||
Future<ChatSession?> selectSession(String id) async { | ||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import 'message.dart'; | ||
|
||
class ChatSession { | ||
final String id; | ||
final String title; | ||
List<Message> messages; | ||
|
||
// Constructor | ||
ChatSession({ | ||
required this.id, | ||
required this.title, | ||
List<Message>? messages, // Optional parameter for messages | ||
}) : messages = messages ?? []; // Initialize messages as an empty list if null | ||
|
||
factory ChatSession.fromJson(Map<String, dynamic> json) { | ||
var messagesJson = json['messages'] as List; | ||
List<Message> messages = messagesJson.map((msg) => Message.fromJson(msg)).toList(); | ||
|
||
return ChatSession( | ||
id: json['id'], | ||
title: json['title'], | ||
messages: messages, | ||
); | ||
} | ||
|
||
Map<String, dynamic> toJson() { | ||
return { | ||
'id': id, | ||
'title': title, | ||
'messages': messages.map((msg) => (msg as Message).toJson()).toList(), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
class Message { | ||
final String role; | ||
String content; | ||
|
||
Message({required this.role, required this.content}); | ||
|
||
// Factory constructor for creating a new Message instance from JSON | ||
factory Message.fromJson(Map<String, dynamic> json) { | ||
return Message( | ||
role: json['role'], | ||
content: json['content'], | ||
); | ||
} | ||
|
||
// Method for converting a Message instance to JSON format | ||
Map<String, dynamic> toJson() { | ||
return { | ||
'role': role, | ||
'content': content, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import '../entities/message.dart'; | ||
|
||
abstract class ChatRepository { | ||
Stream<String> sendMessages(List<Message> messages); | ||
} |
9 changes: 9 additions & 0 deletions
9
lib/domain/repositories_abstract/chat_session_repository.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import '../entities/chat_session.dart'; | ||
|
||
abstract class ChatSessionRepository { | ||
Future<List<ChatSession>> getAllSessions(); // Fetch sessions from a data source | ||
Future<void> createSession(ChatSession session); | ||
Future<void> saveSession(ChatSession session); | ||
Future<void> deleteSession(String id); | ||
Future<ChatSession?> selectSession(String id); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import '../entities/chat_session.dart'; | ||
import '../entities/message.dart'; | ||
import '../repositories_abstract/chat_session_repository.dart'; | ||
|
||
class ChatSessionUseCase { | ||
final ChatSessionRepository repository; | ||
|
||
ChatSessionUseCase(this.repository); | ||
|
||
Future<List<ChatSession>> getAllSessions() async { | ||
return repository.getAllSessions(); | ||
} | ||
|
||
Future<void> saveSession(ChatSession session) async { | ||
// You can add business rules here (e.g., session validation) | ||
repository.saveSession(session); | ||
} | ||
|
||
Future<void> deleteSession(String sessionId) async { | ||
repository.deleteSession(sessionId); | ||
} | ||
|
||
@override | ||
Future<void> createSession(ChatSession session) async { | ||
repository.createSession(session); | ||
} | ||
|
||
void addMessageToSession(ChatSession session, Message message) { | ||
session.messages.add(message); | ||
saveSession(session); | ||
} | ||
|
||
// Check if the last message in the session is from the assistant | ||
bool isLastMessageAssistInSession(ChatSession session) { | ||
final messages = session.messages; | ||
if (messages != null && messages.isNotEmpty) { | ||
return messages.last.role == 'assistant'; | ||
} | ||
return false; | ||
} | ||
|
||
// Add a new method to update the last assistant message | ||
void updateLastAssistantMessage(ChatSession session, String token) { | ||
// Find the last message that is from the assistant | ||
for (var i = session.messages.length - 1; i >= 0; i--) { | ||
if (session.messages[i].role == 'assistant') { | ||
final previousContent = session.messages[i].content; | ||
session.messages[i] = Message(role: 'assistant', content: previousContent + token); | ||
break; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import '../entities/message.dart'; | ||
import '../repositories_abstract/chat_repository.dart'; | ||
|
||
class ChatUseCase { | ||
final ChatRepository repository; | ||
|
||
ChatUseCase(this.repository); | ||
|
||
Stream<String> sendMessages(List<Message> messages) { | ||
return repository.sendMessages(messages); | ||
} | ||
} |
Oops, something went wrong.