如何利用OpenAI实现一个聊天机器人

539 阅读3分钟

OpenAI开放了聊天机器人的接口,只要有账号,我们就可以利用接口实现一个聊天机器人应用。

API文档的地址[OpenAI Platform]

我们也可以利用ChatGPT来完成聊天功能的开发。但因为ChatGPT开发的资料也是来源于网络博客,关于OpenAI的使用的博客还不是很多,跟着ChatGPT的提示来进行聊天机器人的开发走了好多弯路啊,遂打算写一篇文章简单介绍一个这个接口的使用。

创建API_KEY

每次会话都需要验证API_KEY。点击右上角头像,选择“View API keys”进入API keys 页面,点击"create new secrat key"创建密钥,填入密钥名称。创建时需要将密钥记录下来,创建好后就看不到密钥了(没有好好看说明书的我只能重新创建一个密钥)。

b1d529854e2f50249aaa36c71b95539c5686f16e.png

7ae81be10c999441190be04dc6708c2aa4a34526.png

676241e8516cbde12b318e0f2f1a7964204b4307.png

这是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)
                        }
                    }
                }
            }
        }
    }