OpenAI开放了聊天机器人的接口,只要有账号,我们就可以利用接口实现一个聊天机器人应用。
API文档的地址[OpenAI Platform]
我们也可以利用ChatGPT来完成聊天功能的开发。但因为ChatGPT开发的资料也是来源于网络博客,关于OpenAI的使用的博客还不是很多,跟着ChatGPT的提示来进行聊天机器人的开发走了好多弯路啊,遂打算写一篇文章简单介绍一个这个接口的使用。
创建API_KEY
每次会话都需要验证API_KEY。点击右上角头像,选择“View API keys”进入API keys 页面,点击"create new secrat key"创建密钥,填入密钥名称。创建时需要将密钥记录下来,创建好后就看不到密钥了(没有好好看说明书的我只能重新创建一个密钥)。
这是Chat API文档的部分截图,展示了接口和会话的数据格式。model和messages是必要参数。messages是一个消息数组,里面存放若干消息,每次提问时可以将新的内容追加在messages后面。每个会话使用一个messages,这样ChatGPT能根据完整的会话信息进行回答。message必须指定role,普通用户直接指定为user即可。
创建会话
OpenAI没有Java语言的现成库,所以需要我们自己建立会话的连接,这里使用OKHttp创建会话。
创建项目后,导入相应的依赖库:
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.10.0'
implementation "com.google.code.gson:gson:2.8.7"
implementation 'com.tencent:mmkv:1.2.10'
implementation 'org.litepal.guolindev:core:3.2.3'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
Manifest申请网络权限:
<uses-permission android:name="android.permission.INTERNET" />
根据消息格式创建数据模型:
//会话数据模型:
data class BodyMsg(val model:String="gpt-3.5-turbo",val messages:Array<Message>)
data class Message(val role:String="user",val content:String)
//用于展示和保存的数据模型:
data class MsgModel(
var dialogId:Long,
val send: Boolean,
val content: String,
val timeStamp: Long = System.currentTimeMillis()
) :
LitePalSupport() {
constructor() : this(0L,false, "") //LitePal更新时需要一个无参构造函数
}
创建一个会话类,用于收发消息:
object ChatGPTClient {
private val TAG = "ChatGPTClient"
private val gson = Gson()
private const val API_URL = "https://api.openai.com/v1/chat/completions"
private const val API_KEY = "此处填入前面创建API_KEY"
private val client by lazy {
OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.build()
}
@Throws(IOException::class)
fun sendChatRequest(message: Message): String? =
sendChatRequest(arrayOf(message))
@Throws(Exception::class)
fun sendChatRequest(messages: Array<Message>): String? =
sendChatRequest(BodyMsg(messages = messages))
//发送消息,参数传入消息实体,返回值为端口返回的数据
@Throws(Exception::class)
fun sendChatRequest(body: BodyMsg): String? {
val mediaType: MediaType = "application/json".toMediaType()
val json: String = gson.toJson(body) //将消息转换为json格式
val body: RequestBody = RequestBody.create(mediaType, json)
val request: Request = Request.Builder()
.url(API_URL)
.post(body)
.addHeader("Authorization", "Bearer " + API_KEY) //填入API KEY
.build()
try {
val response = client.newCall(request).execute() //发送消息
return if (response.isSuccessful) {
response.body!!.string() //直接获取返回的消息
} else {
throw IOException("Unexpected response code: " + response.code + " " + response.message)
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
return null
}
}
使用,添加一个RecyclerView用于显示对话,添加一个EditText和Button用于编辑和发送消息,调用sendChatRequest进行消息的收发:
private fun send() {
if (mEtInput.text.isEmpty()) return
else {
changeMode(true) //页面状态切换
val msg = mEtInput.text.toString() //获取要发送的消息
mEtInput.setText("")
//先显示发送的消息
val sendModel = MsgModel(mDialogModel.id, true, msg)
mChatAdapter.addMsg(sendModel)
//协程中发送消息
mCoroutineScope.launch {
val message = Message(role = "user", msg) //创建消息
messages.add(message) //添加到会话消息队列
//发送消息,挂起等待结果
val responseJson =
ChatGPTClient.sendChatRequest(messages.toTypedArray())
val jsonObject = JSONObject(responseJson)
//根据返回的消息格式对结果进行解析
val messageJson =
jsonObject?.getJSONArray("choices")?.getJSONObject(0)?.getJSONObject("message")
messageJson?.let {
val msg = gson.fromJson(it.toString(), Message::class.java)
msg?.content?.let {
lastAnswer = MsgModel(mDialogModel.id, false, it)
//切换到主线程更新消息
withContext(Dispatchers.Main) {
mChatAdapter.addMsg(lastAnswer!!)
changeMode(false)
}
}
}
}
}
}