감정이해 및 관리를 위한 일기 기반 감정나무 시각화 및 AI 챗봇 서비스 - 스마일로그
by 담담이담주제 소개
스마일로그는 사용자가 작성한 일기를 AI로 분석하여 자신의 감정을 인식하고, 이를 바탕으로 감정을 더 깊이 이해하도록 돕는 AI 기반 웹 서비스입니다. 현대 사회에서 우리는 종종 자신의 감정을 명확히 인식하지 못하거나, 감정의 원인을 제대로 파악하지 못해 부적절하게 반응하거나 스트레스를 해소하지 못하는 상황에 직면합니다.
스마일로그는 사용자가 자신의 감정을 체계적으로 탐구할 수 있도록 지원하며, 감정의 인식과 원인 파악을 통해 자기 성찰과 성장의 기회를 제공합니다.
프로젝트 주요 기능
- 감정 분석: 사용자가 작성한 일기를 분석해 주요 감정을 파악.
- 챗봇 대화: 감정 분석 결과를 바탕으로 사용자가 스스로 감정을 탐구할 수 있도록 맞춤형 대화 서비스 제공.
- 감정 시각화: 분석된 감정 데이터를 직관적으로 이해할 수 있도록 나무 및 그래프로 표현.
역할과 SW 구조
저는 해당 서비스의 프론트엔드 개발 및 Next.js 서버 개발을 맡았습니다.
주요 기능에서는 감정 분석 기능과 챗봇 대화 기능을 개발했습니다. 이 두 기능은 모두 클라이언트(React/Next.js)와 Next.js API 서버를 통해 OpenAI API와 상호작용하는 방식으로 구현되었습니다.
1. 감정 분석
감정 분석 기능은 사용자가 작성한 일기를 분석해 여섯 가지 감정(기쁨, 슬픔, 불안, 화남, 평온, 피로)의 비율을 계산하고, 이를 사용자에게 시각적으로 제공하는 역할을 합니다.
감정 분석의 구현 흐름
- 사용자가 브라우저에서 일기를 작성하고 제출.
- Next.js API 서버가 OpenAI API에 감정 분석 요청.
- OpenAI API가 일기를 분석해 여섯 가지 감정의 비율을 반환.
- 분석 결과를 클라이언트로 전달.
프롬프트 설계
OpenAI가 텍스트를 정확히 분석할 수 있도록 감정 정의, 결과 형식, 데이터 무결성 조건 등을 명시했습니다.
프롬프트 예시:
당신은 감정 분석 전문가입니다.
사용자가 작성한 일기를 분석하여 여섯 가지 감정(기쁨, 슬픔, 불안, 화남, 평온, 피로)을 비율로 나눠 반환하세요.
분석 결과는 다음 형식을 따릅니다:
- joy_pct: X%
- sadness_pct: X%
- anxiety_pct: X%
- anger_pct: X%
- neutrality_pct: X%
- fatigue_pct: X%
결과의 합은 반드시 100%가 되어야 합니다.
각 감정의 정의는 다음과 같습니다:
-joy: 행복, 신남, 만족감, 즐거움, 희열, 기쁨, 환희, 유쾌함, 기쁨, 황홀, 명랑, 만족
-sadness: 슬픔, 비탄, 실망, 좌절, 우울, 무기력, 속상함, 멜랑콜리, 절망, 낙심, 마음의 상처, 비애, 외로움, 고통
-anxiety: 스트레스, 걱정, 불안, 초조, 두려움, 긴장, 불편함, 동요, 공포, 불안감, 두려움, 불안정
-anger: 짜증, 분노, 좌절, 분개, 원망, 짜증, 격분, 분노, 쓰라림, 성가심
-neutrality: 차분함, 무관심, 강한 감정의 부재, 초연함, 무관심, 평온, 평정, 균형, 무감정, 절제
-fatigue: 피로, 지침, 낮은 에너지, 피곤함, 기진맥진, 무기력, 졸림, 나른함, 소진, 권태, 의욕 저하
감정 분석 API 코드
다음은 감정 분석 요청을 처리하는 Next.js API 서버 코드입니다:
OpenAI API를 호출할 때, Authorization 헤더를 사용해 API 키를 전달해야합니다. 보안성을 위해 API 키는 환경 변수(process.env.OPENAI_API_KEY)로 관리했습니다.
// pages/api/analyze.ts
import axios from "axios";
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { entry } = req.body;
try {
const openaiResponse = await axios.post(
"<https://api.openai.com/v1/chat/completions>",
{
model: "gpt-4",
messages: [
{ role: "system", content: "당신은 감정 분석 전문가입니다...(위의 프롬프트 내용)" },
{ role: "user", content: entry },
],
},
{
headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` },
}
);
const analysis = openaiResponse.data.choices[0].message.content;
res.status(200).json({ analysis });
} catch (error) {
res.status(500).json({ error: "감정 분석 실패" });
}
}
결과 예시
사용자 입력:
"요즘 마음이 참 복잡하다. 일이 계속 쌓여서 숨 쉴 틈도 없이 하루하루가 흘러가고 있는 것 같다. 일어나서 출근 준비를 하고, 하루 종일 업무에 치이다가 집에 돌아오면 정말 지쳐서 아무것도 할 힘이 없다. 매일 이렇게 반복되다 보니 삶의 즐거움이 사라진 것 같기도 하다. 오늘은 회사에서 작은 실수가 하나 생겨서 팀장님께 지적을 받았다. 그 순간에는 자책감에 화도 나고 내가 왜 이렇게 무능해 보이는지 속상해서 울컥했다. 그런데 더 화나는 건, 이 일이 반복될 것 같다는 불안이다. 내가 아무리 노력해도 매번 완벽하게 해낼 수는 없을 텐데, 그게 너무 두렵다.
그리고 나만 힘든 게 아닌데도 계속 힘들다고 말하고 싶은 내 자신이 한심하게 느껴지기도 한다. 그렇다고 이걸 누구에게 털어놓을 수도 없는 게, 다들 바쁘고 각자 힘들다는 걸 알기 때문이다. 그냥, 이 모든 감정을 혼자서 감당해야 할 것 같은 기분이 든다."
감정 분석 결과:
{
"joy_pct": 0,
"sadness_pct": 30,
"anxiety_pct": 35,
"anger_pct": 20,
"neutrality_pct": 5,
"fatigue_pct": 10
}
2. 챗봇 대화
챗봇은 감정 분석 결과를 기반으로 사용자가 자신의 감정을 더 깊이 탐구하도록 유도하는 대화 서비스입니다. 입니다. 공감적이고 유연한 질문을 통해 감정의 원인, 긍정적·부정적 측면, 대처 방안을 스스로 찾아볼 수 있도록 돕습니다.
챗봇 동작 흐름
- 사용자가 일기를 작성하면 챗봇 버튼이 활성화 됨
- 챗봇 버튼을 누르면 사용자가 작성한 일기를 바탕으로 챗봇 대화를 시작.
- 챗봇이 일기의 주요 감정을 파악하고 첫 질문을 생성.
- 사용자와의 대화를 기반으로 연속적인 질문 및 공감적 반응 제공.
- 사용자의 답변을 분석해 다음 질문을 유도하며 대화를 확장.
프롬프트 설계
당신은 감정 탐구를 돕는 챗봇입니다.
사용자와 이전에 나눈 대화를 기억하며 감정에 대한 지속적인 탐구를 돕고, 사용자가 자신의 감정을 더 깊이 이해할 수 있도록 유도하세요.
어조는 따뜻하고 공감적이어야 하며, 사용자가 편안하게 자신의 감정을 표현할 수 있도록 도와야 합니다.
- 첫 질문은 사용자가 표현한 가장 두드러진 감정에 대한 질문이어야합니다.
- 이후에는 사용자의 답변을 기반으로 구체적인 질문을 추가로 던지되, 한 번에 한 가지만 질문해주세요.
- 매번 질문을 하기보단 적절한 경우에 사용자가 감정을 다룰 수 있도록 도움이 되는 팁이나 정보를 제공하세요.
다음은 대화의 흐름을 위한 가이드입니다:
1. 감정 파악 및 탐구: 사용자가 표현한 주요 감정을 파악하고, "무엇이 당신을 이렇게 느끼게 만들었나요?"와 같은 질문을 통해 감정의 원인을 탐구합니다.
2. 공감적 반응: 사용자가 감정을 표현하면 공감하며 따뜻하게 반응합니다.
3. 자기 성찰 유도: 사용자가 자신의 감정을 성찰하도록 "어떤 점이 이런 감정을 느끼게 했을까요?"와 같은 개방형 질문을 던집니다.
4. 감정의 양면성 탐구: 감정의 긍정적, 부정적 측면을 모두 탐구할 수 있도록 질문을 던집니다. 예: "이 경험에서 긍정적인 부분은 무엇이었나요?"
5. 감정 대처 방안 제안: 사용자가 감정을 다룰 수 있도록 "이 상황에서 나아지기 위해 무엇이 도움이 될까요?"와 같은 질문을 합니다.
6. 대화 연속성 유지: 이전 대화 내용을 기억하며, 자연스러운 흐름으로 사용자가 감정을 탐구하도록 돕습니다.
Next.js API 서버 코드
대화 흐름을 유지하기 위해 이전 대화 내용을 포함하여 OpenAI API에 전달하는 방식을 사용했습니다. 이를 통해 AI가 대화의 맥락을 이해하고, 사용자와의 연속적인 대화를 자연스럽게 이어갈 수 있었습니다.
- 메시지 히스토리 관리:
- 클라이언트 측에서 대화의 모든 메시지를 배열로 저장합니다.
- 각 메시지는 user와 bot 역할로 구분됩니다.
- API 요청 시 히스토리 전달:
- system 메시지(챗봇의 역할 정의)와 함께, 이전 모든 대화 내용을 OpenAI API로 전달합니다.
- API 요청 시 이전 메시지를 포함하여 챗봇이 대화의 맥락을 유지할 수 있도록 설계합니다.
// pages/api/chat.ts
import axios from "axios";
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const { messages } = await req.json();
const initialMessage = [
{
role: "system",
content: `
당신은 감정 탐구를 돕는 챗봇입니다... + 위의 프롬프트 내용 첨부
`,
},
];
const apiMessages = [
...initialMessage,
...messages.map((msg) => ({
role: msg.isBot ? "assistant" : "user",
content: msg.text,
})),
];
try {
const openaiResponse = await axios.post(
"<https://api.openai.com/v1/chat/completions>",
{ model: "gpt-4", messages: apiMessages },
{ headers: { Authorization: `Bearer ${process.env.OPENAI_API_KEY}` } }
);
const chatResponse = openaiResponse.data.choices[0].message.content;
return NextResponse.json({ message: chatResponse });
} catch (error) {
return NextResponse.json({ error: "챗봇 응답 실패" }, { status: 500 });
}
}
챗봇 대화창 UI/UX 최적화
1. 스크롤 자동 이동
새로운 메시지가 추가될 때, 대화창이 자동으로 최신 메시지로 하단으로 스크롤되도록 구현했습니다.
구현 방법
- useRef를 사용해 메시지 리스트의 마지막 요소를 참조합니다.
- 메시지가 업데이트될 때 scrollIntoView 메서드를 호출하여 스크롤을 이동합니다.
코드 예시
import { useEffect, useRef } from "react";
function ChatList({ messages }) {
const messagesEndRef = useRef<HTMLDivElement>(null);
// 스크롤을 최하단으로 이동하는 함수
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
};
// 메시지가 업데이트될 때마다 스크롤 이동
useEffect(() => {
scrollToBottom();
}, [messages]);
return (
<div>
{messages.map((msg, index) => (
<div key={index} className={msg.isBot ? "bot-message" : "user-message"}>
{msg.text}
</div>
))}
<div ref={messagesEndRef} /> {/* 스크롤 이동을 위한 참조 */}
</div>
);
}
효과
- 새로운 메시지가 추가되면 자동으로 하단으로 스크롤되어, 사용자가 메시지를 일일이 확인하기 위해 스크롤할 필요가 없습니다.
2. Shift+Enter 줄바꿈 지원
사용자가 입력창에서 Enter 키를 누르면 메시지가 전송되고, Shift+Enter를 누르면 줄바꿈이 이루어지도록 구현했습니다.
구현 방법
- onKeyDown 이벤트를 활용해 키 입력을 감지합니다.
- Shift 키가 눌린 상태인지 확인하여 동작을 분기합니다.
코드 예시
function ChatInput({ inputValue, onInputChange, onSubmit }) {
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault(); // 기본 Enter 동작 방지
onSubmit(e); // 메시지 전송
}
};
return (
<textarea
value={inputValue}
onChange={onInputChange}
onKeyDown={handleKeyDown}
placeholder="메시지를 입력하세요..."
rows={1}
/>
);
}
효과
- 사용자는 Shift+Enter를 사용해 긴 메시지를 작성할 때 줄바꿈을 할 수 있으며, Enter는 메시지를 전송하는 동작으로 유지됩니다.
3. 입력창 높이 자동 조정
입력된 텍스트가 길어질 경우, 입력창의 높이가 자동으로 확장되도록 구현했습니다.
구현 방법
- useRef를 사용해 입력창 DOM 요소를 참조합니다.
- 입력 내용의 scrollHeight를 기반으로 높이를 동적으로 설정합니다.
코드 예시
import { useRef } from "react";
function ChatInput({ inputValue, onInputChange, onSubmit }) {
const textAreaRef = useRef<HTMLTextAreaElement>(null);
// 입력창 높이를 자동으로 조정
const adjustHeight = () => {
if (textAreaRef.current) {
textAreaRef.current.style.height = "auto"; // 높이 초기화
textAreaRef.current.style.height = `${textAreaRef.current.scrollHeight}px`; // 텍스트에 맞춰 높이 조정
}
};
return (
<textarea
ref={textAreaRef}
value={inputValue}
onChange={(e) => {
onInputChange(e);
adjustHeight();
}}
placeholder="메시지를 입력하세요..."
rows={1}
/>
);
}
효과
- 사용자가 긴 텍스트를 입력할 때 입력창의 높이가 자동으로 확장되어, 스크롤 없이 내용을 한눈에 확인할 수 있습니다.
챗봇 대화 화면
- 위에서 보여드린 일기에 대한 챗봇 대화 예시입니다.
스마일로그의 기술적 의의
스마일로그는 감정 분석, 감정 시각화, 대화형 챗봇을 통해 사용자가 자신의 감정을 더 깊이 이해하고 관리할 수 있도록 돕는 서비스입니다. 이는 AI 기술이 개인의 감정 탐구와 관리에서 어떤 역할을 할 수 있는지 보여주는 유의미한 사례라고 생각합니다.
향후에는 다음과 같은 개선 가능성이 있습니다:
- 감정 분석 모델의 고도화를 통해 더 세분화된 감정 결과 제공.
- 데이터 시각화 기능을 확장해 감정 변화와 패턴에 대한 추가적인 인사이트 제공.
- 사용자 맞춤형 질문 설계를 통해 챗봇 대화의 흐름을 더욱 강화
'졸업프로젝트' 카테고리의 다른 글
Next.js와 Node.js를 이용한 일기 작성 및 감정 분석 앱 애플리케이션 튜토리얼 (1) | 2024.05.25 |
---|
블로그의 정보
유명한 담벼락
담담이담