플러터로 챗GPT 메시징 애플리케이션을 구축하는 방법
요즘은 친구들과 연락하는 데 시간이 너무 많이 걸립니다. 소셜 미디어와 메시징 앱이 등장하기 전에는 실제로 사람들과 시간을 보내야 했습니다. 지금은 메시지만 보내면 되니 조금 나아졌지만, 여전히 친구에게 무슨 말을 하고 소통할지 고민해야 하는 것은 고통스러운 일입니다.
이제 해결책이 있습니다! 더 이상 고민없이 친구들과 인공지능 채팅을 할 수 있습니다!
물론 농담입니다. 여러분은 여전히 친구들과 어울려야 하며, 친구와의 관계를 AI에 맡겨서는 안 됩니다. 하지만 봇에 답장을 보내거나 대화가 조금 지루해졌을 때 대화를 이어가는 데 도움을 줄 수 있는 멋진 사용 사례입니다.
이 글에서는 아고라챗을 사용하여 자신만의 채팅 애플리케이션을 구축한 다음 챗GPT를 추가하여 더욱 멋지게 만드는 방법을 다룹니다.
전체 코드는 여기에서 확인할 수 있습니다.
아고라챗
아고라챗을 사용하면 텍스트, 이미지, GIF, 이모티콘 및 기타 미디어를 포함하여 친구들과 소통할 수 있습니다. 아고라챗은 독립형 애플리케이션으로 사용하거나 영상 통화와 같은 실시간 커뮤니케이션(RTC)을 사용하는 기존 애플리케이션에 통합할 수 있습니다.
ChatGPT
오픈AI의 챗GPT는 메시지에 대해 매우 사실적인 응답을 생성할 수 있는 AI 모델입니다. 이 모델에 요청을 보내고 채팅에 삽입할 응답을 얻기 위해 오픈AI API를 사용할 것입니다.
설정
이러한 서비스와 상호 작용하려면 아고라와 OpenAI 모두에서 계정을 만들고 일부 토큰을 가져와야 합니다.
아고라챗 정보를 가져오는 방법
- Agora.io 에서 계정을 만듭니다. .
- 프로젝트를 만듭니다.
Chat
까지 아래로 스크롤하여Enable/Configure
를 클릭합니다.- 토글 버튼을 클릭하고 AppKey를 복사하여 붙여넣습니다.
- 왼쪽의
Operation Management
아래에서User
를 선택하고 두 개의 사용자를 만듭니다. (사용자 ID 를 메모해 두세요.) - 기본 정보 탭 아래의
Application Information
으로 돌아가서 Chat User Temp Token 필드에 각 사용자의 사용자 ID를 입력합니다.Generate
를 클릭합니다. 토큰과 사용자 ID를 복사하여consts.dart
파일에 붙여넣습니다.
오픈AI 토큰을 받는 방법
- OpenAI서 계정을 만듭니다.
- 오른쪽 상단에서 이미지를 클릭하고 View
View API Keys
를 선택합니다. - 새 시크릿 키를 생성하고
consts.dart
파일에 복사하여 붙여넣습니다.
챗 페이지
현재 사용자 아이디, 토큰, 메시지를 보내려는 사용자의 아이디가 있는 챗 페이지를 만들어야 합니다. 이 작업을 수행하는 방법은 여러 가지가 있지만, 이 예에서는 개별 사용자로 로그인할 수 있는 버튼 두 개를 만들었습니다. 자세한 내용은 main.dart
파일에서 확인할 수 있습니다.
챗 페이지를 시작하자마자 채팅이 초기화되려면 세 가지 일이 일어나야 합니다. 아직 아고라챗 SDK에 대한 설정이 완료되지 않았으므로 SDK를 초기화한 다음 메시지 수신기를 추가하고 마지막으로 현재 사용자를 로그인해야 채팅 애플리케이션을 완전히 사용할 준비가 됩니다. 이 세 가지 함수는 initState
에서 호출해야 합니다.
void _initSDK() async {
ChatOptions options = ChatOptions(
appKey: widget.chatKey,
autoLogin: false,
);
await ChatClient.getInstance.init(options);
await ChatClient.getInstance.startCallback();
}
void _addChatListener() {
ChatClient.getInstance.chatManager.addMessageEvent(
"UNIQUE_HANDLER_ID",
ChatMessageEvent(
onSuccess: (msgId, msg) {
debugPrint(
"send message succeed: ${(msg.body as ChatTextMessageBody).content}");
_addMessage(
DemoMessage(
text: (msg.body as ChatTextMessageBody).content,
senderId: widget.userId),
);
},
onProgress: (msgId, progress) {
debugPrint("send message succeed");
},
onError: (msgId, msg, error) {
debugPrint(
"send message failed, code: ${error.code}, desc: ${error.description}",
);
},
));
ChatClient.getInstance.chatManager.addEventHandler(
"UNIQUE_HANDLER_ID",
ChatEventHandler(onMessagesReceived: onMessagesReceived),
);
}
void _signIn() async {
try {
await ChatClient.getInstance.loginWithAgoraToken(
widget.userId,
widget.agoraToken,
);
debugPrint("login succeed, userId: ${widget.userId}");
} on ChatError catch (e) {
debugPrint("login failed, code: ${e.code}, desc: ${e.description}");
}
}
여기에 로그인 메서드가 있으므로 로그아웃 메서드도 만들어 보겠습니다. 이 메서드는 dispose
메서드에서 호출됩니다.
void _signOut() async {
ChatClient.getInstance.chatManager.removeMessageEvent("UNIQUE_HANDLER_ID");
ChatClient.getInstance.chatManager.removeEventHandler("UNIQUE_HANDLER_ID");
try {
await ChatClient.getInstance.logout(true);
debugPrint("sign out succeed");
} on ChatError catch (e) {
debugPrint(
"sign out failed, code: ${e.code}, desc: ${e.description}");
}
}
챗 리스너에서 호출되는 몇 가지 함수가 표시되지 않는 것을 알 수 있습니다:
_addMessage
는 수신 메시지를 표시되는 메시지 목록에 추가합니다.debugPrint
는 수신 메시지를 콘솔 로그에 추가합니다.onMessagesReceived
는 메시지가 수신될 때 호출되는 함수입니다. (_addMessage를 사용하여 양쪽의 목록을 보관할 수도 있습니다.)
아래는 해당 함수에 대한 정의입니다.
void onMessagesReceived(List<ChatMessage> messages) {
for (var msg in messages) {
switch (msg.body.type) {
case MessageType.TXT:
{
ChatTextMessageBody body = msg.body as ChatTextMessageBody;
debugPrint(
"receive text message: ${body.content}, from: ${msg.from}",
);
_addMessage(
DemoMessage(text: body.content, senderId: msg.from),
);
}
break;
default:
break;
}
}
}
void _addMessage(DemoMessage message) {
_messages.add(message);
setState(() {
scrollController.jumpTo(scrollController.position.maxScrollExtent + 40);
});
}
챗 표시하기
ListView.builder
는 _messages 목록에 있는 모든 메시지를 표시합니다. 또한 화면 하단에 메시지를 보낼 수 있는 TextField
를 추가해야 합니다.
ListView.builder(
controller: scrollController,
itemCount: _messages.length,
itemBuilder: (_, index) {
//show first 10 characters
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 2),
if (widget.userId != _messages[index].senderId)
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.lightBlue[100],
borderRadius: BorderRadius.circular(10),
),
child: Text(
_messages[index].text!,
),
)
else
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Flexible(
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.lightGreen[100],
borderRadius: BorderRadius.circular(10),
),
child: Text(
_messages[index].text!,
),
),
),
],
),
],
);
},),
메시지 보내기
메시지를 보내려면 아고라챗 SDK에서 sendMessage
함수를 호출해야 합니다. 이 함수는 ChatMessage
객체를 받습니다. 또한 메시지를 보내려는 사람의 사용자 ID를 전달해야 합니다.
void _sendMessage(String sentTo, String? message) async {
if (message == null) {
debugPrint("single chat id or message content is null");
return;
}
var msg = ChatMessage.createTxtSendMessage(
targetId: sentTo,
content: message,
);
ChatClient.getInstance.chatManager.sendMessage(msg);
setState(() {
_messageController.text = "";
});
}
이제 모든 기능을 갖춘 아고라챗 애플리케이션이 완성되었습니다. 마지막 단계는 챗GPT를 통합하여 AI가 생성한 응답을 활성화하는 것입니다.
챗GPT
챗GPT를 사용하려면 먼저 API에 연결해야 합니다. 또한 API의 응답을 기다리는 동안 보내기 버튼을 비활성화하는 데 사용되는 is isWaitingResponse
변수를 선언해야 합니다.
변수가 선언되면 상대방의 마지막 메시지에 대해 행복 또는 화난 응답을 보내는 함수를 설정할 수 있습니다.
final openAI = OpenAI.instance.build(
token: openAIToken,
baseOption: HttpSetup(receiveTimeout: const Duration(seconds: 30)),
isLog: true);
var _isWaitingResponse = false;
void _onTapSendHappyMessage() async {
final List<DemoMessage> otherMessages = _messages
.where((element) => element.senderId != widget.userId)
.toList();
_reset();
_sendAIMessage(
"Give me a happy response to the message: ${otherMessages.last.text}",
).then((value) {
setState(() {
_isWaitingResponse = false;
_messageController.text = value.trim();
});
});
}
void _onTapSendAngryMessage() async {
final List<DemoMessage> otherMessages = _messages
.where((element) => element.senderId != widget.userId)
.toList();
_reset();
_sendAIMessage(
"Give me an angry response to the message: ${otherMessages.last.text}",
).then((value) {
setState(() {
_isWaitingResponse = false;
_messageController.text = value.trim();
});
});
}
void _reset() {
setState(() {
_isWaitingResponse = true;
});
}
Future<String> _sendAIMessage(String message) async {
final request = CompleteText(
prompt: message,
model: Model.textDavinci3,
maxTokens: 200,
);
final response = await openAI.onCompletion(
request: request,
);
return response!.choices.first.text;
}
이것이 애플리케이션의 전체 기능입니다. 이제 이러한 응답을 생성하는 버튼을 추가하고 이를 TextField
의 TextController.value
에 넣어 사용자가 응답을 보낼 수 있도록 할 수 있습니다.
읽어주셔서 감사합니다. 여기를 클릭하여 아고라에 대해 자세히 알아보세요.