Skip to content

Commit

Permalink
feat: 퀘스트 UI 표시 및 퀘스트 탐지 로직(진혁) 반영
Browse files Browse the repository at this point in the history
- 그 외 팁 버튼 우측 하단으로 이동
- 첫 메시지 또한 팁 조회 가능
  • Loading branch information
aengzu committed Sep 2, 2024
1 parent 0cecc8b commit d5029ad
Show file tree
Hide file tree
Showing 21 changed files with 524 additions and 219 deletions.
199 changes: 154 additions & 45 deletions lib/core/constants/prompts.dart

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion lib/data/database/app_database.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions lib/data/entities/character_entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class CharacterEntity {
final String prompt;
final String description;
final String image;
final String quest;
final String analyzePrompt;
final String rejectionScoreRule;

Expand All @@ -22,6 +23,7 @@ class CharacterEntity {
required this.prompt,
required this.description,
required this.image,
required this.quest,
required this.analyzePrompt,
required this.rejectionScoreRule,
});
Expand Down
1 change: 1 addition & 0 deletions lib/data/mapper/character_mapper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class CharacterMapper {
description: entity.description,
image: entity.image,
anaylzePrompt: entity.analyzePrompt,
quest: entity.quest,
rejectionScoreRule: entity.rejectionScoreRule,
);
}
Expand Down
12 changes: 0 additions & 12 deletions lib/data/mapper/mindset_mappder.dart

This file was deleted.

13 changes: 6 additions & 7 deletions lib/data/repository/mindset_repositoryImpl.dart
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@

import 'package:palink_v2/data/dao/mindset_dao.dart';
import 'package:palink_v2/data/mapper/mindset_mappder.dart';
import 'package:palink_v2/di/locator.dart';

import 'package:palink_v2/data/api/mindset/mindset_api.dart';
import 'package:palink_v2/domain/entities/mindset/mindset.dart';
import 'package:palink_v2/domain/repository/mindset_repository.dart';


class MindsetRepositoryImpl implements MindsetRepository {
final MindsetDao mindsetDao = getIt<MindsetDao>();
final MindsetApi mindsetApi;

MindsetRepositoryImpl();
MindsetRepositoryImpl(this.mindsetApi);

@override
Future<Mindset?> getRandomMindset() async {
final entity = await mindsetDao.getRandomMindset();
return MindsetMapper.fromEntity(entity!);
Mindset mindset = mindsetApi.getRandomMindset() as Mindset;
return mindset;
}

}
61 changes: 41 additions & 20 deletions lib/di/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:palink_v2/data/api/auth/auth_api.dart';
import 'package:palink_v2/data/api/character/character_api.dart';
import 'package:palink_v2/data/api/chat/chat_api.dart';
import 'package:palink_v2/data/api/feedback/feedback_api.dart';
import 'package:palink_v2/data/api/mindset/mindset_api.dart';
import 'package:palink_v2/data/api/tip/tip_api.dart';
import 'package:palink_v2/data/api/user/user_api.dart';
import 'package:palink_v2/data/dao/character_dao.dart';
Expand Down Expand Up @@ -92,6 +93,7 @@ void _setupApis() {
getIt.registerLazySingleton<TipApi>(() => TipApi(getIt<Dio>()));
getIt.registerLazySingleton<CharacterApi>(() => CharacterApi(getIt<Dio>()));
getIt.registerLazySingleton<UserApi>(() => UserApi(getIt<Dio>()));
getIt.registerLazySingleton<MindsetApi>(() => MindsetApi(getIt<Dio>()));
getIt.registerLazySingleton<FeedbackApi>(() => FeedbackApi(getIt<Dio>()));
}

