안녕하세요.
ChatGPT API로 챗봇 만들기 두번째 시간입니다.
지난 시간에는 ChatGPT API를 사용하기 위한 설정 후 postman에서 api에 요청을 보내고 응답을 받는 방법에 대해 알아보았습니다.
해당 내용은 다음 링크를 참고해주세요.
2024.05.02 - [안드로이드 자바] - [JAVA][Android] ChatGPT API로 챗봇 만들기 - (1) ChatGPT API 사용하기
오늘은 안드로이드에서 챗봇과 주고 받은 메시지를 띄우기 위한 리사이클러뷰를 만들어 보겠습니다.
1. MainActivity 레이아웃 그리기
먼저 안드로이드 스튜디오에서 새 프로젝트 생성 후 MainActivity의 레이아웃 파일을 다음과 같이 작성합니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<EditText
android:id="@+id/et_msg"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginVertical="8dp"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:background="@null"
android:ems="10"
android:gravity="start|center_vertical"
android:inputType="textMultiLine" />
<Button
android:id="@+id/btn_send"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:enabled="false"
app:icon="@drawable/ic_send" />
</LinearLayout>
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2. ChatMsg 클래스 생성
챗봇과 주고 받은 메시지 데이터를 다루기 위한 ChatMsg 클래스를 생성합니다.
public class ChatMsg {
public static final String ROLE_ASSISTANT = "assistant"; // 챗봇 메시지
public static final String ROLE_USER = "user"; // 내 메시지
public String role; // 누가 보낸 메시지인지 확인
public String content; // 메시지 내용
public ChatMsg(String role, String content) {
this.role = role;
this.content = content;
}
}
3. 아이템 레이아웃 생성
내가 보낸 채팅과 챗봇이 보낸 채팅이 서로 다르게 표시되어야 합니다.
따라서 각각의 메시지를 화면에 그릴 때 사용할 아이템 레이아웃을 만듭니다.
3-1. 내 메시지 레이아웃 만들기
우선 메시지가 말풍선처럼 보이게 하기 위해서 사용할 background를 drawable 폴더에 생성합니다.
bg_my_chat.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#DFD3FF"/>
<corners android:radius="24dp"/>
<stroke android:color="@android:color/holo_purple"
android:width="1dp"/>
</shape>
그리고 layout 폴더에 내 메시지를 그릴 때 사용할 아이템 레이아웃을 생성합니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/tv_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:background="@drawable/bg_my_chat"
android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
android:text="메시지"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
3-2. 챗봇 메시지 레이아웃 만들기
마찬가지로 챗봇 메시지에 사용할 background를 drawable 폴더에 생성합니다.
bg_bot_chat.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/white"/>
<corners android:radius="24dp"/>
<stroke android:color="@android:color/holo_purple"
android:width="1dp"/>
</shape>
layout 폴더에 아이템 레이아웃을 생성합니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/tv_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="300dp"
android:background="@drawable/bg_bot_chat"
android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
android:text="메시지"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
4. 리사이클러뷰 어댑터 클래스 생성
이제 리사이클러뷰에 사용할 어댑터를 만들어줍니다.
해당 어댑터에서는 내 메시지와 챗봇의 메시지를 처리하기 위한 뷰홀더를 각각 만듭니다.
그리고 각 아이템의 뷰타입을 이용해 내가 보낸 메시지인지 챗봇이 보낸 메시지인지에 따라 각각의 뷰홀더를 사용하도록 합니다.
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class ChatMsgAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<ChatMsg> dataList;
//데이터 리스트를 세팅하기 위한 메서드입니다.
public void setDataList(List<ChatMsg> dataList) {
this.dataList = dataList;
notifyDataSetChanged();
}
//채팅 메시지가 추가되었을 때 어댑터에 반영해주기 위한 메서드입니다.
public void addChatMsg(ChatMsg chatMsg) {
dataList.add(chatMsg);
notifyItemInserted(dataList.size());
}
//각 아이템의 뷰타입 호출시 ChatMsg 클래스의 role에 따라 내 메시지는 0 / 챗봇의 메시지는 1을 반환하도록 아래와 같이 오버라이드 합니다.
@Override
public int getItemViewType(int position) {
if (dataList.get(position).role.equals(ChatMsg.ROLE_USER)) return 0;
return 1;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
// 뷰타입이 0 이면 MyChatViewHolder를 반환
if (viewType == 0) {
return new MyChatViewHolder(inflater.inflate(R.layout.item_my_chat, parent, false));
}
// 아니면 BotChatViewHolder 반환
return new BotChatViewHolder(inflater.inflate(R.layout.item_bot_chat, parent, false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
ChatMsg chatMsg = dataList.get(position);
if (chatMsg.role.equals(ChatMsg.ROLE_USER)) {
((MyChatViewHolder) holder).setMsg(chatMsg);
} else {
((BotChatViewHolder) holder).setMsg(chatMsg);
}
}
@Override
public int getItemCount() {
return dataList == null ? 0 : dataList.size();
}
// 내가 보낸 메시지를 띄우기 위한 뷰홀더입니다.
class MyChatViewHolder extends RecyclerView.ViewHolder {
private TextView tvMsg;
public MyChatViewHolder(@NonNull View itemView) {
super(itemView);
tvMsg = itemView.findViewById(R.id.tv_msg);
}
public void setMsg(ChatMsg chatMsg) {
tvMsg.setText(chatMsg.content);
}
}
//챗봇의 메시지를 띄우기 위한 뷰홀더입니다.
class BotChatViewHolder extends RecyclerView.ViewHolder {
private TextView tvMsg;
public BotChatViewHolder(@NonNull View itemView) {
super(itemView);
tvMsg = itemView.findViewById(R.id.tv_msg);
}
public void setMsg(ChatMsg chatMsg) {
tvMsg.setText(chatMsg.content);
}
}
}
5. MainActivity 작성
이제 MainActivity 코드를 작성합니다.
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
ChatMsgAdapter adapter;
Button btnSend;
EditText etMsg;
ProgressBar progressBar;
List<ChatMsg> chatMsgList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//뷰 객체 연결
recyclerView = findViewById(R.id.recyclerView);
btnSend = findViewById(R.id.btn_send);
etMsg = findViewById(R.id.et_msg);
progressBar = findViewById(R.id.progressBar);
//채팅 메시지 데이터를 담을 list 생성
chatMsgList = new ArrayList<>();
//리사이클러뷰 초기화
recyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
adapter = new ChatMsgAdapter();
adapter.setDataList(chatMsgList);
recyclerView.setAdapter(adapter);
//메시지 전송버튼 클릭 리스너 설정 (람다식으로 작성함)
btnSend.setOnClickListener(v -> {
//etMsg에 쓰여있는 텍스트를 가져옵니다.
String msg = etMsg.getText().toString();
//새로운 ChatMsg 객체를 생성하여 어댑터에 추가합니다.
adapter.addChatMsg(new ChatMsg(ChatMsg.TYPE_MY_CHAT, msg));
//etMsg의 텍스트를 초기화합니다.
etMsg.setText(null);
//키보드를 내립니다.
InputMethodManager manager = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
});
//EditText 객체에 text가 변경될 때 실행될 리스너 설정
etMsg.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
//입력창에 메시지가 입력되었을 때만 버튼이 클릭 가능하도록 설정
btnSend.setEnabled(s.length() > 0);
}
});
}
@Override
protected void onStart() {
super.onStart();
// 테스트를 위한 더미 데이터 생성
// i가 짝수일 경우 내 메시지, 홀수일 경우 챗봇의 메시지로 생성되도록 10개의 채팅메시지 객체를 만들어 리스트에 넣습니다.
for (int i = 0; i < 10; i++) {
chatMsgList.add(new ChatMsg(i % 2, "메시지 " + i));
}
}
}
6. 시연 영상
위 코드를 실행했을 때 다음 영상과 같이 보인다면 성공입니다.
이렇게 챗봇을 만들기 위한 리사이클러뷰 만들기 까지 진행했습니다.
다음 시간에는 이제 ChatGPT API를 안드로이드에 연결해서 챗봇과 주고 받은 메시지가 리사이클러뷰에 보여지도록 하겠습니다.
'안드로이드 자바' 카테고리의 다른 글
[JAVA][Android] 네이버 로그인 API 사용하기 (0) | 2024.05.15 |
---|---|
[JAVA][Android]글자크기 맞춰 drawbleStart 이미지 크기 자동조절하기 (0) | 2024.05.11 |
[JAVA][Android] ChatGPT API로 챗봇 만들기 - (1) ChatGPT API 사용하기 (0) | 2024.05.03 |
[JAVA][Android] SharedPreferences에 객체 저장하기 (0) | 2024.04.27 |
[JAVA][Android] 카카오 지도에 현재 위치 표시하기 (12) | 2024.04.22 |