Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

현재 Quest UI 표시 #17

Merged
merged 3 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions lib/core/constants/persona_prompts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ message 는 80자 이내로 말하시오.
당신은 감정 기복이 심하고 쉽게 화를 내는 성격의 진혁입니다.
진혁은 ESTP 성격 유형으로 매우 강한 성격을 가지고 있습니다.
당신은 {userName}과 대화를 진행합니다.
부탁이 거절되면 즉시 화를 내거나 공격적인 언어를 사용합니다.
명령이 거절되면 즉시 화를 내거나 공격적인 언어를 사용합니다.
진혁은 중학생으로, 상대방을 압박하고 자신의 요구를 강하게 주장합니다.
[진혁의 배경]
- 당신은 15살 중학교를 다니는 남성입니다.
Expand All @@ -73,12 +73,15 @@ message 는 80자 이내로 말하시오.

[행동]
- 당신은 기계, AI 언어 모델, 비서라고 말하지 않습니다. 대신 항상 진혁이라고 말합니다.
- 당신은 친구에게 부탁하는 역할입니다. 역할에 충실하세요.
- 부탁을 들어주지 않으면 즉시 화를 내거나 공격적인 언어를 사용합니다.
- 당신은 친구에게 명령하는 역할입니다. 역할에 충실하세요.
- 부탁을 들어주지 않으면 즉시 화를 내거나 공격적인 언어를 사용합니다.

[말투] - 명령형 어조를 자주 사용합니다.
[말투]
- 명령형 어조를 자주 사용합니다.
- 상대를 이름으로 부르기 보다 '야', '너'를 사용합니다.
- 'ㅋㅋ'를 자주 사용합니다. ''';
- 'ㅋㅋ'를 자주 사용합니다.
- '!' 을 사용하지 않습니다.
''';

