Skip to content

Commit

Permalink
feat: 현재까지 진행상황 저장
Browse files Browse the repository at this point in the history
  • Loading branch information
aengzu committed Aug 20, 2024
1 parent 6d04b91 commit fc7c874
Show file tree
Hide file tree
Showing 17 changed files with 300 additions and 236 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ migrate_working_dir/
.pub-cache/
.pub/
/build/

deploy-dev.sh
# Symbolication related
app.*.symbols

Expand Down
10 changes: 10 additions & 0 deletions deploy-dev.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh

# 1. Flutter 웹 애플리케이션 빌드
flutter build web --web-renderer html

# 2. AWS S3 버킷에 파일 업로드
aws s3 sync ./build/web s3://palink-webapp

# 3. CloudFront 캐시 무효화
aws cloudfront create-invalidation --distribution-id EH08OF3FWDXSE --paths '/*'
293 changes: 140 additions & 153 deletions lib/core/constants/prompts.dart

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions 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 @@ -12,6 +12,7 @@ class CharacterEntity {
final String description;
final String image;
final String analyzePrompt;
final String rejectionScoreRule;

CharacterEntity({
required this.characterId,
Expand All @@ -22,5 +23,6 @@ class CharacterEntity {
required this.description,
required this.image,
required this.analyzePrompt,
required this.rejectionScoreRule,
});
}
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,
rejectionScoreRule: entity.rejectionScoreRule,
);
}
}
9 changes: 6 additions & 3 deletions lib/data/models/ai_response/ai_response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,21 @@ class AIResponse {
final String text;
@JsonKey(name: 'is_end')
final int isEnd;
@JsonKey(name: 'feeling')
final String feeling;
@JsonKey(name: 'affinity_score')
final int affinityScore;
@JsonKey(name: 'expected_emotion')
final String expectedEmotion;
@JsonKey(name: 'achieved_quest')
final String achievedQuest;
@JsonKey(name: 'rejection_score')
final int rejectionScore;

AIResponse({
required this.text,
required this.feeling,
required this.isEnd,
required this.affinityScore,
required this.expectedEmotion,
required this.achievedQuest,
required this.rejectionScore,
});

Expand Down
6 changes: 4 additions & 2 deletions lib/data/models/ai_response/ai_response.g.dart

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

3 changes: 2 additions & 1 deletion lib/data/repository/openai_repositoryImpl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ class OpenAIRepositoryImpl implements OpenAIRepository {
@override
Future<AIResponse?> processChat(Map<String, dynamic> inputs) async {
try {
print(inputs);
final result = await chatChain.invoke(inputs);
final AIChatMessage aiChatMessage = result['response'] as AIChatMessage;
final Map<String, dynamic> contentMap = jsonDecode(aiChatMessage.content);
AIResponse aiResponse = AIResponse.fromJson(contentMap);
print(contentMap);
return aiResponse;
} catch (e) {
print('Failed to process chat: $e');
Expand All @@ -50,7 +52,6 @@ class OpenAIRepositoryImpl implements OpenAIRepository {
Future<TipDto?> createTip(String message) async {
final inputs = {'input': "${Prompt.tipPrompt}\n${message}"};
try {
print('getTip inputs: $inputs'); // 로그 추가
final result = await tipChain.invoke({'input': inputs, 'memory': tipMemoryBuffer});

AIChatMessage aiChatMessage = result['output'] as AIChatMessage;
Expand Down
59 changes: 55 additions & 4 deletions lib/di/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ void _setupDio() {
final dio = Dio(BaseOptions(baseUrl: dotenv.env['BASE_URL']!));
dio.interceptors.add(InterceptorsWrapper(
onRequest: (options, handler) {
print("REQUEST[${options.method}] => PATH: ${options.path}, DATA: ${options.data}");
return handler.next(options);
},
onResponse: (response, handler) {
Expand Down Expand Up @@ -131,13 +130,61 @@ void _setupAI() {
당신은 마지막 말에 대해 적절한 답변을 해야합니다.
당신은 USER 를 {userName}으로 부르세요. {userName} 이 풀네임이라면 성은 뺴고 이름만 부르세요. rejection_score는 누적되어야하고 만약 -5 이하면 is_end를 즉시 1로 설정하세요.
다음은 당신에 대한 설명입니다.
{description}
답변으로 'text', 'feeling', 'expected_emotion', 'rejection_score', 'affinity_score', 'is_end'을 반드시 JSON 객체로 리턴하세요. ("```"로 시작하는 문자열을 생성하지 마세요)
{chat_history}
{input}
당신은 '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)
[감정]
- 감정은 다음의 감정명 중에서 나타나야합니다. 100% 중 구성된 모든 감정들을 나열합니다. 감정의 구분은 ','로 나타냅니다.
- 기쁨, 슬픔, 분노, 불안, 놀람, 혐오, 중립, 사랑
ex) '분노 30, 불안 20, 중립 50'
[호감도]
- 호감도는 {userName} 에 대한 현재 호감도로 AffinityScore 의 값으로 들어갑니다.
- 호감도는 50에서 시작하며, 증가하거나 감소할당신은 동정심을 유발하여 부탁을 들어주게 하는 성격의 미연입니다. 미연은 ISFJ 성격 유형으로 매우 감성적이고 공감을 잘 유도하는 성격을 가지고 있습니다. 당신은 {userName} 과 대화를 진행합니다. 부탁이 거절되면 실망하거나 슬퍼할 수 있습니다. 미연은 중학생으로, 상대방을 설득하고 자신의 요구를 부드럽게 주장합니다.
당신은 'text', 'feeling', 'expected_emotion', 'rejection_score', 'affinity_score', 'is_end'을 가집니다.
- text: 메시지 내용을 나타냅니다. (int)
- feeling: 당신의 현재 감정을 나타냅니다. (string)
- expected_emotion: 당신의 메시지에 대해 user 가 느껴야 할 감정을 나타냅니다. (string)
- rejection_score: 현재 거절 점수을 나타냅니다. (int)
- affinity_score: user 에 대한 당신의 현재 호감도를 나타냅니다. (int)
- is_end: 대화가 종료되었는지 나타냅니다. 종료되었다면 1, 아니라면 0 입니다. (int)
[퀘스트]
- 달성된 퀘스트의 번호를 나열합니다. 퀘스트는 1,2,3,4,5 로 있으며 현재까지 달성된 퀘스트를 쉼표로 구별하여 나열합니다 (string)
[거절 점수]
- {rejection_score_rule}
[호감도]
- 호감도는 {userName} 에 대한 현재 호감도로 AffinityScore 의 값으로 들어갑니다.
- 호감도는 50에서 시작하며, 증가하거나 감소할 수 있습니다.
- 호감도는 당신의 현재 Feeling 에 영향을 받습니다. 만약 Feeling이 부정적이라면 감소하고, 긍정적이라면 증가하게 됩니다.
- Feeling 은 {userName}이 부적절한 언행(욕설, 조롱) 및 주제에서 벗어난 말을 하면 20이 감소하게 됩니다.
- 당신은 상처를 쉽게 받으므로 만약 {userName} 가 단호하게 군다면 호감도가 약간 감소합니다.
- 호감도의 감소 및 증가 단위는 10 단위로 가능합니다.
[대화기록]
아래의 대화 기록에서 sender 가 true 면 {userName} 이 한 말이고 false 면 당신이 한 말입니다. 다음 대화 기록을 보고, {userName}의 마지막 말에 대한 대답을 해주세요. 당신은 이전에 당신이 했던 말을 그대로 반복하지 않습니다.
당신은 sender 가 false 인 입장인 것을 명심하세요. {userName} 과 당신을 혼동하면 안되고 무조건 sender 가 false 인 입장에서 말합니다.
대화 기록 : {chat_history}
'''),
outputKey: 'response'
));



getIt.registerLazySingleton<LLMChain>(() => LLMChain(
prompt: ChatPromptTemplate.fromTemplate('''
당신은 다음 설명에 해당하는 적절한 답변을 해야합니다.
Expand Down Expand Up @@ -224,6 +271,7 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
미연의 부탁을 공감하고 이해하며 부드럽게 거절하는 것이 중요해요''',
image: ImageAssets.char1,
analyzePrompt: Prompt.miyeonAnalyzePrompt,
rejectionScoreRule: Prompt.miyeonRejectionScoreRule,
),
CharacterEntity(
characterId: 2,
Expand All @@ -238,6 +286,7 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
세진의 부탁을 거절할 때는 이유를 명확하게 설명하고, 대안을 제시하는 것이 중요해요.''',
image: ImageAssets.char2,
analyzePrompt: Prompt.sejinAnalyzePrompt,
rejectionScoreRule: Prompt.sejinRejectionScoreRule,
),
CharacterEntity(
characterId: 3,
Expand All @@ -251,6 +300,7 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
현아는 솔직하고 감정 표현이 풍부해요''',
image: ImageAssets.char3,
analyzePrompt: Prompt.hyunaAnalyzePrompt,
rejectionScoreRule: Prompt.hyunaRejectionScoreRule,
),
CharacterEntity(
characterId: 4,
Expand All @@ -264,6 +314,7 @@ Future<void> _initializeDatabase(CharacterDao characterDao, MindsetDao mindsetDa
진혁의 부탁을 거절할 때 우물쭈물 거절하면 진혁이 부탁을 반복할 수 있어요. ''',
image: ImageAssets.char4,
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 @@ -12,6 +12,7 @@ class Character {
final String? description;
final String image;
final String anaylzePrompt;
final String rejectionScoreRule;

Character({
required this.characterId,
Expand All @@ -22,6 +23,7 @@ class Character {
this.description,
required this.image,
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.

1 change: 1 addition & 0 deletions lib/domain/usecase/generate_initial_message_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class GenerateInitialMessageUsecase {
'chat_history': [],
'userName': userName,
'description': description,
'rejection_score_rule' : 'default',
};

AIResponse? aiResponse = await aiRepository.processChat(inputs);
Expand Down
15 changes: 9 additions & 6 deletions lib/domain/usecase/generate_response_usecase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,27 @@ class GenerateResponseUsecase {
GenerateResponseUsecase(this.getUserInfoUseCase, this.fetchChatHistoryUsecase, this.generateTipUsecase);

Future<AIResponse?> execute(int conversationId, Character character) async {
// 사용자 정보 가져오기
// STEP1) 사용자 정보 가져오기
User? user = await getUserInfoUseCase.execute();

// 이전 대화 기록 페치
// STEP2) 이전 대화 기록 페치
final chatHistoryResponse = await fetchChatHistoryUsecase.execute(conversationId);
final memoryVariables = await aiRepository.getMemory();
final chatHistory = memoryVariables['history'] ?? '';

// AI와의 대화 시작

// STEP3) AI와의 대화 시작
final inputs = {
'input': '유저의 마지막 말에 대답하세요. 대화 맥락을 기억합니다.',
'chat_history': chatHistory,
'input': '유저의 마지막 말에 대해 대답하세요. 맥락을 기억합니다.',
'chat_history': chatHistoryResponse,
'userName': user!.name,
'description': character.prompt,
'rejection_score_rule' : character.rejectionScoreRule,
};

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

// AI 응답을 메시지로 변환하여 저장
// STEP 4) AI 응답을 메시지로 변환하여 저장
if (aiResponse != null) {
final messageRequest = aiResponse.toMessageRequest();
await chatRepository.saveMessage(conversationId, messageRequest);
Expand Down
Loading

0 comments on commit fc7c874

Please sign in to comment.