Skip to content

Commit

Permalink
feat: 감정 채널 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
aengzu committed Jul 9, 2024
1 parent a9ed5ad commit 5e07b1a
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 165 deletions.
12 changes: 12 additions & 0 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
PODS:
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- path_provider_foundation (0.0.1):
- Flutter
Expand All @@ -8,14 +10,20 @@ PODS:
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- vibration (1.7.5):
- Flutter

DEPENDENCIES:
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- Flutter (from `Flutter`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- vibration (from `.symlinks/plugins/vibration/ios`)

EXTERNAL SOURCES:
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
Flutter:
:path: Flutter
path_provider_foundation:
Expand All @@ -24,12 +32,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
vibration:
:path: ".symlinks/plugins/vibration/ios"

SPEC CHECKSUMS:
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
vibration: 7d883d141656a1c1a6d8d238616b2042a51a1241

PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796

Expand Down
248 changes: 132 additions & 116 deletions lib/constants/prompts.dart

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion lib/controller/character_loading_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class CharacterLoadingController extends GetxController {
chatViewModel.messages.insert(0, sentBotMessage);
}


Get.off(() => ChatScreen(viewModel: chatViewModel));
} catch (e) {
print('Failed to create conversation or get AI response: $e');
Expand Down
14 changes: 11 additions & 3 deletions lib/controller/chatting_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ import 'package:palink_v2/services/openai_service.dart';
import 'package:palink_v2/controller/user_controller.dart';
import 'package:flutter/material.dart';
import '../models/character.dart';
import '../models/emotion_vibration.dart';
import '../models/likability.dart';
import '../models/liking_level.dart';
import '../repository/chat_repository.dart';
import '../utils/message_utils.dart';
import '../views/chatting_view/conversation_end_loading.dart';
import 'package:vibration/vibration.dart';

class ChatViewModel extends GetxController {
final int chatRoomId;
final Character character;
final OpenAIService openAIService;
final OpenAIService openAIService;
final UserController userController = Get.put(UserController());
final EmotionVibration emotionVibration = EmotionVibration();

final ChatRepository chatRepository = ChatRepository();
TextEditingController textController = TextEditingController();
Expand All @@ -27,6 +30,7 @@ class ChatViewModel extends GetxController {
var isLoading = false.obs;
var likingLevels = <LikingLevel>[].obs;
var tipContent = ''.obs;
var backgroundColor = Colors.white.obs;

ChatViewModel(this.chatRoomId, this.character, this.openAIService);

Expand Down Expand Up @@ -54,7 +58,6 @@ class ChatViewModel extends GetxController {
}
}

// 메시지 전송 및 응답 처리 (+호감도, 팁 업데이트)
Future<void> sendMessage() async {
String text = textController.text;
if (text.isEmpty) return;
Expand Down Expand Up @@ -88,10 +91,15 @@ class ChatViewModel extends GetxController {
// ai의 호감도 화면에 표시
likingLevels.insert(0, LikingLevel(
likingLevel: aiResponse.affinityScore, messageId: sentBotMessage.messageId) as LikingLevel);
// AI의 감정에 따른 배경색 변경
print(aiResponse.expectedEmotion);
backgroundColor.value = emotionVibration.getColorForEmotion(aiResponse.expectedEmotion);
// AI의 감정에 따른 진동 실행
emotionVibration.vibrateForEmotion(aiResponse.expectedEmotion);
// 호감도 db 서버에 전송하기
chatRepository.sendLikingLevel(
userController.userId.value, character.characterId,
aiResponse.affinityScore, sentBotMessage!.messageId);
aiResponse.affinityScore, sentBotMessage.messageId);
// 팁 업데이트
Map? tipResponse = await openAIService.invokeTip(aiResponse);

Expand Down
60 changes: 60 additions & 0 deletions lib/models/emotion_vibration.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:vibration/vibration.dart';

class EmotionVibration {
final Map<String, Map<String, dynamic>> emotions = {
"Fear": {
"color": Colors.black.withOpacity(0.5),
"pattern": [100, 200, 100, 200]
},
"Surprise": {
"color": Colors.yellow.withOpacity(0.5),
"pattern": [500]
},
"Anger": {
"color": Colors.red.withOpacity(0.5),
"pattern": [2000]
},
"Sadness": {
"color": Colors.blue.withOpacity(0.5),
"pattern": [1000, 2000]
},
"Trust": {
"color": Colors.indigo.withOpacity(0.5),
"pattern": [500, 500, 500, 500]
},
"Happiness": {
"color": Colors.yellow.withOpacity(0.5),
"pattern": [300, 300, 300, 300]
},
"Disgust": {
"color": Colors.brown.withOpacity(0.5),
"pattern": [500, 500]
},
"Tension": {
"color": Colors.grey.withOpacity(0.5),
"pattern": [500, 500, 500, 500]
},
"Excitement": {
"color": Colors.red.withOpacity(0.5),
"pattern": [300, 300, 300, 300]
},
};

void vibrateForEmotion(String emotion) {
if (emotions.containsKey(emotion)) {
List<int> pattern = emotions[emotion]!['pattern'];
Vibration.vibrate(pattern: pattern);
} else {
print("Unknown emotion: $emotion");
}
}

Color getColorForEmotion(String emotion) {
if (emotions.containsKey(emotion)) {
return emotions[emotion]!['color'];
} else {
return Colors.white.withOpacity(0.5); // default color with opacity
}
}
}
2 changes: 1 addition & 1 deletion lib/services/chat_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class ChatService {

Future<Likability> sendLikingLevel(String userId, int characterId, int likingLevel, int messageId) async {
try {
print(userId);

final response = await _dio.post(
'/api/liking/create',
data: {
Expand Down
15 changes: 10 additions & 5 deletions lib/services/openai_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ class OpenAIService {
''');

final promptTemplate = ChatPromptTemplate.fromTemplate('''
당신은 미연입니다. 다음은 미연에 대한 설명입니다. 당신은 USER 를 {userName}으로 부르세요. rejection_score는 누적되어야하고 만약 -5보다 이하면 is_end를 1로 설정하세요.
당신은 USER 를 {userName}으로 부르세요. rejection_score는 누적되어야하고 만약 -5 이하면 is_end를 즉시 1로 설정하세요.
다음은 당신에 대한 설명입니다.
{description}
답변으로 'text', 'feeling', 'expected_emotion', 'rejection_score', 'affinity_score', 'is_end'을 반드시 JSON 객체로 리턴하세요.
답변으로 'text', 'feeling', 'expected_emotion', 'rejection_score', 'affinity_score', 'is_end'을 반드시 JSON 객체로 리턴하세요. ("```"로 시작하는 문자열을 생성하지 마세요)
{chat_history}
{userName}: {input}
Expand All @@ -47,10 +48,10 @@ class OpenAIService {
반드시 한국어로 하며, AI 캐릭터의 말투를 사용해서 평가해주세요.
{input}
답변으로 'evaluation', 'used_rejection', 'final_rejection_score' 을 반드시 JSON 객체로 리턴하세요.
'used_rejection'은 사용자가 '사용한 거절 능력(해당 능력의 점수)'를 나타냅니다.
답변으로 'evaluation' (string), 'used_rejection' (string), 'final_rejection_score' (int) 을 반드시 JSON 객체로 리턴하세요.
'evaluation'은 사용자의 대화 능력을 AI의 입장에서 100자 이내로 평가한 문자열입니다.
'used_rejection'은 사용자가 대화에서 '사용한 거절 능력(해당 능력의 점수)'의 목록을 나타냅니다.
'final_rejction_score'은 총 거절 점수입니다.
''');

OpenAIService(this.character, this.conversationId) {
Expand Down Expand Up @@ -121,6 +122,10 @@ class OpenAIService {
final Map<String, dynamic> contentMap = jsonDecode(aiChatMessage.content);
AIResponse aiResponse = AIResponse.fromJson(contentMap);
print(aiResponse.rejectionScore);
String jsonString = aiChatMessage.content;
print(jsonString);


return aiResponse;

} catch (e) {
Expand Down
1 change: 1 addition & 0 deletions lib/views/chatting_view/character_loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class CharacterLoadingView extends StatelessWidget {
@override
Widget build(BuildContext context) {
// CharacterLoadingController를 초기화합니다.
print('CharacterLoadingView: character: ${character.name}');
Get.put(CharacterLoadingController(character));

return Scaffold(
Expand Down
76 changes: 40 additions & 36 deletions lib/views/chatting_view/chat_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,49 +59,53 @@ class ChatScreen extends StatelessWidget {
centerTitle: true,
elevation: 0,
),
backgroundColor: Colors.white,
extendBodyBehindAppBar: false,
body: Stack(
children: [
Column(
body: Obx(() {
return Container(
color: viewModel.backgroundColor.value, // Update background color based on emotion
child: Stack(
children: [
Expanded(
Column(
children: [
Expanded(
child: Obx(() {
if (viewModel.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
return viewModel.messages.isEmpty
? const Center(
child: Text(
'No messages yet.',
style: TextStyle(color: Colors.black),
),
)
: Messages(
messages: viewModel.messages,
userId: userController.userId.value,
characterImg: viewModel.character.image,
likingLevels: viewModel.likingLevels.value,
);
}),
),
_sendMessageField(viewModel),
],
),
Positioned(
bottom: 110,
left: 20,
child: Obx(() {
if (viewModel.isLoading.value) {
return const Center(child: CircularProgressIndicator());
}
return viewModel.messages.isEmpty
? const Center(
child: Text(
'No messages yet.',
style: TextStyle(color: Colors.white),
),
)
: Messages(
messages: viewModel.messages,
userId: userController.userId.value,
characterImg: viewModel.character.image,
likingLevels: viewModel.likingLevels.value,
return TipButton(
tipContent: viewModel.tipContent.value,
isExpanded: tipViewModel.isExpanded.value,
isLoading: tipViewModel.isLoading.value,
onToggle: tipViewModel.toggle,
);
}),
),
_sendMessageField(viewModel),
],
),
Positioned(
bottom: 110,
left: 20,
child: Obx(() {
return TipButton(
tipContent: viewModel.tipContent.value,
isExpanded: tipViewModel.isExpanded.value,
isLoading: tipViewModel.isLoading.value,
onToggle: tipViewModel.toggle,
);
}),
),
],
),
);
}),
),
);
}
Expand Down Expand Up @@ -166,4 +170,4 @@ class ChatScreen extends StatelessWidget {
),
),
);
}
}
11 changes: 8 additions & 3 deletions lib/views/chatting_view/conversation_end_loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ class ConversationEndLoadingView extends StatelessWidget {
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 0.1.sw, vertical: 0.02.sh),
child: Text(
"현실적으로 생각해도 못하겠으면 빨리 거절해야 상대방이 다른 방법을 찾을 수 있다. 따라서 이 경우 거절이 좋은 배려이다.",
style: textTheme().bodyMedium,
child: Text.rich(
textAlign: TextAlign.center,
TextSpan(
text: '\n',
children: <TextSpan>[
TextSpan(text: ' 모든 사람을 만족시킬 수는 없다.\n', style: textTheme().titleMedium),
TextSpan(text: '\n모든 사람을 만족시키려 하면 자신을 잃게 됩니다. 스스로를 우선시하는 것이 중요합니다. 이는 우리의 정신적, 감정적 건강을\n 지키는 데 필요합니다.', style: textTheme().bodyMedium),
],
),
),
),
CircularProgressIndicator(color: Colors.blue),
Expand Down
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import FlutterMacOS
import Foundation

import device_info_plus
import path_provider_foundation
import shared_preferences_foundation
import url_launcher_macos

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
Expand Down
2 changes: 2 additions & 0 deletions macos/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
Expand Down
Loading

0 comments on commit 5e07b1a

Please sign in to comment.