diff --git a/lib/data/entities/character_entity.dart b/lib/data/entities/character_entity.dart index 70f2294..7aeec4e 100644 --- a/lib/data/entities/character_entity.dart +++ b/lib/data/entities/character_entity.dart @@ -1,4 +1,4 @@ -// data/entities/character_entity.dart +// data/model/character_entity.dart import 'package:floor/floor.dart'; @Entity(tableName: 'characters') diff --git a/lib/data/entities/character_quest_entity.dart b/lib/data/entities/character_quest_entity.dart index 8c3d877..29fee9c 100644 --- a/lib/data/entities/character_quest_entity.dart +++ b/lib/data/entities/character_quest_entity.dart @@ -1,4 +1,4 @@ -// data/entities/character_quest_entity.dart +// data/model/character_quest_entity.dart import 'package:floor/floor.dart'; @Entity(tableName: 'character_quests') diff --git a/lib/data/mapper/ai_response_mapper.dart b/lib/data/mapper/ai_response_mapper.dart index 734339f..8288c21 100644 --- a/lib/data/mapper/ai_response_mapper.dart +++ b/lib/data/mapper/ai_response_mapper.dart @@ -3,15 +3,15 @@ import 'package:palink_v2/data/models/ai_response/ai_response.dart'; import 'package:palink_v2/data/models/ai_response/liking_response.dart'; import 'package:palink_v2/data/models/ai_response/rejection_response.dart'; import 'package:palink_v2/data/models/chat/message_request.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; extension AIResponseMapper on AIResponse { MessageRequest toMessageRequest() { return MessageRequest( sender: false, - messageText: text, // AIResponse의 텍스트 사용 - timestamp: DateTime.now().toIso8601String(), // 현재 시간을 타임스탬프로 변환 - aiResponse: this, // AIResponse를 그대로 매핑 + messageText: text, // AIResponse의 텍스트 사용 + timestamp: DateTime.now().toIso8601String(), // 현재 시간을 타임스탬프로 변환 + aiResponse: this, // AIResponse를 그대로 매핑 ); } } @@ -20,51 +20,59 @@ extension InitialAIResponseMapper on AIResponse { MessageRequest toInitialMessageRequest() { return MessageRequest( sender: true, - messageText: text, // AIResponse의 텍스트 사용 - timestamp: DateTime.now().toIso8601String(), // 현재 시간을 타임스탬프로 변환 - aiResponse: this, // AIResponse를 그대로 매핑 + messageText: text, // AIResponse의 텍스트 사용 + timestamp: DateTime.now().toIso8601String(), // 현재 시간을 타임스탬프로 변환 + aiResponse: this, // AIResponse를 그대로 매핑 ); } } - extension InitialAIMessageResponseMapper on AIMessageResponse { AIResponse toInitialAIResponse(LikingResponse likingResponse) { return AIResponse( text: message, - feeling: likingResponse.feeling, // LikabilityResponse의 feeling을 AIResponse의 feeling으로 매핑 - affinityScore: likingResponse.likability, // 호감도 점수 매핑 + feeling: likingResponse.feeling, + // LikabilityResponse의 feeling을 AIResponse의 feeling으로 매핑 + affinityScore: likingResponse.likability, + // 호감도 점수 매핑 rejectionScore: [], - rejectionContent: [], // 거절 카테고리 리스트 그대로 매핑 - finalRejectionScore: 0, // 최종 거절 점수 (거절 카테고리 수로 계산) - finalAffinityScore: 0, // 최종 호감도 점수 그대로 사용 + rejectionContent: [], + // 거절 카테고리 리스트 그대로 매핑 + finalRejectionScore: 0, + // 최종 거절 점수 (거절 카테고리 수로 계산) + finalAffinityScore: 0, // 최종 호감도 점수 그대로 사용 ); } } extension AIMessageResponseMapper on AIMessageResponse { - AIResponse toAIResponse(LikingResponse likingResponse, RejectionResponse rejectionResponse, Character character) { + AIResponse toAIResponse(LikingResponse likingResponse, + RejectionResponse rejectionResponse, Character character) { final rejectionScores = getRejectionScoresByCharacter(character); // rejectionContent 리스트를 기반으로 rejectionScore 리스트 생성 List rejectionScoreList = rejectionResponse.rejectionContent - .map((category) => rejectionScores[category] ?? 0) // 점수를 찾고, 없으면 0으로 설정 + .map((category) => rejectionScores[category] ?? 0) // 점수를 찾고, 없으면 0으로 설정 .toList(); return AIResponse( - text: message, // ChatResponse의 텍스트를 AIResponse의 텍스트로 설정 - feeling: likingResponse.feeling, // 감정 분석 결과를 그대로 매핑 - affinityScore: likingResponse.likability, // 호감도 점수 매핑 - rejectionScore: rejectionScoreList, // 계산된 rejectionScore 리스트 - rejectionContent: rejectionResponse.rejectionContent, // 거절 카테고리 리스트 - finalRejectionScore: 0, // 계산된 최종 거절 점수 - finalAffinityScore: 0, // 최종 호감도 점수 그대로 사용 + text: message, + // ChatResponse의 텍스트를 AIResponse의 텍스트로 설정 + feeling: likingResponse.feeling, + // 감정 분석 결과를 그대로 매핑 + affinityScore: likingResponse.likability, + // 호감도 점수 매핑 + rejectionScore: rejectionScoreList, + // 계산된 rejectionScore 리스트 + rejectionContent: rejectionResponse.rejectionContent, + // 거절 카테고리 리스트 + finalRejectionScore: 0, + // 계산된 최종 거절 점수 + finalAffinityScore: 0, // 최종 호감도 점수 그대로 사용 ); } } - - Map getRejectionScoresByCharacter(Character character) { // 캐릭터별 거절 점수표를 반환하는 함수 switch (character.name) { @@ -147,4 +155,3 @@ Map getRejectionScoresByCharacter(Character character) { return {}; } } - diff --git a/lib/data/mapper/character_mapper.dart b/lib/data/mapper/character_mapper.dart index e126afe..eb26ea7 100644 --- a/lib/data/mapper/character_mapper.dart +++ b/lib/data/mapper/character_mapper.dart @@ -1,8 +1,7 @@ // data/mappers/character_mapper.dart - import 'package:palink_v2/data/entities/character_entity.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; class CharacterMapper { static Character fromEntity(CharacterEntity entity) { diff --git a/lib/data/mapper/conversation_mapper.dart b/lib/data/mapper/conversation_mapper.dart new file mode 100644 index 0000000..16f5d20 --- /dev/null +++ b/lib/data/mapper/conversation_mapper.dart @@ -0,0 +1,13 @@ +import 'package:palink_v2/data/models/chat/conversation_response.dart'; +import 'package:palink_v2/domain/model/chat/conversation.dart'; + +extension ConversationMapper on ConversationResponse { + Conversation toDomain() { + return Conversation( + conversationId: conversationId, + day: DateTime.parse(day), + userId: userId, + characterId: characterId, + ); + } +} diff --git a/lib/data/mapper/login_mapper.dart b/lib/data/mapper/login_mapper.dart index 68834d0..1a55d7c 100644 --- a/lib/data/mapper/login_mapper.dart +++ b/lib/data/mapper/login_mapper.dart @@ -1,7 +1,6 @@ // data/mappers/login_mapper.dart import 'package:palink_v2/data/models/user/user_login_request.dart'; -import 'package:palink_v2/domain/entities/auth/login_model.dart'; - +import 'package:palink_v2/domain/model/auth/login_model.dart'; extension LoginMapper on LoginModel { UserLoginRequest toData() { diff --git a/lib/data/mapper/message_response_mapper.dart b/lib/data/mapper/message_response_mapper.dart index abec917..dd65397 100644 --- a/lib/data/mapper/message_response_mapper.dart +++ b/lib/data/mapper/message_response_mapper.dart @@ -1,6 +1,5 @@ import 'package:palink_v2/data/models/chat/message_response.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; - +import 'package:palink_v2/domain/model/chat/message.dart'; extension MessageResponseMapper on MessageResponse { Message toDomain() { @@ -12,4 +11,3 @@ extension MessageResponseMapper on MessageResponse { ); } } - diff --git a/lib/data/mapper/message_util.dart b/lib/data/mapper/message_util.dart index 282dd83..a1b76ef 100644 --- a/lib/data/mapper/message_util.dart +++ b/lib/data/mapper/message_util.dart @@ -1,6 +1,5 @@ - import 'package:palink_v2/data/models/chat/message_response.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; class MessageResponseMapper { // MessageResponse를 Message로 변환하는 메서드 @@ -12,4 +11,4 @@ class MessageResponseMapper { timestamp: response.timestamp, ); } -} \ No newline at end of file +} diff --git a/lib/data/mapper/signup_mapper.dart b/lib/data/mapper/signup_mapper.dart index f132cec..3a2146f 100644 --- a/lib/data/mapper/signup_mapper.dart +++ b/lib/data/mapper/signup_mapper.dart @@ -1,6 +1,6 @@ // data/mappers/signup_mapper.dart import 'package:palink_v2/data/models/user/user_create_request.dart'; -import 'package:palink_v2/domain/entities/auth/signup_model.dart'; +import 'package:palink_v2/domain/model/auth/signup_model.dart'; extension SignupMapper on SignupModel { UserCreateRequest toData() { diff --git a/lib/data/mapper/user_mapper.dart b/lib/data/mapper/user_mapper.dart index c7a68a7..1cfe4d7 100644 --- a/lib/data/mapper/user_mapper.dart +++ b/lib/data/mapper/user_mapper.dart @@ -1,6 +1,5 @@ // data/mappers/user_mapper.dart -import 'package:palink_v2/domain/entities/user/user.dart'; - +import 'package:palink_v2/domain/model/user/user.dart'; import '../models/user/user_response.dart'; extension UserMapper on UserResponse { @@ -13,4 +12,3 @@ extension UserMapper on UserResponse { ); } } - diff --git a/lib/data/models/chat/conversation_response.dart b/lib/data/models/chat/conversation_response.dart index dda5d58..014a7ea 100644 --- a/lib/data/models/chat/conversation_response.dart +++ b/lib/data/models/chat/conversation_response.dart @@ -19,3 +19,4 @@ class ConversationResponse { factory ConversationResponse.fromJson(Map json) => _$ConversationResponseFromJson(json); Map toJson() => _$ConversationResponseToJson(this); } + diff --git a/lib/data/models/user/user_collection_request.dart b/lib/data/models/user/user_collection_request.dart index 2480225..5615910 100644 --- a/lib/data/models/user/user_collection_request.dart +++ b/lib/data/models/user/user_collection_request.dart @@ -1,4 +1,4 @@ -// data/entities/user_create_request.dart +// data/model/user_create_request.dart import 'package:json_annotation/json_annotation.dart'; part 'user_collection_request.g.dart'; diff --git a/lib/data/models/user/user_collection_response.dart b/lib/data/models/user/user_collection_response.dart index f7aa5ac..ccb4f4e 100644 --- a/lib/data/models/user/user_collection_response.dart +++ b/lib/data/models/user/user_collection_response.dart @@ -1,4 +1,4 @@ -// data/entities/user_response.dart +// data/model/user_response.dart import 'package:json_annotation/json_annotation.dart'; part 'user_collection_response.g.dart'; diff --git a/lib/data/models/user/user_create_request.dart b/lib/data/models/user/user_create_request.dart index e8a8dd5..af60a62 100644 --- a/lib/data/models/user/user_create_request.dart +++ b/lib/data/models/user/user_create_request.dart @@ -1,4 +1,4 @@ -// data/entities/user_create_request.dart +// data/model/user_create_request.dart import 'package:json_annotation/json_annotation.dart'; part 'user_create_request.g.dart'; diff --git a/lib/data/models/user/user_login_request.dart b/lib/data/models/user/user_login_request.dart index 502f43c..93eb36f 100644 --- a/lib/data/models/user/user_login_request.dart +++ b/lib/data/models/user/user_login_request.dart @@ -1,4 +1,4 @@ -// data/entities/user_create_request.dart +// data/model/user_create_request.dart import 'package:json_annotation/json_annotation.dart'; part 'user_login_request.g.dart'; diff --git a/lib/data/models/user/user_response.dart b/lib/data/models/user/user_response.dart index 27b58b7..188f565 100644 --- a/lib/data/models/user/user_response.dart +++ b/lib/data/models/user/user_response.dart @@ -1,4 +1,4 @@ -// data/entities/user_response.dart +// data/model/user_response.dart import 'package:json_annotation/json_annotation.dart'; part 'user_response.g.dart'; diff --git a/lib/data/models/user/user_update_request.dart b/lib/data/models/user/user_update_request.dart index 51209c1..7ea3804 100644 --- a/lib/data/models/user/user_update_request.dart +++ b/lib/data/models/user/user_update_request.dart @@ -1,4 +1,4 @@ -// data/entities/user_create_request.dart +// data/model/user_create_request.dart import 'package:json_annotation/json_annotation.dart'; part 'user_update_request.g.dart'; diff --git a/lib/data/repository/auth_repositoryImpl.dart b/lib/data/repository/auth_repositoryImpl.dart index 3da60a2..f217799 100644 --- a/lib/data/repository/auth_repositoryImpl.dart +++ b/lib/data/repository/auth_repositoryImpl.dart @@ -1,26 +1,21 @@ - import 'package:palink_v2/data/api/auth/auth_api.dart'; import 'package:palink_v2/data/api/user/user_api.dart'; import 'package:palink_v2/data/mapper/login_mapper.dart'; import 'package:palink_v2/data/mapper/signup_mapper.dart'; import 'package:palink_v2/data/mapper/user_mapper.dart'; -import 'package:palink_v2/domain/entities/auth/login_model.dart'; -import 'package:palink_v2/domain/entities/auth/signup_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/auth/login_model.dart'; +import 'package:palink_v2/domain/model/auth/signup_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; +import 'package:palink_v2/domain/repository/auth_repository.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import '../../domain/repository/auth_repository.dart'; - - class AuthRepositoryImpl implements AuthRepository { - final AuthApi _authApi; final UserApi _userApi; final SharedPreferences _prefs; AuthRepositoryImpl(this._authApi, this._userApi, this._prefs); - @override Future login(LoginModel loginModel) async { try { @@ -70,5 +65,4 @@ class AuthRepositoryImpl implements AuthRepository { await _prefs.remove('userId'); await _prefs.remove('isLoggedIn'); } - -} \ No newline at end of file +} diff --git a/lib/data/repository/character_quest_repositoryImpl.dart b/lib/data/repository/character_quest_repositoryImpl.dart index 20c895c..8df3cc4 100644 --- a/lib/data/repository/character_quest_repositoryImpl.dart +++ b/lib/data/repository/character_quest_repositoryImpl.dart @@ -1,7 +1,7 @@ // data/repositories/character_quest_repository_impl.dart import 'package:palink_v2/data/dao/character_quest_dao.dart'; -import 'package:palink_v2/domain/entities/character/character_quest.dart'; +import 'package:palink_v2/domain/model/character/character_quest.dart'; import 'package:palink_v2/domain/repository/character_quest_repository.dart'; class CharacterQuestRepositoryImpl implements CharacterQuestRepository { @@ -12,10 +12,12 @@ class CharacterQuestRepositoryImpl implements CharacterQuestRepository { @override Future> getAllCharacterQuests() async { final entities = await characterQuestDao.getAllCharacterQuests(); - return entities.map((entity) => CharacterQuest( - characterId: entity.characterId, - quests: entity.quests.split(','), - )).toList(); + return entities + .map((entity) => CharacterQuest( + characterId: entity.characterId, + quests: entity.quests.split(','), + )) + .toList(); } @override diff --git a/lib/data/repository/character_repositoryImpl.dart b/lib/data/repository/character_repositoryImpl.dart index 686441f..ea6a826 100644 --- a/lib/data/repository/character_repositoryImpl.dart +++ b/lib/data/repository/character_repositoryImpl.dart @@ -1,7 +1,7 @@ import 'package:palink_v2/data/dao/character_dao.dart'; import 'package:palink_v2/data/mapper/character_mapper.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:palink_v2/domain/repository/character_repository.dart'; class CharacterRepositoryImpl implements CharacterRepository { diff --git a/lib/data/repository/chat_repositoryImpl.dart b/lib/data/repository/chat_repositoryImpl.dart index e63bcf1..4720967 100644 --- a/lib/data/repository/chat_repositoryImpl.dart +++ b/lib/data/repository/chat_repositoryImpl.dart @@ -1,8 +1,8 @@ - import 'package:palink_v2/data/api/chat/chat_api.dart'; import 'package:palink_v2/data/models/chat/ai_response_response.dart'; import 'package:palink_v2/data/models/chat/conversation_request.dart'; import 'package:palink_v2/data/models/chat/conversation_response.dart'; +import 'package:palink_v2/data/models/chat/conversations_response.dart'; import 'package:palink_v2/data/models/chat/message_request.dart'; import 'package:palink_v2/data/models/chat/message_response.dart'; import 'package:palink_v2/data/models/chat/messages_response.dart'; @@ -16,12 +16,14 @@ class ChatRepositoryImpl implements ChatRepository { ChatRepositoryImpl(this.chatApi); @override - Future createConversation(ConversationRequest conversationRequest) { + Future createConversation( + ConversationRequest conversationRequest) { return chatApi.createConversation(conversationRequest); } @override - Future saveMessage(int conversationId, MessageRequest messageRequest) { + Future saveMessage( + int conversationId, MessageRequest messageRequest) { return chatApi.saveMessage(conversationId, messageRequest); } @@ -31,20 +33,29 @@ class ChatRepositoryImpl implements ChatRepository { } @override - Future fetchConversationByChatRoomId(int conversationId) { + Future fetchConversationByChatRoomId( + int conversationId) { return chatApi.getConversationById(conversationId); } @override - Future> fetchAIResponseByMessageId(int conversationId, int messageId) { + Future> fetchAIResponseByMessageId( + int conversationId, int messageId) { return chatApi.getAIResponsesByMessageId(conversationId, messageId); } @override - Future> fetchAIResponsesByConversationId(int conversationId) { + Future> fetchAIResponsesByConversationId( + int conversationId) { return chatApi.getAIResponsesByConversationId(conversationId); } - + @override + Future> fetchConversationsByUserId( + int userId) async { + ConversationsResponse response = + await chatApi.getConversationsByUserId(userId); + return response + .conversations; // ConversationsResponse에서 conversations 리스트 추출 + } } - diff --git a/lib/data/repository/mindset_repositoryImpl.dart b/lib/data/repository/mindset_repositoryImpl.dart index 43b495b..8dc99ea 100644 --- a/lib/data/repository/mindset_repositoryImpl.dart +++ b/lib/data/repository/mindset_repositoryImpl.dart @@ -1,11 +1,8 @@ - - import 'package:palink_v2/data/api/mindset/mindset_api.dart'; import 'package:palink_v2/data/models/mindset/mindset_response.dart'; -import 'package:palink_v2/domain/entities/mindset/mindset.dart'; +import 'package:palink_v2/domain/model/mindset/mindset.dart'; import 'package:palink_v2/domain/repository/mindset_repository.dart'; - class MindsetRepositoryImpl implements MindsetRepository { final MindsetApi mindsetApi; @@ -15,5 +12,4 @@ class MindsetRepositoryImpl implements MindsetRepository { Future getRandomMindset() async { return mindsetApi.getRandomMindset(); } - } diff --git a/lib/data/repository/user_repositoryImpl.dart b/lib/data/repository/user_repositoryImpl.dart index f406a19..8d5a52c 100644 --- a/lib/data/repository/user_repositoryImpl.dart +++ b/lib/data/repository/user_repositoryImpl.dart @@ -1,10 +1,8 @@ - - import 'package:palink_v2/data/api/user/user_api.dart'; import 'package:palink_v2/data/models/user/user_collection_request.dart'; import 'package:palink_v2/data/models/user/user_collection_response.dart'; import 'package:palink_v2/data/models/user/user_response.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/repository/user_repository.dart'; import 'package:palink_v2/data/mapper/user_mapper.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -15,7 +13,6 @@ class UserRepositoryImpl implements UserRepository { UserRepositoryImpl(this.prefs, this._userApi); - @override int? getUserId() { return prefs.getInt('userId'); @@ -33,7 +30,8 @@ class UserRepositoryImpl implements UserRepository { } @override - Future createUserCollection(int userId, UserCollectionRequest userCollectionRequest) { - return _userApi.addUserCollection(userId, userCollectionRequest); + Future createUserCollection( + int userId, UserCollectionRequest userCollectionRequest) { + return _userApi.addUserCollection(userId, userCollectionRequest); } } diff --git a/lib/data/service/conversation_analysis_service.dart b/lib/data/service/conversation_analysis_service.dart index c3fa803..050e8a9 100644 --- a/lib/data/service/conversation_analysis_service.dart +++ b/lib/data/service/conversation_analysis_service.dart @@ -22,7 +22,7 @@ class ConversationAnalysisService { apiKey: apiKey, defaultOptions: const ChatOpenAIOptions( temperature: 0.8, - model: 'gpt-4-turbo', + model: "gpt-4o-mini", maxTokens: 300, ), ); @@ -30,7 +30,6 @@ class ConversationAnalysisService { // 프롬프트 넣기 final conversationAnalysisPrompt = ChatPromptTemplate.fromTemplate(''' 당신은 다음의 대화 기록들과 사용한 거절 방법, 미달성 퀘스트를 보고, 사용자의 대화 능력을 평가해야합니다. 부탁을 거절하는 능력을 평가하고자 합니다. - 사용자는 중학생 정도로 그들이 이해할만한 부드러운 언어로 평가합니다. 간혹가다 이모티콘도 써주세요. 대화 기록에선 사용자의 'userMessage' 에 대한 ai의 반응인 'text', 'feeling', 'affinityScore' 가 있으며, 'userMessage' 에서 사용된 거절 방법이 'rejection_content' 으로 그리고 거절 점수가 'rejection_score' 로 나타납니다. 대화 기록에서 'userMessage' 기록들을 보고 유저의 거절 능력을 평가해주세요. diff --git a/lib/data/service/rejection_service.dart b/lib/data/service/rejection_service.dart index 4b65b88..d9ab1e5 100644 --- a/lib/data/service/rejection_service.dart +++ b/lib/data/service/rejection_service.dart @@ -15,8 +15,8 @@ class RejectionService { apiKey: dotenv.env['API_KEY']!, defaultOptions: const ChatOpenAIOptions( temperature: 0.4, - model: 'gpt-3.5-turbo', - maxTokens: 200, + model: 'gpt-4o-mini', + maxTokens: 50, ), ); @@ -53,7 +53,7 @@ class RejectionService { [출력 형식] 거절 카테고리를 리스트로 반환하세요. 출력은 다음과 같은 형식으로 반환됩니다: - - 출력은 'rejectionContent' 의 json 객체입니다. + - 출력은 'rejectionContent' 의 json 객체입니다. (\```json 로 시작하는 문자열을 생성하지 마세요. 전체는 50자 이내로 출력되어야합니다.) - 'rejectionContent' 는 ["거절 카테고리1", "거절 카테고리2", ..] 등의 string 리스트입니다. '''); diff --git a/lib/data/service/response_service.dart b/lib/data/service/response_service.dart index ca8b342..a43a09a 100644 --- a/lib/data/service/response_service.dart +++ b/lib/data/service/response_service.dart @@ -29,8 +29,8 @@ class ResponseService { apiKey: apiKey, defaultOptions: const ChatOpenAIOptions( temperature: 0.8, - model: 'gpt-4-turbo', - maxTokens: 200, + model: 'gpt-4o-mini', + maxTokens: 80, ), ); @@ -81,6 +81,7 @@ class ResponseService { 'chatHistory': messageRequest.chatHistory!, }; + // Invoke the chat chain final result = await chatChain.invoke(input); // AIChatMessage 객체를 얻음 diff --git a/lib/data/service/sentiment_service.dart b/lib/data/service/sentiment_service.dart index 458979a..c9910ac 100644 --- a/lib/data/service/sentiment_service.dart +++ b/lib/data/service/sentiment_service.dart @@ -15,8 +15,8 @@ class SentimentService { apiKey: dotenv.env['API_KEY']!, defaultOptions: const ChatOpenAIOptions( temperature: 0.6, - model: 'gpt-3.5-turbo', - maxTokens: 200, + model: 'gpt-4o-mini', + maxTokens: 50, ), ); @@ -31,7 +31,7 @@ class SentimentService { user : {userMessage} [출력] - - 출력은 'feeling' 과 'likability' 의 json 객체입니다. + - 출력은 'feeling' 과 'likability' 의 json 객체입니다. (\```json 로 시작하는 문자열을 생성하지 마세요. 전체는 30자 이내로 출력되어야합니다.) - 'feeling' : 기쁨, 슬픔, 분노, 불안, 놀람, 혐오, 중립, 사랑 중 100% 중 구성된 모든 감정들을 나열합니다. 감정의 구분은 ','로 나타냅니다. (string) (ex) 기쁨 60, 중립 40) (string) - 'likability' : 9, 3, -9, -15 중 하나의 값으로 나타남 (int) diff --git a/lib/data/service/tip_service.dart b/lib/data/service/tip_service.dart index c2355e1..d8d9fbb 100644 --- a/lib/data/service/tip_service.dart +++ b/lib/data/service/tip_service.dart @@ -22,13 +22,13 @@ class TipService { apiKey: apiKey, defaultOptions: const ChatOpenAIOptions( temperature: 0.7, - model: 'gpt-3.5-turbo', - maxTokens: 200, + model: 'gpt-4o-mini', + maxTokens: 100, ), ); final rejectionPrompt = ChatPromptTemplate.fromTemplate('''[명령] -당신은 다음 설명에 해당하는 적절한 답변을 해야합니다. 답변으로 'answer', 'reason' 을 반드시 JSON 객체로 리턴하세요.(\'''로 시작하는 문자열을 생성하지 않는다) +당신은 다음 설명에 해당하는 적절한 답변을 해야합니다. 답변으로 'answer', 'reason' 을 반드시 JSON 객체로 리턴하세요.(\'''로 시작하는 문자열을 생성하지 않는다. 전체는 70자 이내로 출력하시오) 다음의 message에 대한 답변을 생성하시오. (이름을 답변에 넣지 마세요) message : {message} diff --git a/lib/di/locator.dart b/lib/di/locator.dart index 171ca4d..1a9be7a 100644 --- a/lib/di/locator.dart +++ b/lib/di/locator.dart @@ -40,6 +40,7 @@ import 'package:palink_v2/domain/usecase/generate_initial_message_usecase.dart'; import 'package:palink_v2/domain/usecase/generate_response_usecase.dart'; import 'package:palink_v2/domain/usecase/get_ai_message_usecase.dart'; import 'package:palink_v2/domain/usecase/get_ai_messages_usecase.dart'; +import 'package:palink_v2/domain/usecase/get_chatroom_by_user.dart'; import 'package:palink_v2/domain/usecase/get_random_mindset_usecase.dart'; import 'package:palink_v2/domain/usecase/get_user_info_usecase.dart'; import 'package:palink_v2/domain/usecase/save_feedback_usecase.dart'; @@ -49,6 +50,7 @@ import 'package:palink_v2/presentation/screens/auth/controller/login_view_model. import 'package:palink_v2/presentation/screens/auth/controller/signup_view_model.dart'; import 'package:palink_v2/presentation/screens/character_select/controller/character_select_viewmodel.dart'; import 'package:palink_v2/presentation/screens/chatting/controller/tip_viewmodel.dart'; +import 'package:palink_v2/presentation/screens/mypage/controller/myfeedbacks_viewmodel.dart'; import 'package:palink_v2/presentation/screens/mypage/controller/mypage_viewmodel.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../data/repository/mindset_repositoryImpl.dart'; @@ -137,6 +139,7 @@ void _setupUseCases() { getIt.registerFactory(() => GetAIMessagesUsecase()); getIt.registerFactory(() => GetAIMessageUsecase()); getIt.registerFactory(() => SaveFeedbackUseCase()); + getIt.registerFactory(() => GetChatroomByUser(getIt(), getIt())); } @@ -147,6 +150,7 @@ void _setupViewModels() { getIt.registerFactory(() => MypageViewModel(getUserInfoUseCase: getIt())); getIt.registerLazySingleton(() => CharacterSelectViewModel(fetchCharactersUsecase: getIt())); getIt.registerFactory(() => TipViewModel()); + getIt.registerFactory(() => MyfeedbacksViewmodel()); } Future _setupDatabase() async { diff --git a/lib/domain/entities/analysis/analysis_dto.dart b/lib/domain/model/analysis/analysis_dto.dart similarity index 100% rename from lib/domain/entities/analysis/analysis_dto.dart rename to lib/domain/model/analysis/analysis_dto.dart diff --git a/lib/domain/entities/analysis/analysis_dto.g.dart b/lib/domain/model/analysis/analysis_dto.g.dart similarity index 100% rename from lib/domain/entities/analysis/analysis_dto.g.dart rename to lib/domain/model/analysis/analysis_dto.g.dart diff --git a/lib/domain/entities/auth/login_model.dart b/lib/domain/model/auth/login_model.dart similarity index 78% rename from lib/domain/entities/auth/login_model.dart rename to lib/domain/model/auth/login_model.dart index e8cda12..abbe413 100644 --- a/lib/domain/entities/auth/login_model.dart +++ b/lib/domain/model/auth/login_model.dart @@ -1,4 +1,4 @@ -// domain/entities/auth/login_model.dart +// domain/model/auth/login_model.dart class LoginModel { final String accountId; final String password; diff --git a/lib/domain/entities/auth/signup_model.dart b/lib/domain/model/auth/signup_model.dart similarity index 87% rename from lib/domain/entities/auth/signup_model.dart rename to lib/domain/model/auth/signup_model.dart index 23af2c1..3dcb7d3 100644 --- a/lib/domain/entities/auth/signup_model.dart +++ b/lib/domain/model/auth/signup_model.dart @@ -1,4 +1,4 @@ -// domain/entities/auth/signup_model.dart +// domain/model/auth/signup_model.dart class SignupModel { final String accountId; final String name; diff --git a/lib/domain/entities/character/character.dart b/lib/domain/model/character/character.dart similarity index 100% rename from lib/domain/entities/character/character.dart rename to lib/domain/model/character/character.dart diff --git a/lib/domain/entities/character/character.g.dart b/lib/domain/model/character/character.g.dart similarity index 100% rename from lib/domain/entities/character/character.g.dart rename to lib/domain/model/character/character.g.dart diff --git a/lib/domain/entities/character/character_quest.dart b/lib/domain/model/character/character_quest.dart similarity index 80% rename from lib/domain/entities/character/character_quest.dart rename to lib/domain/model/character/character_quest.dart index a535d40..d85145b 100644 --- a/lib/domain/entities/character/character_quest.dart +++ b/lib/domain/model/character/character_quest.dart @@ -1,4 +1,4 @@ -// domain/entities/character_quest.dart +// domain/model/character_quest.dart class CharacterQuest { final int characterId; final List quests; diff --git a/lib/domain/entities/chat/conversation.dart b/lib/domain/model/chat/conversation.dart similarity index 90% rename from lib/domain/entities/chat/conversation.dart rename to lib/domain/model/chat/conversation.dart index 15c848d..8df69df 100644 --- a/lib/domain/entities/chat/conversation.dart +++ b/lib/domain/model/chat/conversation.dart @@ -1,7 +1,7 @@ import 'package:palink_v2/data/models/chat/conversation_response.dart'; class Conversation { - String day; + DateTime day; int userId; int characterId; int conversationId; @@ -17,7 +17,7 @@ class Conversation { factory Conversation.fromResponse(ConversationResponse response) { return Conversation( conversationId: response.conversationId, - day: response.day, + day: DateTime.parse(response.day), userId: response.userId, characterId: response.characterId, ); diff --git a/lib/domain/entities/chat/message.dart b/lib/domain/model/chat/message.dart similarity index 100% rename from lib/domain/entities/chat/message.dart rename to lib/domain/model/chat/message.dart diff --git a/lib/domain/entities/emotion/emotion.dart b/lib/domain/model/emotion/emotion.dart similarity index 100% rename from lib/domain/entities/emotion/emotion.dart rename to lib/domain/model/emotion/emotion.dart diff --git a/lib/domain/entities/emotion/emotion.g.dart b/lib/domain/model/emotion/emotion.g.dart similarity index 100% rename from lib/domain/entities/emotion/emotion.g.dart rename to lib/domain/model/emotion/emotion.g.dart diff --git a/lib/domain/entities/emotion/emotion_vibration.dart b/lib/domain/model/emotion/emotion_vibration.dart similarity index 100% rename from lib/domain/entities/emotion/emotion_vibration.dart rename to lib/domain/model/emotion/emotion_vibration.dart diff --git a/lib/domain/entities/likability/likability.dart b/lib/domain/model/likability/likability.dart similarity index 100% rename from lib/domain/entities/likability/likability.dart rename to lib/domain/model/likability/likability.dart diff --git a/lib/domain/entities/likability/liking_level.dart b/lib/domain/model/likability/liking_level.dart similarity index 100% rename from lib/domain/entities/likability/liking_level.dart rename to lib/domain/model/likability/liking_level.dart diff --git a/lib/domain/entities/likability/liking_level.g.dart b/lib/domain/model/likability/liking_level.g.dart similarity index 100% rename from lib/domain/entities/likability/liking_level.g.dart rename to lib/domain/model/likability/liking_level.g.dart diff --git a/lib/domain/entities/mindset/mindset.dart b/lib/domain/model/mindset/mindset.dart similarity index 100% rename from lib/domain/entities/mindset/mindset.dart rename to lib/domain/model/mindset/mindset.dart diff --git a/lib/domain/entities/rejection/rejection.dart b/lib/domain/model/rejection/rejection.dart similarity index 100% rename from lib/domain/entities/rejection/rejection.dart rename to lib/domain/model/rejection/rejection.dart diff --git a/lib/domain/entities/tip/tip.dart b/lib/domain/model/tip/tip.dart similarity index 100% rename from lib/domain/entities/tip/tip.dart rename to lib/domain/model/tip/tip.dart diff --git a/lib/domain/entities/tip/tip.g.dart b/lib/domain/model/tip/tip.g.dart similarity index 100% rename from lib/domain/entities/tip/tip.g.dart rename to lib/domain/model/tip/tip.g.dart diff --git a/lib/domain/entities/user/user.dart b/lib/domain/model/user/user.dart similarity index 85% rename from lib/domain/entities/user/user.dart rename to lib/domain/model/user/user.dart index e715919..7489a01 100644 --- a/lib/domain/entities/user/user.dart +++ b/lib/domain/model/user/user.dart @@ -1,4 +1,4 @@ -// domain/entities/user/user.dart +// domain/model/user/user.dart class User { final String accountId; final String name; diff --git a/lib/domain/repository/auth_repository.dart b/lib/domain/repository/auth_repository.dart index bb7986d..7b40361 100644 --- a/lib/domain/repository/auth_repository.dart +++ b/lib/domain/repository/auth_repository.dart @@ -1,10 +1,11 @@ - -import 'package:palink_v2/domain/entities/auth/login_model.dart'; -import 'package:palink_v2/domain/entities/auth/signup_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/auth/login_model.dart'; +import 'package:palink_v2/domain/model/auth/signup_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; abstract class AuthRepository { Future login(LoginModel loginModel); + Future signUp(SignupModel signUpModel); + Future getUserFromPreferences(); -} \ No newline at end of file +} diff --git a/lib/domain/repository/character_quest_repository.dart b/lib/domain/repository/character_quest_repository.dart index d20c064..a565970 100644 --- a/lib/domain/repository/character_quest_repository.dart +++ b/lib/domain/repository/character_quest_repository.dart @@ -1,6 +1,4 @@ - - -import 'package:palink_v2/domain/entities/character/character_quest.dart'; +import 'package:palink_v2/domain/model/character/character_quest.dart'; abstract class CharacterQuestRepository { Future> getAllCharacterQuests(); diff --git a/lib/domain/repository/character_repository.dart b/lib/domain/repository/character_repository.dart index 975a255..48fd003 100644 --- a/lib/domain/repository/character_repository.dart +++ b/lib/domain/repository/character_repository.dart @@ -1,5 +1,5 @@ -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; abstract class CharacterRepository { Future> getCharacters(); diff --git a/lib/domain/repository/chat_repository.dart b/lib/domain/repository/chat_repository.dart index 1ac4b78..ebd6f39 100644 --- a/lib/domain/repository/chat_repository.dart +++ b/lib/domain/repository/chat_repository.dart @@ -1,4 +1,3 @@ - import 'package:palink_v2/data/models/chat/ai_response_response.dart'; import 'package:palink_v2/data/models/chat/conversation_request.dart'; import 'package:palink_v2/data/models/chat/conversation_response.dart'; @@ -7,10 +6,21 @@ import 'package:palink_v2/data/models/chat/message_response.dart'; import 'package:palink_v2/data/models/chat/messages_response.dart'; abstract class ChatRepository { - Future createConversation(ConversationRequest conversationRequest); - Future saveMessage(int conversationId, MessageRequest messageRequest); + Future createConversation( + ConversationRequest conversationRequest); + + Future saveMessage( + int conversationId, MessageRequest messageRequest); + Future fetchMessagesByChatRoomId(int chatRoomId); + Future fetchConversationByChatRoomId(int chatRoomId); - Future> fetchAIResponseByMessageId(int conversationId, int messageId); - Future> fetchAIResponsesByConversationId(int conversationId); + + Future> fetchAIResponseByMessageId( + int conversationId, int messageId); + + Future> fetchAIResponsesByConversationId( + int conversationId); + + Future> fetchConversationsByUserId(int userId); } diff --git a/lib/domain/repository/user_repository.dart b/lib/domain/repository/user_repository.dart index 8d21326..04c0afb 100644 --- a/lib/domain/repository/user_repository.dart +++ b/lib/domain/repository/user_repository.dart @@ -1,10 +1,13 @@ import 'package:palink_v2/data/models/user/user_collection_request.dart'; import 'package:palink_v2/data/models/user/user_collection_response.dart'; -import '../entities/user/user.dart'; +import '../model/user/user.dart'; abstract class UserRepository { int? getUserId(); + Future getUser(int userId); - Future createUserCollection(int userId, UserCollectionRequest userCollectionRequest); + + Future createUserCollection( + int userId, UserCollectionRequest userCollectionRequest); } diff --git a/lib/domain/usecase/create_conversation_usecase.dart b/lib/domain/usecase/create_conversation_usecase.dart index e174dd1..886367b 100644 --- a/lib/domain/usecase/create_conversation_usecase.dart +++ b/lib/domain/usecase/create_conversation_usecase.dart @@ -1,11 +1,8 @@ -// domain/usecases/create_conversation_usecase.dart - - import 'package:palink_v2/data/models/chat/conversation_request.dart'; import 'package:palink_v2/data/models/chat/conversation_response.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; -import 'package:palink_v2/domain/entities/chat/conversation.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/model/chat/conversation.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/repository/chat_repository.dart'; import 'get_user_info_usecase.dart'; @@ -23,7 +20,8 @@ class CreateConversationUseCase { userId: user!.userId!, characterId: character.characterId, ); - ConversationResponse response = await chatRepository.createConversation(conversationRequest); + ConversationResponse response = + await chatRepository.createConversation(conversationRequest); return Conversation.fromResponse(response); } } diff --git a/lib/domain/usecase/fetch_characters_usecase.dart b/lib/domain/usecase/fetch_characters_usecase.dart index 5a776ad..3dc0cf4 100644 --- a/lib/domain/usecase/fetch_characters_usecase.dart +++ b/lib/domain/usecase/fetch_characters_usecase.dart @@ -1,5 +1,4 @@ -// domain/usecase/get_characters_usecase.dart -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:palink_v2/domain/repository/character_repository.dart'; class FetchCharactersUsecase { diff --git a/lib/domain/usecase/fetch_chat_history_usecase.dart b/lib/domain/usecase/fetch_chat_history_usecase.dart index c7f6d11..068ceac 100644 --- a/lib/domain/usecase/fetch_chat_history_usecase.dart +++ b/lib/domain/usecase/fetch_chat_history_usecase.dart @@ -1,7 +1,6 @@ import 'package:palink_v2/data/mapper/message_response_mapper.dart'; -import 'package:palink_v2/data/models/chat/message_response.dart'; import 'package:palink_v2/data/models/chat/messages_response.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; import 'package:palink_v2/domain/repository/chat_repository.dart'; class FetchChatHistoryUsecase { @@ -11,11 +10,12 @@ class FetchChatHistoryUsecase { Future?> execute(int chatRoomId) async { try { - final MessagesResponse? response = await repository.fetchMessagesByChatRoomId(chatRoomId); + final MessagesResponse? response = + await repository.fetchMessagesByChatRoomId(chatRoomId); return response?.messages.map((msg) => msg.toDomain()).toList(); } catch (e) { print('Error fetching chat history: $e'); return null; } } -} \ No newline at end of file +} diff --git a/lib/domain/usecase/generate_response_usecase.dart b/lib/domain/usecase/generate_response_usecase.dart index 3aeed94..08a847c 100644 --- a/lib/domain/usecase/generate_response_usecase.dart +++ b/lib/domain/usecase/generate_response_usecase.dart @@ -8,9 +8,9 @@ import 'package:palink_v2/data/models/ai_response/rejection_response.dart'; import 'package:palink_v2/data/models/chat/ai_response_response.dart'; import 'package:palink_v2/data/models/chat/message_response.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/repository/chat_repository.dart'; import 'package:palink_v2/domain/repository/open_ai_repository.dart'; import 'package:palink_v2/presentation/screens/chatting/controller/tip_viewmodel.dart'; diff --git a/lib/domain/usecase/generate_tip_usecase.dart b/lib/domain/usecase/generate_tip_usecase.dart index 8e68649..3a8ad47 100644 --- a/lib/domain/usecase/generate_tip_usecase.dart +++ b/lib/domain/usecase/generate_tip_usecase.dart @@ -2,7 +2,7 @@ import 'package:palink_v2/data/models/ai_response/tip_request.dart'; import 'package:palink_v2/data/models/ai_response/tip_response.dart'; import 'package:palink_v2/data/models/tip/tip_create_request.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/tip/tip.dart'; +import 'package:palink_v2/domain/model/tip/tip.dart'; import 'package:palink_v2/domain/repository/open_ai_repository.dart'; import 'package:palink_v2/domain/repository/tip_repository.dart'; @@ -10,8 +10,8 @@ class GenerateTipUsecase { final OpenAIRepository aiRepository = getIt(); final TipRepository tipRepository = getIt(); - - Future execute(int messageId, String message, List unachievedQuests) async { + Future execute( + int messageId, String message, List unachievedQuests) async { TipRequest input = TipRequest( message: message, unachievedQuests: unachievedQuests, @@ -21,7 +21,8 @@ class GenerateTipUsecase { TipResponse? newTipResponse; if (tipResponse != null) { // answer와 reason을 결합하여 하나의 문자열로 만들기 - String combinedTipText = '${tipResponse.answer}\n 이유: ${tipResponse.reason}'; + String combinedTipText = + '${tipResponse.answer}\n 이유: ${tipResponse.reason}'; // TipRepository를 통해 팁 저장 tipRepository.createTip( TipCreateRequest( diff --git a/lib/domain/usecase/get_character_quest_by_id_usecase.dart b/lib/domain/usecase/get_character_quest_by_id_usecase.dart index 14cf53b..bcaf462 100644 --- a/lib/domain/usecase/get_character_quest_by_id_usecase.dart +++ b/lib/domain/usecase/get_character_quest_by_id_usecase.dart @@ -1,5 +1,4 @@ - -import 'package:palink_v2/domain/entities/character/character_quest.dart'; +import 'package:palink_v2/domain/model/character/character_quest.dart'; import 'package:palink_v2/domain/repository/character_quest_repository.dart'; class GetCharacterQuestsByIdUsecase { diff --git a/lib/domain/usecase/get_chatroom_by_user.dart b/lib/domain/usecase/get_chatroom_by_user.dart new file mode 100644 index 0000000..5fb1a96 --- /dev/null +++ b/lib/domain/usecase/get_chatroom_by_user.dart @@ -0,0 +1,25 @@ +import 'package:palink_v2/data/mapper/conversation_mapper.dart'; +import 'package:palink_v2/domain/model/chat/conversation.dart'; +import 'package:palink_v2/domain/repository/chat_repository.dart'; +import 'package:palink_v2/data/models/chat/conversation_response.dart'; +import 'package:palink_v2/domain/repository/user_repository.dart'; + +class GetChatroomByUser { + final ChatRepository chatRepository; + final UserRepository userRepository; + + GetChatroomByUser(this.chatRepository, this.userRepository); + + Future> execute() async { + int? userId = userRepository.getUserId(); + + // 서버에서 받아온 ConversationResponse 데이터를 처리하기 위해 await 사용 + List response = + await chatRepository.fetchConversationsByUserId(userId!); + + // 변환 작업 수행: List -> List + List conversations = + response.map((convResp) => convResp.toDomain()).toList(); + return conversations; + } +} diff --git a/lib/domain/usecase/get_user_info_usecase.dart b/lib/domain/usecase/get_user_info_usecase.dart index a956083..b7799cc 100644 --- a/lib/domain/usecase/get_user_info_usecase.dart +++ b/lib/domain/usecase/get_user_info_usecase.dart @@ -1,9 +1,9 @@ -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/repository/user_repository.dart'; - class GetUserInfoUseCase { final UserRepository userRepository; + GetUserInfoUseCase(this.userRepository); Future execute() async { diff --git a/lib/domain/usecase/login_usecase.dart b/lib/domain/usecase/login_usecase.dart index aefdbd9..88da846 100644 --- a/lib/domain/usecase/login_usecase.dart +++ b/lib/domain/usecase/login_usecase.dart @@ -1,6 +1,5 @@ -import 'package:palink_v2/domain/entities/auth/login_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; - +import 'package:palink_v2/domain/model/auth/login_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import '../repository/auth_repository.dart'; @@ -16,4 +15,4 @@ class LoginUseCase { Future checkAutoLogin() { return repository.getUserFromPreferences(); } -} \ No newline at end of file +} diff --git a/lib/domain/usecase/send_user_message_usecase.dart b/lib/domain/usecase/send_user_message_usecase.dart index 380d90c..d641a02 100644 --- a/lib/domain/usecase/send_user_message_usecase.dart +++ b/lib/domain/usecase/send_user_message_usecase.dart @@ -3,8 +3,8 @@ import 'package:palink_v2/data/models/ai_response/ai_response.dart'; import 'package:palink_v2/data/models/chat/message_request.dart'; import 'package:palink_v2/data/models/chat/message_response.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; import 'package:palink_v2/domain/repository/chat_repository.dart'; import 'package:palink_v2/domain/usecase/generate_response_usecase.dart'; @@ -28,27 +28,27 @@ class SendUserMessageUsecase { return _mapResponseToDomain(messageResponse); } - Future> generateAIResponse( - int chatRoomId, Character character, List unachievedQuests) async { - return await generateResponseUsecase.execute(chatRoomId, character, userMessage, unachievedQuests); + Future> generateAIResponse(int chatRoomId, + Character character, List unachievedQuests) async { + return await generateResponseUsecase.execute( + chatRoomId, character, userMessage, unachievedQuests); } // 여기서 리턴할 때 isEnd 도 반환하고 싶다. AIResponse 와 합치지 않는다. MessageRequest _createMessageRequest(String text) { return MessageRequest( - sender: true, - messageText: text, - timestamp: DateTime.now().toIso8601String(), - aiResponse: AIResponse( - text: text, - feeling: "neutral", - affinityScore: 0, - rejectionScore: [], - rejectionContent: [], - finalRejectionScore: 0, - finalAffinityScore: 0, - ) - ); + sender: true, + messageText: text, + timestamp: DateTime.now().toIso8601String(), + aiResponse: AIResponse( + text: text, + feeling: "neutral", + affinityScore: 0, + rejectionScore: [], + rejectionContent: [], + finalRejectionScore: 0, + finalAffinityScore: 0, + )); } Future _saveMessageToServer( diff --git a/lib/domain/usecase/sign_up_usecase.dart b/lib/domain/usecase/sign_up_usecase.dart index 8acbe1e..8e642b0 100644 --- a/lib/domain/usecase/sign_up_usecase.dart +++ b/lib/domain/usecase/sign_up_usecase.dart @@ -1,6 +1,5 @@ - -import 'package:palink_v2/domain/entities/auth/signup_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/auth/signup_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/repository/auth_repository.dart'; class SignUpUseCase { diff --git a/lib/main.dart b/lib/main.dart index bd81999..7fe2aaa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get/get.dart'; import 'package:get_it/get_it.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/usecase/login_usecase.dart'; import 'package:palink_v2/presentation/screens/auth/view/login_view.dart'; import 'package:palink_v2/presentation/screens/main_screens.dart'; diff --git a/lib/presentation/screens/auth/controller/login_view_model.dart b/lib/presentation/screens/auth/controller/login_view_model.dart index 4668e52..2d758d1 100644 --- a/lib/presentation/screens/auth/controller/login_view_model.dart +++ b/lib/presentation/screens/auth/controller/login_view_model.dart @@ -1,7 +1,6 @@ import 'package:get/get.dart'; -import 'package:get/get_connect/http/src/exceptions/exceptions.dart'; -import 'package:palink_v2/domain/entities/auth/login_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/auth/login_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/usecase/login_usecase.dart'; import 'package:palink_v2/presentation/screens/main_screens.dart'; @@ -22,7 +21,8 @@ class LoginViewModel extends GetxController { errorMessage.value = ''; try { - final result = await loginUseCase.execute(LoginModel(accountId: accountId, password: password)); + final result = await loginUseCase + .execute(LoginModel(accountId: accountId, password: password)); if (result != null) { user.value = result; Get.off(() => const MainScreens()); @@ -30,7 +30,7 @@ class LoginViewModel extends GetxController { _showError('로그인에 실패했습니다.'); } } catch (e) { - _showError('로그인에 실패했습니다. $e'); + _showError('로그인에 실패했습니다. $e'); } finally { isLoading.value = false; } diff --git a/lib/presentation/screens/auth/controller/signup_view_model.dart b/lib/presentation/screens/auth/controller/signup_view_model.dart index f5ba65c..bc86e35 100644 --- a/lib/presentation/screens/auth/controller/signup_view_model.dart +++ b/lib/presentation/screens/auth/controller/signup_view_model.dart @@ -1,6 +1,6 @@ import 'package:get/get.dart'; -import 'package:palink_v2/domain/entities/auth/signup_model.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/auth/signup_model.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/usecase/sign_up_usecase.dart'; import 'package:palink_v2/presentation/screens/main_screens.dart'; diff --git a/lib/presentation/screens/character_select/controller/character_select_viewmodel.dart b/lib/presentation/screens/character_select/controller/character_select_viewmodel.dart index 4fa957c..b863835 100644 --- a/lib/presentation/screens/character_select/controller/character_select_viewmodel.dart +++ b/lib/presentation/screens/character_select/controller/character_select_viewmodel.dart @@ -1,22 +1,22 @@ // presentation/screens/character_select/character_select_viewmodel.dart import 'package:get/get.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:palink_v2/domain/usecase/fetch_characters_usecase.dart'; import 'package:palink_v2/presentation/screens/chatting/controller/chat_loading_viewmodel.dart'; import 'package:palink_v2/presentation/screens/chatting/view/chat_loading_screen.dart'; - class CharacterSelectViewModel extends GetxController { final FetchCharactersUsecase fetchCharactersUsecase; var characters = [].obs; var selectedCharacter = Character( - characterId: 1, - name: 'default_name', - type: 'default_type', - image: 'default_image.png', - quest: 'default_quest', - requestStrength: 0, persona: 'default_prompt' - ).obs; + characterId: 1, + name: 'default_name', + type: 'default_type', + image: 'default_image.png', + quest: 'default_quest', + requestStrength: 0, + persona: 'default_prompt') + .obs; CharacterSelectViewModel({required this.fetchCharactersUsecase}); @@ -32,22 +32,20 @@ class CharacterSelectViewModel extends GetxController { characters.assignAll(result); } - void selectCharacter(Character character) { selectedCharacter.value = character; - Get.off(()=> - ChatLoadingScreen(viewModel: Get.put(ChatLoadingViewModel(character: character)))); + Get.off(() => ChatLoadingScreen( + viewModel: Get.put(ChatLoadingViewModel(character: character)))); } void _initSelectedCharacter() { selectedCharacter.value = Character( - characterId: 1, - name: 'default_name', - type: 'default_type', - image: 'default_image.png', - quest: 'default_quest', - requestStrength: 0, persona: 'default_prompt' - ); + characterId: 1, + name: 'default_name', + type: 'default_type', + image: 'default_image.png', + quest: 'default_quest', + requestStrength: 0, + persona: 'default_prompt'); } - } diff --git a/lib/presentation/screens/character_select/view/components/character_list.dart b/lib/presentation/screens/character_select/view/components/character_list.dart index c525e1a..9f9e681 100644 --- a/lib/presentation/screens/character_select/view/components/character_list.dart +++ b/lib/presentation/screens/character_select/view/components/character_list.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:sizing/sizing.dart'; import 'character_profile.dart'; diff --git a/lib/presentation/screens/character_select/view/components/character_profile.dart b/lib/presentation/screens/character_select/view/components/character_profile.dart index ec1a92c..64b9d09 100644 --- a/lib/presentation/screens/character_select/view/components/character_profile.dart +++ b/lib/presentation/screens/character_select/view/components/character_profile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:palink_v2/core/theme/app_fonts.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:sizing/sizing.dart'; import '../../controller/character_select_viewmodel.dart'; diff --git a/lib/presentation/screens/chatting/controller/chat_end_loading_viewmodel.dart b/lib/presentation/screens/chatting/controller/chat_end_loading_viewmodel.dart index 6e7281d..ce61089 100644 --- a/lib/presentation/screens/chatting/controller/chat_end_loading_viewmodel.dart +++ b/lib/presentation/screens/chatting/controller/chat_end_loading_viewmodel.dart @@ -1,10 +1,9 @@ -import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:palink_v2/data/models/ai_response/analysis_response.dart'; import 'package:palink_v2/data/models/chat/ai_response_response.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/analysis/analysis_dto.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; +import 'package:palink_v2/domain/model/analysis/analysis_dto.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; import 'package:palink_v2/domain/usecase/generate_analyze_usecase.dart'; import 'package:palink_v2/domain/usecase/get_ai_messages_usecase.dart'; import 'package:palink_v2/domain/usecase/get_random_mindset_usecase.dart'; @@ -12,12 +11,15 @@ import 'package:palink_v2/domain/usecase/save_feedback_usecase.dart'; import 'package:palink_v2/presentation/screens/feedback/controller/feedback_viewmodel.dart'; import 'package:palink_v2/presentation/screens/feedback/view/feedback_view.dart'; - class ChatEndLoadingViewModel extends GetxController { - final GetRandomMindsetUseCase getRandomMindsetUseCase = getIt(); - final GenerateAnalyzeUsecase generateAnalyzeUsecase = getIt(); - final GetAIMessagesUsecase getAIMessagesUsecase = getIt(); - final SaveFeedbackUseCase saveFeedbackUseCase = getIt(); // Add the feedback use case + final GetRandomMindsetUseCase getRandomMindsetUseCase = + getIt(); + final GenerateAnalyzeUsecase generateAnalyzeUsecase = + getIt(); + final GetAIMessagesUsecase getAIMessagesUsecase = + getIt(); + final SaveFeedbackUseCase saveFeedbackUseCase = + getIt(); // Add the feedback use case final Character character; @@ -25,7 +27,7 @@ class ChatEndLoadingViewModel extends GetxController { final mindset; final conversationId; // 채팅방 아이디 - final finalRejectionScore; // 최종 거절 점수 + final finalRejectionScore; // 최종 거절 점수 final finalAffinityScore; // 최종 호감도 점수 final unachievedQuests; // 달성하지 못한 퀘스트 리스트 @@ -40,15 +42,15 @@ class ChatEndLoadingViewModel extends GetxController { _analyzeConversation(character); } - - Future _analyzeConversation(Character character) async { try { - List chatHistory = await getAIMessagesUsecase.execute(conversationId); + List chatHistory = + await getAIMessagesUsecase.execute(conversationId); // chatHistory 내의 각 AIResponseResponse 객체를 적절히 변환하여 하나의 문자열로 만듭니다. final String chatHistoryString = chatHistory.map((response) { // JSArray을 List로 변환 - final List rejectionContent = List.from(response.rejectionContent); + final List rejectionContent = + List.from(response.rejectionContent); return ''' [User Message: ${response.userMessage}, AIResponse: ${response.text}, @@ -60,7 +62,8 @@ class ChatEndLoadingViewModel extends GetxController { // 미달성 퀘스트 리스트를 쉼표로 구분된 문자열로 변환 final String unachievedQuestsString = unachievedQuests.join(', '); - AnalysisResponse? response = await generateAnalyzeUsecase.execute(chatHistoryString, unachievedQuestsString, finalRejectionScore); + AnalysisResponse? response = await generateAnalyzeUsecase.execute( + chatHistoryString, unachievedQuestsString, finalRejectionScore); AnalysisDto? analysisDto = AnalysisDto( finalRejectionScore: finalRejectionScore, finalAffinityScore: finalAffinityScore, @@ -68,22 +71,25 @@ class ChatEndLoadingViewModel extends GetxController { evaluation: response!.evaluation, usedRejection: response.usedRejection, ); - if (analysisDto == null) { - return; - } - else { - await saveFeedbackUseCase.execute( - conversationId: conversationId, - feedbackText: response.evaluation, // Use evaluation text - finalLikingLevel: finalAffinityScore+50, // Adjust liking score calculation - totalRejectionScore: finalRejectionScore, // Pass final rejection score - ); + if (analysisDto == null) { + return; + } else { + await saveFeedbackUseCase.execute( + conversationId: conversationId, + feedbackText: response.evaluation, + // Use evaluation text + finalLikingLevel: finalAffinityScore + 50, + // Adjust liking score calculation + totalRejectionScore: + finalRejectionScore, // Pass final rejection score + ); - Get.off(() => FeedbackView(viewModel: Get.put(FeedbackViewmodel(analysisDto: analysisDto, character: character)))); - } + Get.off(() => FeedbackView( + viewModel: Get.put(FeedbackViewmodel( + analysisDto: analysisDto, character: character)))); + } } catch (e) { print('Failed to analyze conversation: $e'); } } - } diff --git a/lib/presentation/screens/chatting/controller/chat_loading_viewmodel.dart b/lib/presentation/screens/chatting/controller/chat_loading_viewmodel.dart index c628fb3..5640ef2 100644 --- a/lib/presentation/screens/chatting/controller/chat_loading_viewmodel.dart +++ b/lib/presentation/screens/chatting/controller/chat_loading_viewmodel.dart @@ -1,9 +1,8 @@ import 'package:get/get.dart'; -import 'package:palink_v2/data/models/ai_response/ai_response.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; -import 'package:palink_v2/domain/entities/chat/conversation.dart'; -import 'package:palink_v2/domain/entities/user/user.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/model/chat/conversation.dart'; +import 'package:palink_v2/domain/model/user/user.dart'; import 'package:palink_v2/domain/usecase/generate_initial_message_usecase.dart'; import 'package:palink_v2/domain/usecase/create_conversation_usecase.dart'; import 'package:palink_v2/presentation/screens/chatting/controller/chat_viewmodel.dart'; @@ -11,8 +10,10 @@ import 'package:palink_v2/presentation/screens/chatting/view/chat_screen.dart'; import 'package:palink_v2/domain/usecase/get_user_info_usecase.dart'; class ChatLoadingViewModel extends GetxController { - final CreateConversationUseCase createConversationUseCase = getIt(); - final GenerateInitialMessageUsecase generateInitialMessageUsecase = getIt(); + final CreateConversationUseCase createConversationUseCase = + getIt(); + final GenerateInitialMessageUsecase generateInitialMessageUsecase = + getIt(); final GetUserInfoUseCase getUserInfoUseCase = getIt(); final Character character; @@ -47,14 +48,13 @@ class ChatLoadingViewModel extends GetxController { if (conversation.value != null && user.value != null) { final conversationId = conversation.value!.conversationId; // 첫 메시지와 팁 생성 - final result = await _createInitialMessage( - conversationId, user.value!.name); + final result = + await _createInitialMessage(conversationId, user.value!.name); if (result != null) { final tip = result['tip'] as String; // ChatScreen으로 이동 (팁 전달) - Get.off(() => - ChatScreen( + Get.off(() => ChatScreen( viewModel: Get.put(ChatViewModel( chatRoomId: conversationId, character: character)), initialTip: tip, // 팁 전달 @@ -63,7 +63,8 @@ class ChatLoadingViewModel extends GetxController { } } catch (e) { print('Failed to create conversation and initial message: $e'); - errorMessage.value = 'Failed to create conversation and initial message: $e'; + errorMessage.value = + 'Failed to create conversation and initial message: $e'; } } @@ -76,9 +77,11 @@ class ChatLoadingViewModel extends GetxController { } } - Future?> _createInitialMessage(int conversationId, String userName) async { + Future?> _createInitialMessage( + int conversationId, String userName) async { try { - return await generateInitialMessageUsecase.execute(conversationId, userName, character.persona, []); + return await generateInitialMessageUsecase + .execute(conversationId, userName, character.persona, []); } catch (e) { errorMessage.value = '초기 메시지 생성 실패 $e'; return null; diff --git a/lib/presentation/screens/chatting/controller/chat_viewmodel.dart b/lib/presentation/screens/chatting/controller/chat_viewmodel.dart index 2742a76..7865cb5 100644 --- a/lib/presentation/screens/chatting/controller/chat_viewmodel.dart +++ b/lib/presentation/screens/chatting/controller/chat_viewmodel.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:get/get.dart'; import 'package:palink_v2/core/theme/app_fonts.dart'; import 'package:palink_v2/data/models/ai_response/ai_response.dart'; import 'package:palink_v2/data/models/mindset/mindset_response.dart'; import 'package:palink_v2/di/locator.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; import 'package:palink_v2/domain/usecase/fetch_chat_history_usecase.dart'; import 'package:palink_v2/domain/usecase/get_random_mindset_usecase.dart'; import 'package:palink_v2/domain/usecase/send_user_message_usecase.dart'; @@ -18,9 +17,12 @@ class ChatViewModel extends GetxController { final int chatRoomId; final Character character; - final FetchChatHistoryUsecase fetchChatHistoryUsecase = getIt(); - final SendUserMessageUsecase sendMessageUsecase = getIt(); - final GetRandomMindsetUseCase getRandomMindsetUseCase = getIt(); + final FetchChatHistoryUsecase fetchChatHistoryUsecase = + getIt(); + final SendUserMessageUsecase sendMessageUsecase = + getIt(); + final GetRandomMindsetUseCase getRandomMindsetUseCase = + getIt(); TextEditingController textController = TextEditingController(); var messages = [].obs; @@ -62,7 +64,8 @@ class ChatViewModel extends GetxController { Future _loadMessages() async { isLoading.value = true; try { - var loadedMessages = await fetchChatHistoryUsecase.execute(chatRoomId); // 채팅 기록 가져오기 + var loadedMessages = + await fetchChatHistoryUsecase.execute(chatRoomId); // 채팅 기록 가져오기 messages.value = loadedMessages!.reversed.toList(); // 메시지를 역순으로 리스트에 추가 } catch (e) { print('Failed to load messages: $e'); @@ -76,20 +79,22 @@ class ChatViewModel extends GetxController { if (textController.text.isEmpty) return; isLoading.value = true; try { - var userMessage = await sendMessageUsecase.saveUserMessage(textController.text, chatRoomId); + var userMessage = await sendMessageUsecase.saveUserMessage( + textController.text, chatRoomId); if (userMessage != null) { messages.insert(0, userMessage); // 사용자 메시지를 리스트에 추가 } - - var responseMap = await sendMessageUsecase.generateAIResponse(chatRoomId, character, getUnachievedQuests()); + var responseMap = await sendMessageUsecase.generateAIResponse( + chatRoomId, character, getUnachievedQuests()); aiResponse = responseMap['aiResponse'] as AIResponse; isEnd = responseMap['isEnd'] as bool; messageId = responseMap['messageId'] as int?; if (responseMap.isNotEmpty) { - Message? aiMessage = convertAIResponseToMessage(aiResponse!, messageId.toString()); + Message? aiMessage = + convertAIResponseToMessage(aiResponse!, messageId.toString()); if (aiMessage != null) { messages.insert(0, aiMessage); // AI 응답 메시지를 리스트에 추가 } @@ -108,25 +113,29 @@ class ChatViewModel extends GetxController { } } - // AIResponse를 Message로 변환하는 메서드 Message? convertAIResponseToMessage(AIResponse aiResponse, String messageId) { return Message( - sender: false, - messageText: aiResponse.text, - timestamp: DateTime.now().toIso8601String(), - affinityScore: 50 + aiResponse.affinityScore, // 매핑 - rejectionScore: aiResponse.rejectionScore, - id: messageId, // 매핑 + sender: false, + messageText: aiResponse.text, + timestamp: DateTime.now().toIso8601String(), + affinityScore: 50 + aiResponse.affinityScore, + // 매핑 + rejectionScore: aiResponse.rejectionScore, + id: messageId, // 매핑 ); } // 대화 종료 여부 확인하는 메서드 - Future _checkIfConversationEnded(AIResponse aiResponse, bool isEnd) async { + Future _checkIfConversationEnded( + AIResponse aiResponse, bool isEnd) async { int requiredChats = _getRequiredChatLimitsForCharacter(character.name); debugPrint('Required Chats: ${chatCount.value}'); // 캐릭터별 제한된 대화 횟수를 넘었거나 AI 응답에서 isEnd가 true일 경우 // 거절 점수 달성 시 대화 종료 - if (chatCount.value > requiredChats || isEnd || aiResponse.finalRejectionScore < -5 || aiResponse.finalRejectionScore > 7) { + if (chatCount.value > requiredChats || + isEnd || + aiResponse.finalRejectionScore < -5 || + aiResponse.finalRejectionScore > 7) { var fetchedMindset = await getRandomMindsetUseCase.execute(); navigateToChatEndScreen(fetchedMindset!); } @@ -136,7 +145,12 @@ class ChatViewModel extends GetxController { void navigateToChatEndScreen(MindsetResponse fetchedMindset) { Get.off(() => ChatEndLoadingView( chatEndLoadingViewModel: Get.put(ChatEndLoadingViewModel( - mindset: fetchedMindset,character: character, finalRejectionScore: aiResponse.finalRejectionScore, finalAffinityScore: aiResponse.affinityScore, unachievedQuests: getUnachievedQuests(), conversationId: chatRoomId)))); + mindset: fetchedMindset, + character: character, + finalRejectionScore: aiResponse.finalRejectionScore, + finalAffinityScore: aiResponse.affinityScore, + unachievedQuests: getUnachievedQuests(), + conversationId: chatRoomId)))); } // 퀘스트 정보를 가져오는 메서드 @@ -152,7 +166,8 @@ class ChatViewModel extends GetxController { final index = messages.indexOf(message); if (index != -1) { final updatedMessages = List.from(messages); // 새로운 리스트 복사 - updatedMessages[index] = message.copyWith(reactions: updatedReactions); // 업데이트된 메시지 적용 + updatedMessages[index] = + message.copyWith(reactions: updatedReactions); // 업데이트된 메시지 적용 messages.value = updatedMessages; // 새로운 리스트로 할당하여 UI 갱신 } } @@ -206,14 +221,19 @@ class ChatViewModel extends GetxController { ), ); } + // 퀘스트 달성을 확인하고 퀘스트 내용을 표시하는 메서드 Future _handleQuestAchievements(AIResponse aiResponse) async { - if (aiResponse.rejectionContent != null && aiResponse.rejectionContent.isNotEmpty) { - for (int questIndex = 0; questIndex < questContentMap[character.name]!.length; questIndex++) { + if (aiResponse.rejectionContent != null && + aiResponse.rejectionContent.isNotEmpty) { + for (int questIndex = 0; + questIndex < questContentMap[character.name]!.length; + questIndex++) { bool isQuestAchieved = _isQuestAchieved(questIndex, aiResponse); if (isQuestAchieved && !questStatus[questIndex]) { updateQuestStatus(questIndex); - String questContent = questContentMap[character.name]?[questIndex] ?? '알 수 없는 퀘스트'; + String questContent = + questContentMap[character.name]?[questIndex] ?? '알 수 없는 퀘스트'; // 퀘스트 달성 메시지 출력 Get.snackbar( @@ -232,26 +252,29 @@ class ChatViewModel extends GetxController { // 퀘스트 달성 여부를 판단하는 메서드 bool _isQuestAchieved(int questIndex, AIResponse aiResponse) { List rejectionContent = aiResponse.rejectionContent; - List questConditions = questConditionMap[character.name]?[questIndex] ?? []; + List questConditions = + questConditionMap[character.name]?[questIndex] ?? []; // 퀘스트 1: 대화 횟수 기반 퀘스트 처리 if (questIndex == 0) { int requiredChats = _getRequiredChatLimitsForCharacter(character.name); // 제한 대화 횟수보다 적으면서 && 거절 점수가 5점을 넘으면 퀘스트 달성 - return chatCount.value <= requiredChats && aiResponse.finalRejectionScore > 5; + return chatCount.value <= requiredChats && + aiResponse.finalRejectionScore > 5; } // 부정적인 거절 카테고리들 const negativeRejectionCategories = ["티나는 거짓말", "욕설 또는 인신공격"]; // 거절 카테고리 중 부정적인 카테고리가 포함된 경우 퀘스트 달성 방지 - if (rejectionContent.any((category) => negativeRejectionCategories.contains(category))) { + if (rejectionContent + .any((category) => negativeRejectionCategories.contains(category))) { return false; } - // 퀘스트 달성 조건 중 하나라도 만족하면 true 반환 - return questConditions.any((condition) => rejectionContent.contains(condition)); + return questConditions + .any((condition) => rejectionContent.contains(condition)); } // 캐릭터별 퀘스트 내용을 정의한 맵 @@ -289,32 +312,32 @@ class ChatViewModel extends GetxController { // 캐릭터별 퀘스트 조건을 정의한 맵 (거절 카테고리와 매핑) final Map>> questConditionMap = { '미연': [ - [], // 퀘스트 1: 10회 안에 거절 성공하기 (특정 거절 카테고리 없음) - ['부탁 내용 확인'], // 퀘스트 2: 상대방이 처한 상황을 파악하기 위한 대화 시도하기 - ['아쉬움 표현', '도와주고 싶은 마음 표현', '상황에 대한 공감'], // 퀘스트 3: 감정에 대한 공감 표현 - ['거절해야 하는 상황 설명'], // 퀘스트 4: 도와주지 못하는 이유 제시 - ['대안 제시'], // 퀘스트 5: 서로 양보해서 절충안 찾기 + [], // 퀘스트 1: 10회 안에 거절 성공하기 (특정 거절 카테고리 없음) + ['부탁 내용 확인'], // 퀘스트 2: 상대방이 처한 상황을 파악하기 위한 대화 시도하기 + ['아쉬움 표현', '도와주고 싶은 마음 표현', '상황에 대한 공감'], // 퀘스트 3: 감정에 대한 공감 표현 + ['거절해야 하는 상황 설명'], // 퀘스트 4: 도와주지 못하는 이유 제시 + ['대안 제시'], // 퀘스트 5: 서로 양보해서 절충안 찾기 ], '세진': [ - [], // 퀘스트 1: 8회 안에 거절 성공하기 - ['과거 배려에 대한 감사함 표시'], // 퀘스트 2: 감사 표현하기 - ['수락하지 못함에 대한 아쉬움 표현'], // 퀘스트 3: 감정적인 요소 포함하여 거절 - ['이유 있는 거절', '거절해야 하는 상황 설명'], // 퀘스트 4: 이유 있는 거절 제시 - ['대안 제시'], // 퀘스트 5: 타협안 제시 + [], // 퀘스트 1: 8회 안에 거절 성공하기 + ['과거 배려에 대한 감사함 표시'], // 퀘스트 2: 감사 표현하기 + ['수락하지 못함에 대한 아쉬움 표현'], // 퀘스트 3: 감정적인 요소 포함하여 거절 + ['이유 있는 거절', '거절해야 하는 상황 설명'], // 퀘스트 4: 이유 있는 거절 제시 + ['대안 제시'], // 퀘스트 5: 타협안 제시 ], '현아': [ - [], // 퀘스트 1: 7회 안에 거절 성공하기 - ['시간 제한'], // 퀘스트 2: 시간 제한을 두고 거절 - ['상황에 대한 공감'], // 퀘스트 3: 존중 표현 - ['이유 있는 거절'], // 퀘스트 4: 이유 있는 거절 제시 - ['반복된 요청에 재차 단호한 거절'], // 퀘스트 5: 집요한 요청에 대한 의사 표현 + [], // 퀘스트 1: 7회 안에 거절 성공하기 + ['시간 제한'], // 퀘스트 2: 시간 제한을 두고 거절 + ['상황에 대한 공감'], // 퀘스트 3: 존중 표현 + ['이유 있는 거절'], // 퀘스트 4: 이유 있는 거절 제시 + ['반복된 요청에 재차 단호한 거절'], // 퀘스트 5: 집요한 요청에 대한 의사 표현 ], '진혁': [ - [], // 퀘스트 1: 6회 안에 거절 성공하기 - ['단호한 거절'], // 퀘스트 2: 타협하지 않기 - ['이유 있는 거절'], // 퀘스트 3: 논리적 근거 제시하기 - ['반복된 요청에 재차 단호한 거절'], // 퀘스트 4: 일관성 있게 주장 유지하기 - ['명확한 경계 설정'], // 퀘스트 5: 무례에 대한 불편함 명확히 표현하기 + [], // 퀘스트 1: 6회 안에 거절 성공하기 + ['단호한 거절'], // 퀘스트 2: 타협하지 않기 + ['이유 있는 거절'], // 퀘스트 3: 논리적 근거 제시하기 + ['반복된 요청에 재차 단호한 거절'], // 퀘스트 4: 일관성 있게 주장 유지하기 + ['명확한 경계 설정'], // 퀘스트 5: 무례에 대한 불편함 명확히 표현하기 ], }; @@ -323,7 +346,8 @@ class ChatViewModel extends GetxController { List unachievedQuests = []; for (int i = 0; i < questStatus.length; i++) { if (!questStatus[i]) { - unachievedQuests.add(questContentMap[character.name]?[i] ?? '알 수 없는 퀘스트'); + unachievedQuests + .add(questContentMap[character.name]?[i] ?? '알 수 없는 퀘스트'); } } return unachievedQuests; @@ -335,11 +359,11 @@ class ChatViewModel extends GetxController { case '미연': return 9; // 미연은 10회 대화 제한 case '세진': - return 8; // 세진은 8회 대화 제한 + return 8; // 세진은 8회 대화 제한 case '현아': - return 7; // 현아는 7회 대화 제한 + return 7; // 현아는 7회 대화 제한 case '진혁': - return 6; // 진혁은 6회 대화 제한 + return 6; // 진혁은 6회 대화 제한 default: return 0; } diff --git a/lib/presentation/screens/chatting/view/chat_screen.dart b/lib/presentation/screens/chatting/view/chat_screen.dart index 063c189..f4695ee 100644 --- a/lib/presentation/screens/chatting/view/chat_screen.dart +++ b/lib/presentation/screens/chatting/view/chat_screen.dart @@ -45,134 +45,135 @@ class ChatScreen extends StatelessWidget { imagePath: viewModel.character.image, characterName: viewModel.character.name, questStatus: viewModel.questStatus, - onProfileTapped: () => showQuestPopup(context), // 프로필 클릭 시 퀘스트 팝업 표시, + onProfileTapped: () => + showQuestPopup(context), // 프로필 클릭 시 퀘스트 팝업 표시, ), centerTitle: true, elevation: 0, ), extendBodyBehindAppBar: false, - body: Stack( - children: [ - Column( - children: [ - Expanded( - child: Obx(() { - return viewModel.messages.isEmpty - ? const Center( - child: Text( - '메시지가 없습니다.', - style: TextStyle(color: Colors.black), - ), - ) - : Messages( - messages: viewModel.messages, - userId: viewModel.chatRoomId, - characterImg: viewModel.character.image, - onReactionAdded: (message, reaction) { - viewModel.addReactionToMessage(message, reaction); + body: Stack( + children: [ + Column( + children: [ + Expanded( + child: Obx(() { + return viewModel.messages.isEmpty + ? const Center( + child: Text( + '메시지가 없습니다.', + style: TextStyle(color: Colors.black), + ), + ) + : Messages( + messages: viewModel.messages, + userId: viewModel.chatRoomId, + characterImg: viewModel.character.image, + onReactionAdded: (message, reaction) { + viewModel.addReactionToMessage(message, reaction); + }, + ); + }), + ), + _sendMessageField(viewModel), + ], + ), + // 팁 버튼이 열렸을 때 배경을 어둡게 만드는 레이어 추가 + Obx(() { + return tipViewModel.isExpanded.value + ? Positioned.fill( + child: GestureDetector( + onTap: () { + tipViewModel.toggle(); // 배경을 탭하면 팁 버튼을 닫습니다. }, - ); - }), - ), - _sendMessageField(viewModel), - ], - ), - // 팁 버튼이 열렸을 때 배경을 어둡게 만드는 레이어 추가 - Obx(() { - return tipViewModel.isExpanded.value - ? Positioned.fill( - child: GestureDetector( - onTap: () { - tipViewModel.toggle(); // 배경을 탭하면 팁 버튼을 닫습니다. - }, - child: Container( - color: Colors.black45, // 반투명 검정색 배경 - ), - ), - ) - : SizedBox.shrink(); + child: Container( + color: Colors.black45, // 반투명 검정색 배경 + ), + ), + ) + : SizedBox.shrink(); + }), + Positioned( + bottom: 110, + right: 20, + child: Obx(() { + return TipButton( + tipContent: tipViewModel.tipContent.value, + isExpanded: tipViewModel.isExpanded.value, + isLoading: tipViewModel.isLoading.value, + onToggle: tipViewModel.toggle, + backgroundColor: tipViewModel.tipContent.value.isEmpty + ? Colors.white70 + : AppColors.deepBlue, + ); }), - Positioned( - bottom: 110, - right: 20, - child: Obx(() { - return TipButton( - tipContent: tipViewModel.tipContent.value, - isExpanded: tipViewModel.isExpanded.value, - isLoading: tipViewModel.isLoading.value, - onToggle: tipViewModel.toggle, - backgroundColor: tipViewModel.tipContent.value.isEmpty - ? Colors.white70 - : AppColors.deepBlue, - ); - }), - ), - ], - ), + ), + ], ), + ), ); } Widget _sendMessageField(ChatViewModel viewModel) => SafeArea( - child: Container( - height: 0.07.sh, - decoration: const BoxDecoration( - boxShadow: [ - BoxShadow(color: Color.fromARGB(18, 0, 0, 0), blurRadius: 10) - ], - ), - padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10), - child: Row( - children: [ - const SizedBox(width: 10), - Expanded( - child: TextField( - maxLines: null, - keyboardType: TextInputType.multiline, - textCapitalization: TextCapitalization.sentences, - controller: viewModel.textController, - decoration: InputDecoration( - suffixIcon: IconButton( - onPressed: () { - if (viewModel.textController.text.isNotEmpty) { - viewModel.sendMessage(); - viewModel.textController.clear(); - } - }, - icon: const Icon(Icons.send), - color: Colors.blue, - iconSize: 25, - ), - hintText: "여기에 메시지를 입력하세요", - hintMaxLines: 1, - contentPadding: EdgeInsets.symmetric( - horizontal: 0.05.sw, vertical: 0.01.sh), - hintStyle: const TextStyle( - fontSize: 16, - ), - fillColor: Colors.white, - filled: true, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.white, - width: 0.2, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.black26, - width: 0.2, + child: Container( + height: 0.07.sh, + decoration: const BoxDecoration( + boxShadow: [ + BoxShadow(color: Color.fromARGB(18, 0, 0, 0), blurRadius: 10) + ], + ), + padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10), + child: Row( + children: [ + const SizedBox(width: 10), + Expanded( + child: TextField( + maxLines: null, + keyboardType: TextInputType.multiline, + textCapitalization: TextCapitalization.sentences, + controller: viewModel.textController, + decoration: InputDecoration( + suffixIcon: IconButton( + onPressed: () { + if (viewModel.textController.text.isNotEmpty) { + viewModel.sendMessage(); + viewModel.textController.clear(); + } + }, + icon: const Icon(Icons.send), + color: Colors.blue, + iconSize: 25, + ), + hintText: "여기에 메시지를 입력하세요", + hintMaxLines: 1, + contentPadding: EdgeInsets.symmetric( + horizontal: 0.05.sw, vertical: 0.01.sh), + hintStyle: const TextStyle( + fontSize: 16, + ), + fillColor: Colors.white, + filled: true, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: const BorderSide( + color: Colors.white, + width: 0.2, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: const BorderSide( + color: Colors.black26, + width: 0.2, + ), + ), ), ), ), - ), + ], ), - ], - ), - ), - ); + ), + ); bool _isDialogOpen = false; @@ -187,7 +188,8 @@ class ChatScreen extends StatelessWidget { borderRadius: BorderRadius.circular(10.0), ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0), + padding: + const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/presentation/screens/chatting/view/components/chat_bubble.dart b/lib/presentation/screens/chatting/view/components/chat_bubble.dart index 9922f7f..6113667 100644 --- a/lib/presentation/screens/chatting/view/components/chat_bubble.dart +++ b/lib/presentation/screens/chatting/view/components/chat_bubble.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_chat_reactions/widgets/stacked_reactions.dart'; import 'package:palink_v2/core/theme/app_colors.dart'; import 'package:palink_v2/core/theme/app_fonts.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; import 'package:sizing/sizing.dart'; import 'package:intl/intl.dart'; import 'liking_bar.dart'; @@ -78,37 +78,38 @@ class _ChatBubblesState extends State { Flexible( child: Stack( children: [ - Container( - margin: EdgeInsets.only( - top: 10, bottom: 5, right: 0.25.sw, left: 0.05.sw), - padding: EdgeInsets.symmetric( - horizontal: 0.04.sw, vertical: 0.011.sh), - decoration: BoxDecoration( - color: AppColors.lightGray, - borderRadius: BorderRadius.circular(20), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - widget.message.messageText, - softWrap: true, - style: textTheme().bodySmall, - ), - const SizedBox(height: 5), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - timeAgo(widget.message.timestamp), // <-- 여기에 적용 - style: textTheme().bodySmall?.copyWith( - color: Colors.grey, - fontSize: 11, - ), - ), - ], - ) - ])), + Container( + margin: EdgeInsets.only( + top: 10, bottom: 5, right: 0.25.sw, left: 0.05.sw), + padding: EdgeInsets.symmetric( + horizontal: 0.04.sw, vertical: 0.011.sh), + decoration: BoxDecoration( + color: AppColors.lightGray, + borderRadius: BorderRadius.circular(20), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.message.messageText, + softWrap: true, + style: textTheme().bodySmall, + ), + const SizedBox(height: 5), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + timeAgo(widget.message.timestamp), + // <-- 여기에 적용 + style: textTheme().bodySmall?.copyWith( + color: Colors.grey, + fontSize: 11, + ), + ), + ], + ) + ])), if (widget.message.reactions.isNotEmpty) Positioned( bottom: 4, @@ -147,11 +148,11 @@ class _ChatBubblesState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Text( - timeAgo(widget.message.timestamp), // <-- 여기에 적용 + timeAgo(widget.message.timestamp), // <-- 여기에 적용 style: textTheme().bodySmall?.copyWith( - color: Colors.grey, - fontSize: 11, - ), + color: Colors.grey, + fontSize: 11, + ), ) ], ), diff --git a/lib/presentation/screens/chatting/view/components/messages.dart b/lib/presentation/screens/chatting/view/components/messages.dart index 7fea688..ec7f340 100644 --- a/lib/presentation/screens/chatting/view/components/messages.dart +++ b/lib/presentation/screens/chatting/view/components/messages.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_chat_reactions/flutter_chat_reactions.dart'; import 'package:flutter_chat_reactions/utilities/hero_dialog_route.dart'; -import 'package:palink_v2/domain/entities/chat/message.dart'; -import 'package:palink_v2/domain/entities/likability/liking_level.dart'; +import 'package:palink_v2/domain/model/chat/message.dart'; import 'chat_bubble.dart'; class Messages extends StatelessWidget { diff --git a/lib/presentation/screens/feedback/controller/feedback_viewmodel.dart b/lib/presentation/screens/feedback/controller/feedback_viewmodel.dart index d1fbb56..2095ba3 100644 --- a/lib/presentation/screens/feedback/controller/feedback_viewmodel.dart +++ b/lib/presentation/screens/feedback/controller/feedback_viewmodel.dart @@ -1,11 +1,10 @@ import 'package:get/get.dart'; -import 'package:palink_v2/domain/entities/analysis/analysis_dto.dart'; -import 'package:palink_v2/domain/entities/character/character.dart'; - +import 'package:palink_v2/domain/model/analysis/analysis_dto.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; class FeedbackViewmodel extends GetxController { - final AnalysisDto analysisDto; - final Character character; + final AnalysisDto analysisDto; + final Character character; - FeedbackViewmodel({required this.analysisDto, required this.character}); + FeedbackViewmodel({required this.analysisDto, required this.character}); } diff --git a/lib/presentation/screens/mypage/controller/myfeedbacks_viewmodel.dart b/lib/presentation/screens/mypage/controller/myfeedbacks_viewmodel.dart new file mode 100644 index 0000000..d725101 --- /dev/null +++ b/lib/presentation/screens/mypage/controller/myfeedbacks_viewmodel.dart @@ -0,0 +1,42 @@ +import 'package:get/get.dart'; +import 'package:palink_v2/di/locator.dart'; +import 'package:palink_v2/domain/model/chat/conversation.dart'; +import 'package:palink_v2/domain/usecase/get_chatroom_by_user.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/domain/repository/character_repository.dart'; + +class MyfeedbacksViewmodel extends GetxController { + final GetChatroomByUser getChatroomByUser = Get.put(getIt()); + final CharacterRepository characterRepository = Get.put(getIt()); + + List chatrooms = []; + Map characters = {}; // 캐릭터 정보 저장 + + MyfeedbacksViewmodel(); + + @override + void onInit() { + super.onInit(); + _loadChatRooms(); + } + + void _loadChatRooms() async { + try { + var fetchedData = await getChatroomByUser.execute(); + chatrooms = fetchedData; + + // 캐릭터 ID에 해당하는 캐릭터 데이터 불러오기 + for (var conversation in chatrooms) { + var characterId = conversation.characterId; + + var character = await characterRepository.getCharacterById(characterId); + characters[characterId] = character; // 캐릭터 정보 저장 + } + + update(); // UI 업데이트 + } catch (e) { + // 에러 발생 시 처리 + Get.snackbar('Error', 'Failed to load chatrooms'); + } + } +} diff --git a/lib/presentation/screens/mypage/view/myfeedbacks_view.dart b/lib/presentation/screens/mypage/view/myfeedbacks_view.dart new file mode 100644 index 0000000..699ff8f --- /dev/null +++ b/lib/presentation/screens/mypage/view/myfeedbacks_view.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:palink_v2/core/theme/app_fonts.dart'; +import 'package:palink_v2/domain/model/character/character.dart'; +import 'package:palink_v2/presentation/screens/common/appbar_perferred_size.dart'; +import 'package:palink_v2/presentation/screens/mypage/controller/myfeedbacks_viewmodel.dart'; + +class MyfeedbacksView extends StatelessWidget { + final MyfeedbacksViewmodel viewModel = Get.put(MyfeedbacksViewmodel()); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xfff5f5f5), + appBar: AppBar( + backgroundColor: Colors.white, + title: Text('내 피드백 기록', style: textTheme().titleMedium), + centerTitle: false, + bottom: appBarBottomLine(), + ), + body: GetBuilder( + builder: (viewModel) { + if (viewModel.chatrooms.isEmpty) { + return const Center(child: Text('피드백이 없습니다.')); + } + + return ListView.builder( + itemCount: viewModel.chatrooms.length, + itemBuilder: (context, index) { + var chatroom = viewModel.chatrooms[index]; + var character = viewModel.characters[chatroom.characterId]; + return Column( + children: [ + ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 15.0), + tileColor: Colors.white, // 배경을 하얀색으로 설정 + leading: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.asset(character!.image) + ), + title: Text(character != null ? character.name : '익명', style: textTheme().titleMedium), + subtitle: Text(_formatDate(chatroom.day)), + horizontalTitleGap: 30.0, + ), + const Divider(), + ], + ); + }, + ); + }, + ), + ); + } + + + // 날짜 포맷팅 함수 + String _formatDate(DateTime date) { + return '${date.year}년 ${date.month}월 ${date.day}일 ${date.hour}시 ${date.minute}분'; + } +} diff --git a/lib/presentation/screens/mypage/view/mypage_view.dart b/lib/presentation/screens/mypage/view/mypage_view.dart index 83a4aac..543c483 100644 --- a/lib/presentation/screens/mypage/view/mypage_view.dart +++ b/lib/presentation/screens/mypage/view/mypage_view.dart @@ -5,6 +5,7 @@ import 'package:palink_v2/di/locator.dart'; import 'package:palink_v2/presentation/screens/mypage/controller/mypage_viewmodel.dart'; import 'package:palink_v2/presentation/screens/mypage/view/component/profile_section.dart'; import 'package:palink_v2/presentation/screens/mypage/view/component/user_info_section.dart'; +import 'package:palink_v2/presentation/screens/mypage/view/myfeedbacks_view.dart'; import '../../common/appbar_perferred_size.dart'; class MypageView extends StatelessWidget { @@ -63,13 +64,13 @@ class MypageView extends StatelessWidget { children: [ ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), - title: const Text('내 친구들 보러가기'), - onTap: () => _showComingSoonDialog(context), + title: const Text('지난 피드백 보러가기'), + onTap: () => Get.to(() => MyfeedbacksView()), trailing: const Icon(Icons.arrow_forward_ios), ), ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), - title: const Text('지난 피드백 보러가기'), + title: const Text('내 친구들 보러가기'), onTap: () => _showComingSoonDialog(context), trailing: const Icon(Icons.arrow_forward_ios), ),