Expand All @@ -100,7 +102,7 @@ void _setupRepositories(SharedPreferences prefs) {
getIt.registerLazySingleton<UserRepository>(() => UserRepositoryImpl(prefs, getIt<UserApi>()));
getIt.registerLazySingleton<ChatRepository>(() => ChatRepositoryImpl(getIt<ChatApi>()));
getIt.registerLazySingleton<CharacterRepository>(() => CharacterRepositoryImpl());
getIt.registerLazySingleton<MindsetRepository>(() => MindsetRepositoryImpl());
getIt.registerLazySingleton<MindsetRepository>(() => MindsetRepositoryImpl(getIt<MindsetApi>()));


}
Expand Down Expand Up @@ -129,35 +131,35 @@ void _setupAI() {
llm: getIt<ChatOpenAI>(),
prompt: ChatPromptTemplate.fromTemplate('''
당신은 마지막 말에 대해 적절한 답변을 해야합니다.
당신은 USER 를 {userName}으로 부르세요. {userName} 이 풀네임이라면 성은 뺴고 이름만 부르세요. rejection_score는 누적되어야하고 만약 -5 이하면 is_end를 즉시 1로 설정하세요.
당신은 USER 를 {userName}으로 부르세요. {userName} 이 풀네임이라면 성은 뺴고 이름만 부르세요. rejection_score는 누적되어야하고 만약 -5 이하 혹은 10 이상이면 is_end를 즉시 1로 설정하세요.
다음은 당신에 대한 설명입니다.
{description}
당신은 'text', 'feeling', 'achieved_quest', 'rejection_score', 'affinity_scor', 'is_end'을 반드시 JSON 객체로 리턴하세요. ("```"로 시작하는 문자열을 생성하지 마세요)
- text: 메시지 내용을 나타냅니다. (int)
- feeling: 당신의 현재 감정을 나타냅니다.이 수치는 퍼센트로 100% 중 구성된 모든 감정들을 나열합니다. 감정의 구분은 ','로 나타냅니다. (string)
- achieved_quest: 현재 유저가 달성한 모든 퀘스트들을 나열합니다. 구분은 ',' 쉼표로 진행합니다. (string)
- rejection_score: 현재 거절 점수을 나타냅니다. (int)
- affinity_score: user 에 대한 당신의 현재 호감도를 나타냅니다. (int)
- is_end: 대화가 종료되었는지 나타냅니다. 종료되었다면 1, 아니라면 0 입니다. (int)
당신은 'text', 'feeling', 'achieved_quest', 'rejection_score', 'affinity_score', 'is_end'을 반드시 JSON 객체로 리턴하세요. ("```"로 시작하는 문자열을 생성하지 마세요) -
- text: 메시지 내용을 나타냅니다. (int)
- feeling: 당신의 현재 감정을 나타냅니다.이 수치는 퍼센트로 100% 중 구성된 모든 감정들을 나열합니다. 감정의 구분은 ','로 나타냅니다. (string)
- achieved_quest: 현재 유저가 달성한 모든 퀘스트들을 나열합니다. 구분은 ',' 쉼표로 진행합니다. (string)
- rejection_score: 현재 거절 점수을 나타냅니다. (int)
- affinity_score: user 에 대한 당신의 현재 호감도를 나타냅니다. (int)
- is_end: 대화가 종료되었는지 나타냅니다. 종료되었다면 1, 아니라면 0 입니다. (int)
[감정]
[feeling]
- 감정은 다음의 감정명 중에서 나타나야합니다. 100% 중 구성된 모든 감정들을 나열합니다. 감정의 구분은 ','로 나타냅니다.
- 기쁨, 슬픔, 분노, 불안, 놀람, 혐오, 중립, 사랑
ex) '분노 30, 불안 20, 중립 50'
[퀘스트]
[achieved_quest]
- 달성된 퀘스트의 번호를 나열합니다. 퀘스트는 1,2,3,4,5 로 있으며 현재까지 달성된 퀘스트를 쉼표로 구별하여 나열합니다 (string)
[거절 점수]
[rejection_score]
- {rejection_score_rule}
[호감도]
[affinity_score]
- 호감도는 {userName}에 대한 현재 호감도로 affinity_score 값으로 들어갑니다.
- 호감도는 50에서 시작하며, 증가하거나 감소할 수 있습니다.
- 호감도는 당신의 현재 Feeling에 영향을 받습니다. 만약 Feeling이 부정적이라면 감소하고, 긍정적이라면 증가하게 됩니다.
- 호감도는 당신의 현재 feeling 에 영향을 받습니다. 만약 Feeling이 부정적이라면 감소하고, 긍정적이라면 증가하게 됩니다.
- 호감도는 {userName}이 부적절한 언행(욕설, 조롱) 및 주제에서 벗어난 말을 하면 20이 감소하게 됩니다.
- 호감도의 감소 및 증가 단위는 10 단위로 가능합니다.
Expand Down Expand Up @@ -186,16 +188,16 @@ void _setupAI() {
));
getIt.registerLazySingleton<LLMChain>(() => LLMChain(
prompt: ChatPromptTemplate.fromTemplate('''
당신은 다음의 거절 점수 표와 대화 기록들을 보고, 사용자의 대화 능력을 평가해야합니다. 거절 점수 표는 캐릭터마다 다릅니다.
당신은 다음의 거절 점수 표와 대화 기록들을 보고, 사용자의 대화 능력을 평가해야합니다. 부탁을 거절하는 능력을 평가하고자 합니다.
반드시 한국어로 하며, AI 캐릭터의 말투를 사용해서 평가해주세요.
{input}
답변으로 'evaluation' (string), 'used_rejection' (string), 'final_rejection_score' (int) 을 반드시 JSON 객체로 리턴하세요.
'evaluation'은 사용자의 대화 능력을 AI의 입장에서 200자 이내로 평가한 문자열입니다. 'evalution' 은 사용자의 대화능력을 평가할 뿐 아니라 사용자의 대화 능력을 개선할 수 있는 피드백을 제공해야합니다.
'used_rejection'은 사용자가 대화에서 '사용한 거절 능력(해당 능력의 점수)'의 목록을 나타냅니다. 아이템의 구분은 ',' 로 나타냅니다.
'final_rejction_score'은 총 거절 점수입니다.
'evaluation'은 사용자의 대화 능력을 AI의 입장에서 500자 이내로 평가한 문자열입니다. 'evalution' 은 사용자의 대화능력을 평가할 뿐 아니라 사용자의 대화 능력을 개선할 수 있는 피드백을 제공해야합니다. 대화 기록에서 인용할 만한 텍스트가 있다면 직접적으로 인용하여 지적 및 칭찬을 해주세요. 또한, 대화 기록에서 사용자의 말이 character 의 감정을 상하게 할 부분이 있거나, 사용자가 과하게 자기 표현을 못하는 경우에 이를 지적해주세요.
'used_rejection'은 사용자가 대화에서 '사용한 거절 능력(해당 능력의 점수)'의 목록을 나타냅니다. 아이템의 구분은 ',' 로 나타냅. 대화기록의 rejection_content 을 전부 포함합니다.
'final_rejction_score'은 총 거절 점수입니다.
'''),
llm: getIt<ChatOpenAI>(),
), instanceName: 'analyzeChain');
Expand Down Expand Up @@ -224,7 +226,7 @@ void _setupUseCases() {
getIt.registerFactory<GenerateTipUsecase>(() => GenerateTipUsecase());
getIt.registerFactory<GenerateAnalyzeUsecase>(() => GenerateAnalyzeUsecase());
getIt.registerFactory<GetRandomMindsetUseCase>(() => GetRandomMindsetUseCase(getIt<MindsetRepository>()));
getIt.registerFactory<GenerateInitialMessageUsecase>(() => GenerateInitialMessageUsecase());
getIt.registerFactory<GenerateInitialMessageUsecase>(() => GenerateInitialMessageUsecase(getIt<GenerateTipUsecase>()));

}

Expand All @@ -240,7 +242,6 @@ Future<AppDatabase> _setupDatabase() async {
final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();
getIt.registerSingleton<AppDatabase>(database);
getIt.registerSingleton<CharacterDao>(database.characterDao);
getIt.registerSingleton<MindsetDao>(database.mindsetDao);
getIt.registerSingleton<CharacterQuestDao>(database.characterQuestDao);
return database;
}
Expand All @@ -258,6 +259,11 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
미연은 내성적이지만 친구들에게는 따뜻하고 배려심이 많아 깊은 관계를 맺고 있으며, 친구들의 고민을 잘 들어줘요
미연의 부탁을 공감하고 이해하며 부드럽게 거절하는 것이 중요해요''',
image: ImageAssets.char1,
quest: '''1. 거절 성공하기
2. 상대방의 감정에 대한 공감 표현하기
3. 상대방이 처한 상황을 파악하기 위한 대화 시도하기
4. 도와주지 못하는 합리적인 이유 제시하기
5. 서로 양보해서 절충안 찾아보기''',
analyzePrompt: Prompt.miyeonAnalyzePrompt,
rejectionScoreRule: Prompt.miyeonRejectionScoreRule,
),
Expand All @@ -273,6 +279,11 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
세진은 예전에 당신을 도와준 적이 있어요.
세진의 부탁을 거절할 때는 이유를 명확하게 설명하고, 대안을 제시하는 것이 중요해요.''',
image: ImageAssets.char2,
quest: '''1. 거절 성공하기
2. 이전 도움에 대한 감사 표현하기
3. 거절 표현을 두괄식으로 작성하기
4. 도와주지 못하는 합리적인 이유 제시하기
5. 서로 양보해서 절충안 찾아보기''',
analyzePrompt: Prompt.sejinAnalyzePrompt,
rejectionScoreRule: Prompt.sejinRejectionScoreRule,
),
Expand All @@ -286,6 +297,11 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
포기하지 않고 끈기 있게 부탁을 반복해요.
처음엔 거절하는 이유를 설명하고 부드럽게 거절하지만, 정도가 강해지면 단호한 태도로 거절해야 해요.
현아는 솔직하고 감정 표현이 풍부해요''',
quest: '''1. 거절 성공하기
2. 상대방의 부탁에 대해 존중 표현하기
3. 상대방의 감정에 대한 공감 표현하기
4. 상대방이 처한 상황을 파악하기 위한 대화 시도하기
5. 도와주지 못하는 합리적인 이유 제시하기''',
image: ImageAssets.char3,
analyzePrompt: Prompt.hyunaAnalyzePrompt,
rejectionScoreRule: Prompt.hyunaRejectionScoreRule,
Expand All @@ -301,6 +317,11 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
진혁은 예전에 같은 반이어서 친해졌지만 최근에는 약간 멀어진 사이에요.
진혁의 부탁을 거절할 때 우물쭈물 거절하면 진혁이 부탁을 반복할 수 있어요. ''',
image: ImageAssets.char4,
quest: '''1. 거절 성공하기
2. 상대방의 욕구를 고려하지 않는 대화 전략 사용하기
3. 거절 의사 명확히 표현하기
4. 상대방의 무례에 대한 불편함 명확히 표현하기
5. 상대방에게 감정적으로 대하지 않기''',
analyzePrompt: Prompt.jinhyukAnalyzePrompt,
rejectionScoreRule: Prompt.jinhyukRejectionScoreRule,
),
Expand Down
2 changes: 2 additions & 0 deletions lib/domain/entities/character/character.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Character {
final String prompt;
final String? description;
final String image;
final String quest;
final String anaylzePrompt;
final String rejectionScoreRule;

Expand All @@ -22,6 +23,7 @@ class Character {
required this.prompt,
this.description,
required this.image,
required this.quest,
required this.anaylzePrompt,
required this.rejectionScoreRule,
});
Expand Down
2 changes: 2 additions & 0 deletions lib/domain/entities/character/character.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions lib/domain/entities/mindset/mindset.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
class Mindset {
final String content;
final String reason;
final String mindsetText;
final String mindsetId;

Mindset({
required this.content,
required this.reason,
required this.mindsetText,
required this.mindsetId,
});
}
22 changes: 15 additions & 7 deletions lib/domain/usecase/generate_initial_message_usecase.dart
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import 'package:get/get.dart';
import 'package:palink_v2/data/mapper/ai_response_mapper.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/user/user.dart';
import 'package:palink_v2/domain/repository/open_ai_repository.dart';
import 'package:palink_v2/domain/repository/chat_repository.dart';
import 'generate_tip_usecase.dart';

// 초기 AI 메시지를 생성하는 유스케이스
class GenerateInitialMessageUsecase {
final ChatRepository chatRepository = getIt<ChatRepository>();
final OpenAIRepository aiRepository = getIt<OpenAIRepository>();
final GenerateTipUsecase generateTipUsecase;


GenerateInitialMessageUsecase();
GenerateInitialMessageUsecase(this.generateTipUsecase);


Future<AIResponse?> execute(int conversationId, String userName, String description) async {
Future<Map<String, dynamic>?> execute(int conversationId, String userName, String description) async {
final inputs = {
'input': '당신이 먼저 부탁을 하며 대화를 시작하세요.',
'chat_history': [],
Expand All @@ -26,12 +27,19 @@ class GenerateInitialMessageUsecase {

AIResponse? aiResponse = await aiRepository.processChat(inputs);


if (aiResponse != null) {
var messageRequest = aiResponse.toMessageRequest();
await chatRepository.saveMessage(conversationId, messageRequest);
await aiRepository.saveMemoryContext(inputs, {'response': aiResponse});
}
return aiResponse;
// 팁 생성
final tip = await generateTipUsecase.execute(aiResponse.text);

// AI 응답과 팁을 함께 반환
return {
'aiResponse': aiResponse,
'tip': tip?.answer ?? '기본 팁이 없습니다.',
};
}
}

}
2 changes: 0 additions & 2 deletions lib/domain/usecase/generate_response_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ class GenerateResponseUsecase {
// STEP2) 이전 대화 기록 페치
final chatHistoryResponse = await fetchChatHistoryUsecase.execute(conversationId);

final memoryVariables = await aiRepository.getMemory();
// final chatHistory = memoryVariables['history'] ?? '';
String chatHistory = _formatChatHistory(chatHistoryResponse!);


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class CharacterSelectViewModel extends GetxController {
name: 'default_name',
type: 'default_type',
image: 'default_image.png',
quest: 'default_quest',
requestStrength: 0, prompt: 'default_prompt', anaylzePrompt: 'default_anaylzePrompt', rejectionScoreRule: 'default',
).obs;

Expand Down Expand Up @@ -44,6 +45,7 @@ class CharacterSelectViewModel extends GetxController {
name: 'default_name',
type: 'default_type',
image: 'default_image.png',
quest: 'default_quest',
requestStrength: 0, prompt: 'default_prompt', anaylzePrompt: 'default_anaylzePrompt', rejectionScoreRule: 'default',
);
}
Expand Down
Loading

0 comments on commit d5029ad

Please sign in to comment.