GitHub:https://github.com/baiyuliang/Qrobot_Vue
本項目所用的閒聊接口爲騰訊開放平臺提供,具體可參考:
用Flutter實現小Q聊天機器人(五)
或者官方文檔:
https://ai.qq.com/doc/nlpchat.shtml
說到前端網絡請求,就不得不說跨域問題了,本項目仍然會面臨跨域問題而導致無法去直接請求接口,一般的跨域解決辦法有這麼幾種:jsonp,後端允許跨域,代理。由於本項目環境無法使用jsonp,所以就剩下後端允許跨域和代理兩種辦法了,讓騰訊去爲我們允許跨域?顯然是不可能的,那麼就只能用代理了嗎?其實還有一種解決辦法就是proxy,網上也有很多案例,這裏我也貼出具體操作步驟:
1.新建vue.config.js:
module.exports = {
devServer: {
proxy: {
"/api": {
target: 'https://api.ai.qq.com',
changeOrigin: true,
pathRewrite: {
'^/api': '/'
}
}
}
}
};
2.設置request.js中axios的baseUrl=‘/api’
const request = axios.create({
baseURL: '/api',
timeout: 8000
})
這種辦法最大的缺點就是隻能用於開發環境,無法用於生產環境,所以其實並沒有什麼卵用,只用來自己做項目聯繫倒是有點用!而我本人則是使用nodejs代理的方式實現,但項目中給大家的示例是使用的proxy方式,大家在沒有相關資源的情況下,用這種方法進行練習也是可以的!
這裏貼出ApiChat.js相關代碼:
import request from "@/api/base/request";
import md5 from 'js-md5';
export function getChatResponse(text) {
return request({
url:'fcgi-bin/nlp/nlp_textchat?'+getChatParams(text),
method: 'get'
})
}
function getChatParams(text) {
let app_id = 2151744249;
let app_key = 'AWNcQGMMWi0OUceN';
let nonce_str = 'fa577ce340859f9fe';
let question = encodeURIComponent(text);
let session = 10000;
let time_stamp = parseInt(Date.now() / 1000);
let params = 'app_id=' + app_id + '&nonce_str=' + nonce_str + '&question=' + question + '&session=' + session + '&time_stamp=' + time_stamp + '&app_key=' + app_key;
let sign = md5(params).toUpperCase()
return params+'&sign='+sign
}
剩下的主要就是請求接口和展示數據了:
Chat.vue:
<script>
import Vue from "vue";
import {getChatResponse} from "@/api/ApiChat";
import LeftItem from "@/components/LeftItem";
import RightItem from "@/components/RightItem";
Vue.directive('scroll', {
inserted(el) {
el.scrollIntoView()
}
})
export default {
name: "Chat",
components: {LeftItem, RightItem},
data: () => {
return {
text: '',
msglist: [{
id: 1,
type: 1,
content: '歡迎你!',
me: false
}]
}
},
methods: {
send() {
if (this.text) {
this.msglist.push({
id: this.msglist[this.msglist.length - 1].id + 1,
type: 1,
content: this.text,
me: true
})
if (this.text === '圖片') {
this.msglist.push({
id: this.msglist[this.msglist.length - 1].id + 1,
type: 2,
content: 'http://6emm.hxzdhn.com/img/2020/06/28/jausoellbtf.jpg',
me: false
})
} else {
this.getResponse(this.text)
}
this.text = ''
}
},
getResponse(text) {
getChatResponse(text).then(res => {
console.log(res)
this.msglist.push({
id: this.msglist[this.msglist.length - 1].id + 1,
type: 1,
content: res.data.answer,
me: false
})
})
}
}
}
</script>
其中有一個需要注意的問題,就是聊天消息列表如何能自動滑動到底部?
網上有不少方法說的是用 el.scrollTop=el.offsetHeight這種方式解決,不過我沒有試驗成功!本項目是使用了vue自定義指令:v-scroll:
Vue.directive('scroll', {
inserted(el) {
el.scrollIntoView()
}
})
在li最下面放上一個高度爲0的元素,並添加v-scroll指令:
<li v-for="(item,index) in msglist" :key="index">
<RightItem :id="item.id" :type="item.type" :content="item.content" v-if="item.me"></RightItem>
<LeftItem :id="item.id" :type="item.type" :content="item.content" v-else></LeftItem>
<div v-scroll style="height: 0"></div>
</li>