262 lines
6.7 KiB
Vue
262 lines
6.7 KiB
Vue
<template>
|
||
<view class="content" ref="scrollView">
|
||
<view class="chat">
|
||
<view class="conversation" v-for="item in sparkResult">
|
||
<view class="question">
|
||
<view class="text">{{item.question}}</view>
|
||
<u-avatar class="avatar" bg-color="#2b7" size="25" icon="account-fill" fontSize="20"></u-avatar>
|
||
</view>
|
||
<view class="answer">
|
||
<view class="avatar">
|
||
<image class="img" src="../../static/logo.png" mode=""></image>
|
||
</view>
|
||
<view class="text">{{item.answer}}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="btn">
|
||
<u-input v-model="TEXT" placeholder="问我任何问题...">
|
||
<template slot="suffix">
|
||
<u-button @click="sendToSpark()" type="success" size="mini" icon="checkmark"
|
||
shape="circle"></u-button>
|
||
</template>
|
||
</u-input>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import CryptoJS from 'crypto-js';
|
||
import setting from '@/setting.js';
|
||
const base64 = require('js-base64').Base64
|
||
export default {
|
||
data() {
|
||
return {
|
||
TEXT: '',
|
||
// V1.1-V3.5动态获取,高于以上版本手动指定
|
||
modelDomain:'',
|
||
wsLiveFlag: false,
|
||
sparkResult: [],
|
||
historyTextList: [], // 历史会话信息,由于最大token12000,可以结合实际使用,进行移出
|
||
tempRes: '' // 临时答复保存
|
||
}
|
||
},
|
||
methods: {
|
||
async sendToSpark() {
|
||
if(this.TEXT==""){
|
||
uni.showToast({
|
||
title:"输入框不能为空",
|
||
icon:"none"
|
||
})
|
||
return
|
||
}
|
||
let myUrl = await this.getWebSocketUrl();
|
||
this.tempRes = "";
|
||
|
||
this.socketTask = uni.connectSocket({
|
||
url: myUrl,
|
||
method: 'GET',
|
||
success: res => {
|
||
console.log(res, "ws成功连接...", myUrl)
|
||
this.wsLiveFlag = true;
|
||
}
|
||
})
|
||
this.socketTask.onError((res) => {
|
||
console.log("连接发生错误,请检查appid是否填写", res)
|
||
})
|
||
this.socketTask.onOpen((res) => {
|
||
this.historyTextList.push({
|
||
"role": "user",
|
||
"content": this.TEXT
|
||
})
|
||
// 第一帧..........................................
|
||
let params = {
|
||
"header": {
|
||
"app_id": setting.APPID,
|
||
"uid": "aef9f963-7"
|
||
},
|
||
"parameter": {
|
||
"chat": {
|
||
"domain": this.modelDomain,
|
||
"temperature": 0.5,
|
||
"max_tokens": 1024
|
||
}
|
||
},
|
||
"payload": {
|
||
"message": {
|
||
"text": this.historyTextList
|
||
}
|
||
}
|
||
};
|
||
this.sparkResult.push({
|
||
question:this.TEXT,
|
||
answer:"思考中..."
|
||
})
|
||
this.socketTask.send({ // 发送消息,,都用uni的官方版本
|
||
data: JSON.stringify(params),
|
||
success:()=>{
|
||
this.TEXT = ""
|
||
console.log('第一帧发送成功')
|
||
}
|
||
});
|
||
});
|
||
|
||
// 接受到消息时
|
||
this.socketTask.onMessage((res) => {
|
||
let obj = JSON.parse(res.data)
|
||
let dataArray = obj.payload.choices.text;
|
||
if(this.sparkResult[this.sparkResult.length-1].answer=='思考中...'){
|
||
this.sparkResult[this.sparkResult.length-1].answer=""
|
||
}
|
||
for (let i = 0; i < dataArray.length; i++) {
|
||
this.sparkResult[this.sparkResult.length-1].answer += dataArray[i].content//动态拼接并显示回复的消息
|
||
this.tempRes = this.tempRes + dataArray[i].content
|
||
}
|
||
uni.pageScrollTo({
|
||
scrollTop: 999999999,
|
||
duration: 300
|
||
});
|
||
let temp = JSON.parse(res.data)
|
||
|
||
if (temp.header.code !== 0) {
|
||
this.socketTask.close({
|
||
success(res) {
|
||
console.log('关闭成功', res)
|
||
this.wsLiveFlag = false;
|
||
},
|
||
fail(err) {
|
||
console.log('关闭失败', err)
|
||
}
|
||
})
|
||
} else {
|
||
if (res.data && temp.header.status === 2) {
|
||
this.historyTextList.push({
|
||
"role": "assistant",
|
||
"content": this.tempRes
|
||
})
|
||
setTimeout(() => {
|
||
this.socketTask.close({
|
||
success(res) {
|
||
console.log('关闭成功', res)
|
||
},
|
||
fail(err) {
|
||
console.log('关闭失败', err)
|
||
}
|
||
})
|
||
}, 1000)
|
||
}
|
||
}
|
||
})
|
||
},
|
||
// 鉴权
|
||
getWebSocketUrl() {
|
||
var httpUrlHost = (setting.httpUrl).substring(8, 28);
|
||
var httpUrlPath = (setting.httpUrl).substring(28);
|
||
|
||
switch (httpUrlPath) {
|
||
case "/v1.1/chat":
|
||
this.modelDomain = "general";
|
||
break;
|
||
case "/v2.1/chat":
|
||
this.modelDomain = "generalv2";
|
||
break;
|
||
case "/v3.1/chat":
|
||
this.modelDomain = "generalv3";
|
||
break;
|
||
case "/v3.5/chat":
|
||
this.modelDomain = "generalv3.5";
|
||
break;
|
||
}
|
||
|
||
return new Promise((resolve, reject) => {
|
||
// https://spark-api.xf-yun.com/v1.1/chat V1.5 domain general
|
||
// https://spark-api.xf-yun.com/v2.1/chat V2.0 domain generalv2
|
||
var url = "wss://"+httpUrlHost+httpUrlPath;
|
||
var host = "spark-api.xf-yun.com";
|
||
var apiKeyName = "api_key";
|
||
var date = new Date().toGMTString();
|
||
var algorithm = "hmac-sha256";
|
||
var headers = "host date request-line";
|
||
var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${httpUrlPath} HTTP/1.1`;
|
||
var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, setting.APISecret);
|
||
var signature = CryptoJS.enc.Base64.stringify(signatureSha);
|
||
var authorizationOrigin =
|
||
`${apiKeyName}="${setting.APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
|
||
var authorization = base64.encode(authorizationOrigin);
|
||
url = `${url}?authorization=${authorization}&date=${encodeURI(date)}&host=${host}`;
|
||
|
||
resolve(url); // 主要是返回地址
|
||
});
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
// page{
|
||
// background: #fff;
|
||
// }
|
||
.content{
|
||
padding: 20rpx 20rpx 100rpx 20rpx;
|
||
.chat{
|
||
.conversation{
|
||
.question{
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
margin-bottom: 20rpx;
|
||
.avatar{
|
||
align-self: normal;
|
||
}
|
||
.text{
|
||
max-width: 80%;
|
||
margin-right: 10rpx;
|
||
background: #fff;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
border-radius: 20rpx;
|
||
}
|
||
}
|
||
.answer{
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20rpx;
|
||
.avatar{
|
||
width: 50rpx;
|
||
height: 50rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: #fff;
|
||
border: 1px solid #eee;
|
||
border-radius: 25rpx;
|
||
margin-right: 10rpx;
|
||
align-self: normal ;
|
||
.img{
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
}
|
||
}
|
||
}
|
||
.text{
|
||
max-width: 80%;
|
||
word-break: break-word;
|
||
background: #fff;
|
||
padding: 20rpx;
|
||
box-sizing: border-box;
|
||
border-radius: 20rpx;
|
||
}
|
||
}
|
||
}
|
||
.btn{
|
||
position: fixed;
|
||
border-radius: 20rpx;
|
||
width: 100%;
|
||
bottom: var(--window-bottom);
|
||
left: 0;
|
||
background: #fff;
|
||
}
|
||
}
|
||
|
||
</style>
|