1. 前言
这篇文章旨在教大家快速构建一个可以使用ChatGPT api进行聊天的App。
2. 引入相关依赖
我们使用Volley来进行网络请求。
Volley是一个能够让Android应用更轻松、更快捷地联网的 HTTP 库,在API调用中经常使用
了解volley: developer.android.com/training/vo…
在build.gradle中引入Volley库
implementation 'com.android.volley:volley:1.1.1'
3. 开启联网权限
在AndroidManifest.xml中输入以下代码:
// 开启联网权限
<uses-permission android:name="android.permission.INTERNET"/>
4. 编写代码
4.1 分析
我们知道一个聊天软件,或者说网页版的ChatGPT,就是上面一个聊天界面,下面一个聊天框。
聊天框肯定不用多说,就是一个TextField(EditText)。
上面的聊天界面也不过就是一个列表罢了,可以根据是ChatGPT说的话还是用户自己发送的话来判断气泡框的左右。
下图是OpenAI官网给出的样图,那么我们可以模仿他来写一个。
4.2 准备数据类-消息
data class ChatMessage(var text: String, var type: Int)
4.3 准备消息列表
这个List用来存放消息
val messageList = remember { mutableStateListOf<ChatMessage>() }
4.4 发送网络请求
参照官网给出的文档,构建一个JSONObject来发送请求,收到Response后将消息放进messageList中。
private fun sendQuestion(question: String, messageList: SnapshotStateList<ChatMessage>){
val url = "https://api.openai.com/v1/completions"
// 创建一个请求队列
val queue: RequestQueue = Volley.newRequestQueue(applicationContext)
// 提问
val jsonObject = JSONObject()
jsonObject.put("model", "text-davinci-003")
jsonObject.put("prompt", question)
jsonObject.put("temperature", 0)
jsonObject.put("max_tokens", 300)
jsonObject.put("top_p", 1)
jsonObject.put("frequency_penalty", 0.0)
jsonObject.put("presence_penalty", 0.0)
val postRequest: JsonObjectRequest =
object : JsonObjectRequest(Method.POST, url, jsonObject,
Response.Listener { response ->
val responseMsg: String = response.getJSONArray("choices").getJSONObject(0).getString("text")
Log.d("reply", "getResponse: " + responseMsg)
messageList.add(ChatMessage(responseMsg.trim(), 1))
},
Response.ErrorListener { error ->
Log.d("OpenAI", "getResponse: " + error.message + "\n" + error)
}){
override fun getHeaders(): MutableMap<String, String> {
val params: MutableMap<String, String> = HashMap()
params["Content-Type"] = "application/json"
params["Authorization"] = "Bearer sk-xxx"
return params
}
}
queue.add(postRequest)
}
4.5 编写界面
- 聊天框
分析一下聊天框
传入的参数是text(对话内容),type(身份)
根据type确定对话框的颜色和身份显示
首先是一个纵向布局:Text显示身份(“ChatGPT”或者“Me”),Row里面的内容是对话框
Row里面的Divider是对话框左边的线,Text表示内容
@Composable
fun DialogBox(text: String, type: Int){
val identity: String = if(type == 0) "Me" else "ChatGPT"
val dialogColor: Color = if(type == 0) Color(0xFFE91E63) else Color(0xFF64B5F6)
Column(
modifier = Modifier.offset(x = 20.dp, y = 5.dp)
) {
Text(text = identity, color = dialogColor, fontWeight = FontWeight.Bold)
// 对话框
Row(
modifier = Modifier
.fillMaxWidth()
.height(IntrinsicSize.Min)
.offset(y = 2.dp)
) {
Divider(
color = dialogColor,
modifier = Modifier
.width(3.dp)
.fillMaxHeight()
.padding(0.dp, 8.dp)
)
Text(
text = text,
modifier = Modifier
.width(320.dp)
.padding(5.dp)
)
}
}
}
显示效果:
- 输入框
输入框没什么好说的,就是一个TextField设置一下形状和颜色。
按回车发送的时候调用刚刚写的sendQuestion方法
@Composable
fun inputBox(messageList: SnapshotStateList<ChatMessage>, modifier: Modifier){
var userInput by remember { mutableStateOf("") } // 用户输入
val context = LocalContext.current
TextField(
value = userInput,
onValueChange = {userInput = it},
placeholder = {
Text(text = "Send a chat")
},
shape = CircleShape,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color(0xFFEEEEEE),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Send),
keyboardActions = KeyboardActions(onSend = {
if (userInput.isEmpty()) Toast.makeText(context, "聊天内容不能为空", Toast.LENGTH_SHORT).show()
else{
messageList.add(ChatMessage(userInput, 0))
val question = userInput
userInput = ""
sendQuestion(question, messageList)
}
})
)
}
显示效果:
- 聊天列表
聊天列表使用LazyColumn
@Composable
fun chatList(messageList: SnapshotStateList<ChatMessage>, modifier: Modifier){
LazyColumn(modifier = modifier){
items(messageList){
DialogBox(text = it.text, type = it.type)
}
}
}
- 组合起来
@Composable
fun chatApp(messageList: SnapshotStateList<ChatMessage>){
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
) {
TopAppBar(
title = {Text("ChatGPT APP", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)},
backgroundColor = Color(0xFF0288D1),
contentColor = Color.White,
modifier = Modifier
)
chatList(messageList = messageList, modifier = Modifier.weight(1f))
inputBox(messageList = messageList, modifier = Modifier)
}
}
5. 最终效果
如果你看到了这里,觉得文章写得不错就给个赞呗?
更多Android进阶指南 可以扫码 解锁更多Android进阶资料
敲代码不易,关注一下吧。ღ( ´・ᴗ・` )