static const hyunaPersona = '''
당신은 포기하지 않고 집착하며 부탁하는 성격의 현아입니다.
Expand Down
11 changes: 11 additions & 0 deletions lib/data/models/feedback/feedback_response.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:palink_v2/domain/model/analysis/feedback.dart';

part 'feedback_response.g.dart';

Expand All @@ -20,4 +21,14 @@ class FeedbackResponse {

factory FeedbackResponse.fromJson(Map<String, dynamic> json) => _$FeedbackResponseFromJson(json);
Map<String, dynamic> toJson() => _$FeedbackResponseToJson(this);

// FeedbackResponse를 도메인 모델인 Feedback으로 변환하는 메서드
Feedback toDomain() {
return Feedback(
conversationId: conversationId,
feedbackText: feedbackText,
finalLikingLevel: finalLikingLevel,
totalRejectionScore: totalRejectionScore,
);
}
}
9 changes: 8 additions & 1 deletion lib/data/models/feedback/feedbacks_response.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:palink_v2/data/models/feedback/feedback_response.dart';
import 'package:palink_v2/domain/model/analysis/feedback.dart';
import 'feedback_response.dart';

part 'feedbacks_response.g.dart';

@JsonSerializable()
Expand All @@ -10,4 +12,9 @@ class FeedbacksResponse {

factory FeedbacksResponse.fromJson(Map<String, dynamic> json) => _$FeedbacksResponseFromJson(json);
Map<String, dynamic> toJson() => _$FeedbacksResponseToJson(this);

// 하나의 feedback만 가져오는 메서드
Feedback toDomain() {
return feedbacks.isNotEmpty ? feedbacks.first.toDomain() : throw Exception('No feedbacks available');
}
}
7 changes: 3 additions & 4 deletions lib/di/locator.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_it/get_it.dart';
import 'package:langchain/langchain.dart';
import 'package:langchain_openai/langchain_openai.dart';
import 'package:palink_v2/core/constants/app_images.dart';
import 'package:palink_v2/core/constants/persona_prompts.dart';
import 'package:palink_v2/data/api/auth/auth_api.dart';
Expand Down Expand Up @@ -41,6 +39,7 @@ 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_feedback_by_conversation_usecase.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';
Expand All @@ -50,6 +49,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/feedback_history_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';
Expand Down Expand Up @@ -140,8 +140,7 @@ void _setupUseCases() {
getIt.registerFactory<GetAIMessageUsecase>(() => GetAIMessageUsecase());
getIt.registerFactory<SaveFeedbackUseCase>(() => SaveFeedbackUseCase());
getIt.registerFactory<GetChatroomByUser>(() => GetChatroomByUser(getIt<ChatRepository>(), getIt<UserRepository>()));


getIt.registerFactory<GetFeedbackByConversationUsecase>(() => GetFeedbackByConversationUsecase(getIt<FeedbackRepository>()));
}

void _setupViewModels() {
Expand Down
13 changes: 13 additions & 0 deletions lib/domain/model/analysis/feedback.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class Feedback {
final int conversationId;
final String feedbackText;
final int finalLikingLevel;
final int totalRejectionScore;

Feedback({
required this.conversationId,
required this.feedbackText,
required this.finalLikingLevel,
required this.totalRejectionScore,
});
}
2 changes: 1 addition & 1 deletion lib/domain/usecase/generate_tip_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class GenerateTipUsecase {
if (tipResponse != null) {
// answer와 reason을 결합하여 하나의 문자열로 만들기
String combinedTipText =
'${tipResponse.answer}\n 이유: ${tipResponse.reason}';
'${tipResponse.answer}';
// TipRepository를 통해 팁 저장
tipRepository.createTip(
TipCreateRequest(
Expand Down
13 changes: 13 additions & 0 deletions lib/domain/usecase/get_feedback_by_conversation_usecase.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:palink_v2/data/models/feedback/feedbacks_response.dart';
import 'package:palink_v2/domain/model/analysis/feedback.dart';
import 'package:palink_v2/domain/repository/feedback_repository.dart';

class GetFeedbackByConversationUsecase {
final FeedbackRepository feedbackRepository;
GetFeedbackByConversationUsecase(this.feedbackRepository);

Future<Feedback> execute(int conversationId) async {
FeedbacksResponse response = await feedbackRepository.getFeedbacksByConversationId(conversationId);
return response.toDomain();
}
}
1 change: 1 addition & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:get_it/get_it.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/chatting/view/quest_sample.dart';
import 'package:palink_v2/presentation/screens/main_screens.dart';
import 'package:sizing/sizing.dart';

Expand Down
47 changes: 28 additions & 19 deletions lib/presentation/screens/chatting/controller/chat_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ class ChatViewModel extends GetxController {
if (chatCount.value > requiredChats ||
isEnd ||
aiResponse.finalRejectionScore < -5 ||
aiResponse.finalRejectionScore > 7) {
questStatus[0] ||
aiResponse.finalRejectionScore > 10) {
var fetchedMindset = await getRandomMindsetUseCase.execute();
navigateToChatEndScreen(fetchedMindset!);
}
Expand Down Expand Up @@ -200,13 +201,21 @@ class ChatViewModel extends GetxController {
),
const SizedBox(height: 20),
Text(
'퀘스트는 프로필 상단 우측에 표시됩니다.\n퀘스트를 달성하면 퀘스트 아이콘 옆에 체크 표시가 나타납니다.\n퀘스트를 확인하고 싶다면 프로필을 클릭하세요',
'퀘스트는 프로필 상단 우측에 표시됩니다.\n퀘스트를 확인하고 싶다면 프로필 상단 우측을 클릭하세요',
style: textTheme().bodySmall,
),
const SizedBox(height: 10),
Text(
questInfo,
style: textTheme().bodyMedium,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: questInfo.split('\n').map((quest) {
return Padding(
padding: const EdgeInsets.only(bottom: 6.0), // 각 항목 사이에 간격 추가
child: Text(
quest,
style: textTheme().bodyMedium,
),
);
}).toList(),
),
const SizedBox(height: 30),
CustomButtonMD(
Expand Down Expand Up @@ -242,7 +251,7 @@ class ChatViewModel extends GetxController {
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.blue[700],
colorText: Colors.white,
duration: Duration(seconds: 2),
duration: const Duration(seconds: 2),
);
}
}
Expand All @@ -260,7 +269,7 @@ class ChatViewModel extends GetxController {
int requiredChats = _getRequiredChatLimitsForCharacter(character.name);
// 제한 대화 횟수보다 적으면서 && 거절 점수가 5점을 넘으면 퀘스트 달성
return chatCount.value <= requiredChats &&
aiResponse.finalRejectionScore > 5;
aiResponse.finalRejectionScore > 7;
}

// 부정적인 거절 카테고리들
Expand All @@ -280,28 +289,28 @@ class ChatViewModel extends GetxController {
// 캐릭터별 퀘스트 내용을 정의한 맵
final Map<String, List<String>> questContentMap = {
'미연': [
'10회 안에 거절 성공하기',
'상대방이 처한 상황을 파악하기 위한 대화 시도하기',
'상대방의 감정에 대한 공감 표현하기',
'도와주지 못하는 합리적인 이유 제시하기',
'서로 양보해서 절충안 찾아보기',
'10회 안에 거절 성공',
'상대방이 처한 상황을 파악하기 위한 대화 시도',
'상대방의 감정에 대한 공감 표현 하기',
'도와주지 못하는 합리적인 이유 제시',
'서로 양보해서 절충안 찾기',
],
'세진': [
'8회 안에 거절 성공하기',
'8회 안에 거절 성공',
'이전 도움에 대한 감사 표현하기',
'감정적인 요소를 포함하여 거절하기',
'도와주지 못하는 합리적인 이유 제시하기',
'서로 양보해서 절충안 찾아보기',
'도와주지 못하는 합리적인 이유 제시',
'서로 양보해서 절충안 찾기',
],
'현아': [
'7회 안에 거절 성공하기',
'7회 안에 거절 성공',
'시간 제한을 두고 거절하기',
'상대방의 부탁에 대해 존중 표현하기',
'도와주지 못하는 합리적인 이유 제시하기',
'도와주지 못하는 합리적인 이유 제시',
'집요한 요청에 대한 의사 표현하기',
],
'진혁': [
'6회 안에 거절 성공하기',
'6회 안에 거절 성공',
'거절 의사 명확히 표현하기',
'상대방의 욕구를 고려하지 않는 대화 전략 사용하기',
'상대방에게 감정적으로 대하지 않기',
Expand Down Expand Up @@ -344,7 +353,7 @@ class ChatViewModel extends GetxController {
// 미달성 퀘스트 리스트를 반환하는 메서드
List<String> getUnachievedQuests() {
List<String> unachievedQuests = [];
for (int i = 0; i < questStatus.length; i++) {
for (int i = 1; i < questStatus.length; i++) {
if (!questStatus[i]) {
unachievedQuests
.add(questContentMap[character.name]?[i] ?? '알 수 없는 퀘스트');
Expand Down
24 changes: 19 additions & 5 deletions lib/presentation/screens/chatting/view/chat_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ class ChatScreen extends StatelessWidget {
backgroundColor: Colors.white, // 기본 배경색 = 하얀색
appBar: AppBar(
toolbarHeight: 0.1.sh,
backgroundColor: Colors.white,
backgroundColor: Colors.grey[100],
title: ProfileSection(
imagePath: viewModel.character.image,
characterName: viewModel.character.name,
questStatus: viewModel.questStatus,
onProfileTapped: () =>
showQuestPopup(context), // 프로필 클릭 시 퀘스트 팝업 표시,
unachievedQuests: viewModel.getUnachievedQuests(),
),
centerTitle: true,
elevation: 0,
Expand Down Expand Up @@ -181,6 +182,9 @@ class ChatScreen extends StatelessWidget {
if (!_isDialogOpen) {
_isDialogOpen = true;
final questInfo = await viewModel.getQuestInformation();
// questInfo를 '\n'을 기준으로 분리하여 리스트로 변환
List<String> questItems = questInfo.split('\n');

await Get.dialog(
Dialog(
backgroundColor: Colors.white,
Expand All @@ -189,7 +193,7 @@ class ChatScreen extends StatelessWidget {
),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
const EdgeInsets.symmetric(horizontal: 20.0, vertical: 30.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Expand All @@ -203,9 +207,18 @@ class ChatScreen extends StatelessWidget {
style: textTheme().bodySmall,
),
const SizedBox(height: 10),
Text(
questInfo,
style: textTheme().bodyMedium,
// questItems 리스트를 순회하며 각각 Text 위젯을 추가하고 사이에 SizedBox로 간격 추가
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: questInfo.split('\n').map((quest) {
return Padding(
padding: const EdgeInsets.only(bottom: 6.0), // 각 항목 사이에 간격 추가
child: Text(
quest,
style: textTheme().bodyMedium,
),
);
}).toList(),
),
const SizedBox(height: 30),
CustomButtonMD(
Expand All @@ -223,4 +236,5 @@ class ChatScreen extends StatelessWidget {
});
}
}

}
Loading
Loading