<template>
|
<view class="content">
|
<view class="body">
|
<view v-for="(item,index) in arr" :key="index" :id="'message' + item.message_id">
|
<view class="body_l" v-if="item.role == 'assistant'">
|
<view class="body_lpic a">
|
<image :src="`${setting_data.base_url+now_model.icon}`" mode=""></image>
|
</view>
|
<view class="body_box">
|
<!-- <view class="body_lcon pdg" v-html="item.content"></view> -->
|
<view class="body_rcon pdg border_radius_l">
|
<zero-markdown-view :markdown="item.content" ></zero-markdown-view>
|
</view>
|
<view style="position: absolute;right: 0;bottom: 10rpx;">
|
<u-icon @click="copy(item)" name="file-text-fill" size="24" color="#302cd9"></u-icon>
|
</view>
|
</view>
|
</view>
|
<view class="body_r" v-if="item.role == 'user'">
|
<view class="body_box">
|
<!-- <view class="body_rcon pdg" v-html="item.content"> -->
|
<view class="body_rcon pdg border_radius_r">
|
<zero-markdown-view :markdown="item.content"></zero-markdown-view>
|
</view>
|
</view>
|
<view class="body_rpic a">
|
<!-- <image v-if="token != ''" :src="vals.avatar" mode="aspectFill"></image> -->
|
<image :src="userInfo.avatar ? userInfo.avatar : '../../static/head.png'" mode="aspectFill">
|
</image>
|
</view>
|
</view>
|
</view>
|
|
<view class="body_l" v-if="loading" id="loading">
|
<view class="body_lpic a">
|
<image :src="`${setting_data.base_url+now_model.icon}`" mode=""></image>
|
</view>
|
<view class="body_box ">
|
<view class="body_lcon pdg border_radius_l" style="display: flex; overflow-x: hidden;">
|
<view v-if="!typeingText" style="padding: 30rpx;">{{ now_model.title }}思考中...</view>
|
<!-- <zero-markdown-view v-if="!typeingText" style="padding: 0 20rpx;" :markdown="now_model.title">思考中...</zero-markdown-view> -->
|
<!-- <view v-else style="padding: 30rpx;">{{ typeingText }}...</view> -->
|
<zero-markdown-view v-else style="padding: 0 20rpx;" :markdown="typeingText"></zero-markdown-view>
|
</view>
|
</view>
|
</view>
|
</view>
|
|
<view class="flooer">
|
<view class="flooer_l">
|
<u--textarea v-model="prompt" placeholder="请输入内容,开始体验与人工智能交流吧" border="none" autoHeight
|
style="background-color: #F6F7FB;" :maxlength="256" holdKeyboard :showConfirmBar="false"
|
:cursorSpacing="28"></u--textarea>
|
<!-- <u--input placeholder="请输入内容,开始体验与人工智能交流吧" border="none" clearable v-model="prompt"
|
placeholderStyle="color: #7F8084"></u--input> -->
|
</view>
|
<view class="flooer_r pdg" @click="sendout">
|
<view class="flooer_rpic a">
|
<image src="../../static/fasong.png" mode=""></image>
|
</view>
|
</view>
|
</view>
|
<view style="height: 108rpx;"></view>
|
</view>
|
</template>
|
|
<script>
|
import setting from "@/common/config";
|
//markdown相关插件
|
// import markdownFunc from '@/uni_modules/jo-markdown/components/jo-markdown/index.js';
|
// #ifdef H5
|
import axios from 'axios'
|
// #endif
|
import {
|
mapState
|
} from "vuex"
|
var that;
|
export default {
|
data() {
|
return {
|
prompt: '',
|
arr: [],
|
timer: null,
|
loading: false,
|
chat_id: '',
|
typeingText: "",
|
typeingId: "",
|
now_model: {},
|
setting_data:'null'
|
}
|
},
|
computed: {
|
...mapState(['config', 'num', 'userInfo'])
|
},
|
onLoad(op) {
|
this.setting_data = setting
|
if (op.model) {
|
this.now_model = JSON.parse(op.model)
|
} else {
|
this.now_model = this.$store.state.main_model
|
}
|
uni.setNavigationBarTitle({
|
title: this.now_model.title
|
})
|
this.arr.push({
|
role: 'assistant',
|
content: this.now_model.first_message,
|
message_id: 'aa'
|
})
|
let that = this;
|
if (op.chat_id) {
|
this.chat_id = op.chat_id;
|
this.getMessages()
|
}
|
let pong = '';
|
let userInfo = uni.getStorageSync('userInfo')
|
uni.connectSocket({
|
url: setting.ws
|
});
|
uni.onSocketOpen(function(res) {
|
console.log('chat页WebSocket连接已打开!');
|
// 绑定UID
|
sendMsg({
|
type: 'login',
|
uid: userInfo.member_id
|
// uid: 3
|
})
|
// 设置心跳包
|
pong = setInterval(() => {
|
sendMsg({
|
type: 'pong'
|
})
|
}, 20 * 1000);
|
|
});
|
uni.onSocketError(function(res) {
|
console.log('WebSocket连接打开失败,请检查!');
|
});
|
uni.onSocketMessage(function(res) {
|
// console.log('收到服务器内容:' + res.data);
|
let json = JSON.parse(res.data)
|
// console.log(json)
|
if (json.hasOwnProperty('id')) {
|
that.typeingId = json.id
|
if (!json.choices[0].delta.finish_reason) {
|
if (json.choices[0].delta.hasOwnProperty('content')) {
|
that.typeingText += json.choices[0].delta.content
|
// 此处自行斟酌是否替换
|
// that.typeingText = that.typeingText.replace(/[cogptn]+/ig, "ChatGLM-6B")
|
}
|
}
|
}
|
|
});
|
// socket断开时通知后端改变登录状态
|
uni.onSocketClose(function(res) {
|
console.log('WebSocket 已关闭!');
|
});
|
//上文中的sendMsg原型
|
const sendMsg = function(data) {
|
uni.sendSocketMessage({
|
data: JSON.stringify(data)
|
})
|
}
|
},
|
onUnload() {
|
uni.closeSocket()
|
},
|
onShow() {
|
that = this;
|
uni.getStorage({
|
key: 'token',
|
success: function(res) {
|
that.token = res.data;
|
|
},
|
fail() {
|
that.token = '';
|
}
|
});
|
},
|
onBackPress() {
|
uni.hideLoading()
|
clearInterval(this.timer);
|
},
|
onHide() {
|
uni.hideLoading()
|
clearInterval(this.timer);
|
},
|
methods: {
|
getMessages() {
|
uni.showLoading({
|
|
})
|
this.$request("/api/Message/index", "POST", {
|
chat_id: this.chat_id,
|
limit: 200,
|
sort: 'message_id',
|
order: 'asc',
|
}).then((res) => {
|
console.log(res);
|
if (res.status == 200) {
|
this.arr = this.arr.concat(res.data.data)
|
this.$nextTick(() => {
|
uni.pageScrollTo({
|
selector: "#message" + this.arr[this.arr.length - 1].message_id,
|
duration: 100
|
});
|
});
|
uni.hideLoading()
|
} else {
|
this.$failToast('服务器繁忙,请稍后再试');
|
}
|
|
});
|
},
|
sendout() {
|
if (!this.prompt) {
|
this.$failToast("请输入内容");
|
return;
|
}
|
|
this.loading = true;
|
this.arr.push({
|
role: 'user',
|
content: this.prompt,
|
message_id: this.arr.length + 1
|
});
|
let message = this.prompt;
|
this.prompt = ""
|
this.$nextTick(() => {
|
uni.pageScrollTo({
|
selector: "#loading",
|
duration: 100
|
});
|
});
|
setTimeout(() => {
|
this.sub(message)
|
}, 200);
|
},
|
sub(message) {
|
// 条件编译处理,h5端uni.request与socket会互相阻塞
|
// #ifndef H5
|
this.$request("/api/Message/sendV2", "POST", {
|
message: message,
|
chat_id: this.chat_id,
|
model_id: this.now_model.assistant_id
|
// member_id: 3 // 调试之用,线上环境为token解码
|
}).then((res) => {
|
console.log(res);
|
if (res.status == 200) {
|
this.loading = false;
|
this.typeingText = "";
|
this.typeingId = "";
|
this.arr.push({
|
role: res.data.role,
|
// 此处自行斟酌是否替换
|
content: res.data.content,
|
// content: res.data.content.replace(/[cogptn]+/ig, "ChatGLM-6B")
|
});
|
if (!this.chat_id) {
|
this.chat_id = res.data.chat_id
|
}
|
this.$store.commit('useNum', 1);
|
this.$nextTick(() => {
|
uni.pageScrollTo({
|
scrollTop: 20000,
|
duration: 100
|
});
|
});
|
} else if (res.status == 901) {
|
this.loading = false;
|
this.$failToast('服务器繁忙,请稍后再试');
|
} else if (res.status == 411) {
|
this.loading = false;
|
uni.showModal({
|
content: res.msg
|
})
|
} else {
|
this.loading = false;
|
this.$failToast(res.msg);
|
}
|
}).catch(err => {
|
console.log(err)
|
this.loading = false;
|
this.$failToast(err.errMsg);
|
})
|
// #endif
|
// #ifdef H5
|
axios({
|
method: 'post',
|
url: setting.base_url + "/api/Message/sendV2",
|
data: {
|
message: message,
|
chat_id: this.chat_id,
|
model_id: this.now_model.assistant_id
|
},
|
headers: {
|
'content-type': 'application/x-www-form-urlencoded;charset=utf-8',
|
'Authorization': this.$store.state.token
|
}
|
}).then(response => {
|
console.log(response)
|
let res = response.data
|
if (res.status == 200) {
|
this.loading = false;
|
this.typeingText = "";
|
this.typeingId = "";
|
this.arr.push({
|
role: res.data.role,
|
content: res.data.content
|
});
|
if (!this.chat_id) {
|
this.chat_id = res.data.chat_id
|
}
|
this.$store.commit('useNum', 1);
|
this.$nextTick(() => {
|
uni.pageScrollTo({
|
scrollTop: 20000,
|
duration: 100
|
});
|
});
|
} else if (res.status == 901) {
|
this.loading = false;
|
this.$failToast('服务器繁忙,请稍后再试');
|
} else if (res.status == 411) {
|
this.loading = false;
|
uni.showModal({
|
content: res.msg
|
})
|
} else {
|
this.loading = false;
|
this.$failToast(res.msg);
|
}
|
}).catch(error => {
|
// reject(error);
|
});
|
// #endif
|
|
},
|
copy(item) {
|
uni.setClipboardData({
|
data: item.content,
|
success() {
|
uni.showModal({
|
title: '提示',
|
content: '内容已复制到系统剪贴板'
|
})
|
}
|
})
|
}
|
}
|
}
|
</script>
|
|
<style>
|
@import url("@/static/style/color-ui.css");
|
@import '../../components/css/index.css';
|
</style>
|
<style scoped>
|
.border_radius_l{
|
border-top-left-radius:0;
|
background: #fff;
|
color: #222;
|
}
|
.border_radius_r{
|
border-top-right-radius:0;
|
background: #302cd9;
|
color: #fff;
|
}
|
</style>
|