语音识别-3,添加ai问答
目录
1.基础请求:
2.关联上下文
语音app一般都会添加问答功能.最常见的几deepseek.本文就以它为例.
申请api不说了.
https://api.deepseek.com/chat/completions 这是接口.
Authorization:Bearer sk-xxxxxxx( 这是你的key)
最简的调用方式:rest客户端的
{"messages": [{"content": "用中文回复:北京常住人口,各区人口.","role": "user"}],"model": "deepseek-chat","stream": true
}
"stream": true表示以流的方式返回数据.一般,流的方式让人感觉快一些.等流全部返回了,时间也差不多了.如果不用流的方式,一次调用可能一分钟.
deepseek-chat和deepseek-reasoner是不一样的.deepseek-reasoner是r1.有思考的过程.
1.基础请求:
先有一个okhttp:
fun streamPost(json: String, callback: Callback) {val client = OkHttpClient.Builder().connectTimeout(120, TimeUnit.SECONDS).writeTimeout(180, TimeUnit.SECONDS).readTimeout(180, TimeUnit.SECONDS).callTimeout(180, TimeUnit.SECONDS).build()val builder = Request.Builder().url("https://api.deepseek.com/chat/completions")builder.addHeader("Authorization", "Bearer sk-xxxxxxxxxx")builder.addHeader("content-type", "application/json")if (!TextUtils.isEmpty(json.toString())) {val body = json.toString().toRequestBody(JSON)builder.post(body)}client.newCall(builder.build()).enqueue(callback)}
接着调用:
OKHttpHelper.streamPost(json.toString(),object : Callback {override fun onFailure(call: Call, e: IOException) {Timber.tag(TAG).d("sendToDsStreamAI请求失败: ${e.message}")setErrorMsg()isLoading = false}override fun onResponse(call: Call, response: Response) {if (!response.isSuccessful) {Timber.tag(TAG).e("sendToDsStreamAI请求返回失败: ${response.code}")setErrorMsg()isLoading = falsereturn}// 使用源码流读取 SSE 数据response.body?.source()?.use { source ->streamResp(source, type_msg_assistant)isLoading = false} ?: {isLoading = false}}})
解析:
private fun streamResp(source: BufferedSource, type: Int) {footerUserView?.hide()val builder = StringBuilder()try {while (!source.exhausted()) {try {val line = source.readUtf8LineStrict()if (line.startsWith("data:")) {//Timber.tag(TAG).d("接收到数据: $line")val data = line.substringAfter("data:")if (TextUtils.equals("[DONE]", data.trim())) {Timber.tag(TAG).d("接收到结束: $builder")addAssistant(builder, "")return}val resp = Gson().fromJson<DSResp>(data, DSResp::class.java)//Timber.tag(TAG).d("useDs.result:%s", resp)if (resp?.choices?.isNotEmpty() == true) {AppExecutors.instance.mainThread().execute {val content = resp.choices!![0].delta?.contentif (!TextUtils.isEmpty(content)) {builder.append(content)footerView?.setText(builder.toString())}}}}} catch (e: Exception) {Timber.tag(TAG).e(e)setErrorMsg()}}} catch (e: Exception) {Timber.tag(TAG).e(e)setErrorMsg()}}
关于流返回的格式,从官方的文档可以得到.
2.关联上下文
文档里说明了,要想在刚才的问题继续下去,需要把前面的问题一起给后端.
val json = JSONObject()json.put("model", "deepseek-chat")json.put("stream", true)val messages = getHistories(input, oldList)json.put("messages", messages)Timber.tag(TAG).d("请求json: $json")
定义一个实体:
class Assistant:
var type: Int = type_msg_user
const val type_msg_user = 0
const val type_msg_assistant = -2
这定义了两种,一种是用户的问题,一种是ai的回答.
在列表中,可能一个ai,一个用户问题.
private fun getHistories(input: String, list: List<Assistant>): JSONArray {var messages = JSONArray()//只能一个ai,一个用户这样间隔的对话.把不符合的过滤了.if (list.isNotEmpty()) {val msgList = arrayListOf<Assistant>()var count = list.sizevar last: Assistant? = nullfor (i in count - 1 downTo 0) {val item = list[i]if (item.type == type_msg_assistant) {if (last != null && last.type == type_msg_assistant) {Timber.tag(TAG).d("上一个消息是助手消息: $last")continue}if (!item.success) {Timber.tag(TAG).d("助手失败的消息: $item, last:$last")last = nullcontinue} else {last = itemmsgList.add(item)}} else {if (last == null) {Timber.tag(TAG).d("上一个消息是空,用户消息跳过,可能是出错的消息: $last")continue}if (last.type == type_msg_user) {Timber.tag(TAG).d("上一个消息是用户消息,跳过: $last")continue}if (!item.success) {Timber.tag(TAG).d("上一个消息是用户失败的消息,跳过: $last")continue} else {last = itemmsgList.add(item)}}}if (msgList.isNotEmpty()) {count = msgList.sizefor (i in count - 1 downTo 0) {val item = msgList[i]val content = JSONObject()content.put("content", item.content)if (item.type == type_msg_assistant) {content.put("role", "assistant")} else {content.put("role", "user")}messages.put(content)}}}val content = JSONObject()content.put("role", "user")content.put("content", input)messages.put(content)return messages}
这样得到数据,发送,ai就会有上下文了.