프로젝트에서 chat-GPT 기능을 활용하여 채팅형식의 심리상담을 받을 수 있는 기능을 구현하였다. 여기서 적용한 내용과 개선해야 될 점에 대해서 정리하였다.
UI는 카카오톡과 같은 채팅페이지를 비슷하게 벤치마킹하여 구성하였다. 여기서 자신의 고민을 작성 후, UX를 고려하여 Enter 또는 전송 버튼을 누르게 되면 메세지가 전송이 된다.
서버에 텍스트를 전송하고 chat-GPT와 연동된 백엔드에서 대답을 생성한 뒤 답장을 보내주는 형식이다.
답변을 받는 시간이 짧으면 3초 길면 10초 정도로 시간이 소요되기 때문에 mask를 사용하여 답변을 받기 전까지는 질문을 할 수 없도록 UI를 구성하였다. 또한 사용자가 진행중임을 알 수 있도록 . .. ... 을 반복시켜 진행상황에 문제가 없음을 UX적인 부분도 고려하였다.
아래는 구현한 코드의 일부분이다.
// components/units/chatGPT/ChatGPT.container.tsx
// loading 이거나 빈 문자열을 보낼경우 early return 시켰다.
const submitKeyPressUserText = (e: KeyboardEvent<HTMLInputElement>) => {
if (loading) {
return;
}
if (userText === "") {
return;
}
if (e.charCode == 13) {
submitUserText();
}
};
// 메세지 저장방식은 하나의 배열에서 관리하여 기존 배열의 값을 복사하고, 새로운 값을 추가하는 형식으로 구성하였다.
const submitUserText = async () => {
setMessageList((prevText) => [...prevText, userText]);
setUserText("");
setLoading(true);
try {
const response = await postUserQuestion({ accessToken, text: userText });
setMessageList((prevText) => [...prevText, response]);
} catch (error) {
setMessageList((prevText) => [
...prevText,
"통신에 에러가 발생했습니다. 나중에 다시 시도해 주세요.",
]);
throw error;
} finally {
setLoading(false);
}
};
// components/units/chatGPT/ChatGPT.presenter.tsx
import { ExclamationCircleFilled, SendOutlined } from "@ant-design/icons";
import * as S from "./ChatGPT.styles";
import ScrollToBottom from "react-scroll-to-bottom";
import { IChatGPTProps } from "./ChatGPT.types";
export default function ChatGPTUI({
userText,
handleChangeUserText,
submitUserText,
messageList,
loading,
submitKeyPressUserText,
}: IChatGPTProps) {
return (
<>
<S.Position>
<S.Wrapper>
{loading && ( // post요청시 true로 변경되어 마스크 적용
<S.LodingWrapper>
<S.LoadingNotice></S.LoadingNotice>
</S.LodingWrapper>
)}
<S.TitleWrapper>
<S.Title>당신의 고민을 들려주세요</S.Title>
<S.Notice>
<ExclamationCircleFilled
style={{ color: "#fff", fontSize: "1.5rem" }}
/>
<div>
개인정보 보호를 위해 채팅 내용은 저장되지 않습니다. 채팅 창을
나가면 대화 내용이 사라집니다.
</div>
</S.Notice>
</S.TitleWrapper>
<S.ChatBody>
<ScrollToBottom mode="bottom">
<S.ChatWrapper>
// 메세지 리스트는 하나의 배열로 관리되며, 짝수일 경우 유저가 작성한 채팅이며
// 홀수일 경우 chat-GPT가 답변한 채팅으로 구성하였다.
{messageList?.map((text: string, index: number) => {
return (
<>
{index % 2 === 0 ? (
<S.WrapperMessageUser key={index}>
<S.MessageUser>{text}</S.MessageUser>
</S.WrapperMessageUser>
) : (
<S.WrapperMessageGPT key={index}>
<S.MessageGPT>{text}</S.MessageGPT>
</S.WrapperMessageGPT>
)}
</>
);
})}
</S.ChatWrapper>
</ScrollToBottom>
</S.ChatBody>
<S.WrapperInput>
<S.TextInput
value={userText}
type="text"
placeholder="고민을 말해주세요!"
onChange={handleChangeUserText}
onKeyPress={submitKeyPressUserText}
/>
<S.SendBtn
onClick={submitUserText}
disabled={loading ? true : false}
>
<SendOutlined />
</S.SendBtn>
</S.WrapperInput>
</S.Wrapper>
</S.Position>
</>
);
}
성공적으로 받아와진 모습이다. 만약 무언가의 문제로 인해 답변이 정상적으로 받아지지 않는다면 통신에 에러가 발생했습니다. 나중에 다시 시도해 주세요.
라는 에러 메세지를 답변을 보여주게 된다.
react-scroll-to-bottom
이라는 라이브러리를 활용하여 이전 경험으로 채팅창 페이지 구현을 할 때, 채팅의 양이 많아지면 카카오톡과 같이 가장 최신 대화가 밑으로 보이도록 자동으로 스크롤이 되었지만 이상하게도 이번 프로젝트에서는 적용이 되지 않았다. 원인은 라이브러리가 height의 값을 인지하지 못해 요소가 overflow되어도 움직이지 않는 것 같은데.. 아직 해결중인 문제이다.
이러한 부분은 UX관점에서 대화가 길어지면 매번 답장을 확인할 때 스크롤해서 확인해야 되기 때문에 문제가 있음이 분명하다. 이러한 불편함이나 버그에 대해서 찾고 개선해서 더 나은 개발자가 되기 위해 노력하고 있다.