1. 개요
지난 글에서 챗봇을 만드는 글을 올렸습니다. 구현한 챗봇은 CLI환경에서 작동하는 형태였는데, 현 시중에 나와있는 ChatGPT나 Gemini등 다양한 챗봇들은 Web Server를 통해 GUI환경으로 보여집니다.
그래서 Web을 구현해서 비슷한 형태로 챗봇을 구현해 보도록 하겠습니다.
2. Web 구현
이번 글에서 프로젝트의 구조는 아래와 같습니다.
conversation-app/
├── node_modules/
├── public/
├── src/
│ ├── components/
│ │ ├── ConversationList.js
│ │ ├── AdminPage.js
│ │ ├── Login.js
│ │ ├── SignupPage.js
│ │ ├── ConversationDetail.js
│ │ └── ChatInput.js
│ ├── App.js
│ ├── App.css
│ ├── index.js
│ └── ...
├── package.json
└── ...
먼저 Web을 구성할 React기반의 폴더를 만들어줍니다.
아래와 같은 명령어를 사용하기 위해서는 Node.js와 npm이 선행적으로 설치되어있어야합니다.
npx create-react-app conversation-app #"conversation-app" 부분은 폴더명입니다.
cd conversation-app
- npx: 로컬이나 글로벌로 설치되지 않은 패키지를 일회성으로 실행할 수 있는 도구입니다.
- create-react-app: React 프로젝트를 빠르게 설정해주는 도구입니다.
- conversation-app: 생성될 프로젝트의 이름입니다. 원하는 이름으로 변경할 수 있습니다.
HTTP의 요청을 처리하기 위해서는 두 가지 방법이 있는데
axios와 fetch방식이 있습니다.
axios는 아래와 같이 React 프로젝트에서 설치를 해야합니다.
npm install axios
그 후 package.json파일에 dependencies 부분에 axios가 잘 들어가 있는지 확인합니다.
{
"dependencies": {
"axios": "^1.7.7",
}
}
fetch는 브라우저의 내장 API로 추가적인 라이브러리 설치는 필요하지 않습니다.
axios방식으로 하다가 오류가 발생해서 저는 fetch 방식으로 진행하게 되었습니다.
가. 페이지 작성
src/components내의 페이지들을 만들겠습니다.
저는 사람들이 많이 이용하는 ChatGPT 시안을 활용하여 만들어 보겠습니다.
기본적인 GPT는 좌측에 대화기록이 있고 메인에서 채팅을 주고받는 형태로 되어있습니다.
그래서 저는 5가지 js를 만들어서 활용하겠습니다.
- ConversationList.js
- ConversationDetail.js
- ChatInput.js
- AdminPage.js
- Login.js
- SignupPage.js
1) ConversationList.js
ConversationList.js에서 먼저 React를 import 해줍니다.
import React, { useEffect, useState } from 'react';
사용자에게 대화 목록을 표시하는 역할을 위해 ConversationList를 함수형 컴포넌트로 설정합니다.
const ConversationList = ({ conversations, onSelectConversation }) => {
return (
<div className="conversation-list">
{conversations.map((conversation) => (
<div
key={conversation.id}
onClick={() => onSelectConversation(conversation)}
className="conversation-item"
>
<h4>대화 {conversation.id}</h4>
</div>
))}
</div>
);
};
이 컴포넌트는 두 가지의 props를 받습니다:
- conversations: 각 대화 객체를 포함하는 배열
- onSelectConversation: 대화 항목이 클릭될 때 호출되는 함수
- conversations 배열을 map 함수를 사용하여 순회하면서 각 대화 객체에 대해 div 요소를 생성합니다.
- 각 대화 항목 div의 주요 속성:
- key={conversation.id}: React에서 리스트를 렌더링할 때 각 항목을 고유하게 식별하기 위해 사용합니다.
- onClick={() => onSelectConversation(conversation)}: 대화 항목이 클릭되면 onSelectConversation 함수가 호출되고, 해당 대화 객체가 인자로 전달됩니다.
- className="conversation-item": 각 대화 항목에 적용되는 CSS 클래스입니다.
2) ConversationDetail.js
const ConversationDetail = ({ token, conversationId }) => {
const [conversation, setConversation] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
- conversation : 불러온 대화 대이터를 저장
- loading : 데이터 로딩 상태
- error : 데이터 요청 중 발생한 오류 메시지 저장
useEffect(() => {
if (conversationId !== null && token) {
fetchConversation();
}
}, [conversationId, token]);
- 의존성 배열: [conversationId, token]
- conversationId 또는 token이 변경될 때마다 실행됩니다.
- 조건문:
- conversationId가 null이 아니고 token이 존재할 경우 fetchConversation 함수를 호출하여 데이터를 불러옵니다.
const fetchConversation = async () => {
setLoading(true);
setError(null);
try {
const response = await fetch(`http://localhost:8000/conversations/${token}/${conversationId}`);
if (!response.ok) {
throw new Error('대화를 불러오는 중 오류가 발생했습니다.');
}
const data = await response.json();
setConversation(data.conversation);
} catch (err) {
console.error(err);
setError(err.message);
} finally {
setLoading(false);
}
};
API를 호출하여 특정 대화의 상세 정보를 가져오는 로직으로 과정은 아래와 같습니다.
- 과정:
- setLoading(true): 로딩 상태를 활성화합니다.
- setError(null): 이전의 오류 상태를 초기화합니다.
- API 요청:
- URL: "http://localhost:8000/conversations/${token}/${conversationId}"
- 응답 처리:
- 응답이 성공적이지 않으면 오류를 던집니다.
- 성공 시, 응답 데이터를 JSON으로 파싱하고 setConversation(data.conversation)을 통해 상태를 업데이트합니다.
- 오류 처리:
- 오류 발생 시, 콘솔에 로그를 남기고 setError(err.message)를 통해 오류 메시지를 상태에 저장합니다.
- 최종 처리:
- setLoading(false): 로딩 상태를 비활성화합니다.
if (loading) {
return <div>로딩 중...</div>;
}
if (error) {
return <div style={{ color: 'red' }}>{error}</div>;
}
if (conversation === null) {
return <div>안녕하세요. BJ-GPT입니다. 무엇이든 물어보시면 답변해드릴께요.</div>;
}
return (
<div className='main-content'>
<h3>대화 내용</h3>
<p><strong>사용자:</strong> {conversation.user_input}</p>
<p><strong>BJ-GPT:</strong> {conversation.ai_response}</p>
</div>
);
};
- 로딩 상태 (loading이 true인 경우):
- <div>로딩 중...</div>을 렌더링하여 사용자에게 로딩 중임을 표시합니다.
- 오류 상태 (error가 존재하는 경우):
- 오류 메시지를 빨간색 텍스트로 표시합니다.
- 대화 데이터 없음 (conversation이 null인 경우):
- 기본 인삿말인 "안녕하세요. BJ-GPT입니다. 무엇이든 물어보시면 답변해드릴께요."를 표시합니다.
- 대화 데이터 존재 (conversation이 존재하는 경우):
- 대화 내용을 상세히 표시합니다:
- 사용자 입력: conversation.user_input
- BJ-GPT의 응답: conversation.ai_response
- 대화 내용을 상세히 표시합니다:
'AI > LLM' 카테고리의 다른 글
누구나 쉽게 만드는 LLM을 활용한 챗봇(Web) -2 (3) | 2024.10.10 |
---|---|
누구나 쉽게 만드는 LLM을 활용한 챗봇 (2) | 2024.09.18 |
댓글