|
@@ -1,19 +1,538 @@
|
|
|
<template>
|
|
|
- <div class="chat">
|
|
|
- <h1>对话</h1>
|
|
|
+ <div class="chat" v-loading="loading">
|
|
|
+ <div class="c_chat" ref="chatRef">
|
|
|
+ <div class="c_c_item" v-for="item in chatList" :key="item.uid">
|
|
|
+ <div class="c_c_i_user" v-if="item.content">
|
|
|
+ <div class="c_c_i_u_message">
|
|
|
+ <div class="c_c_i_u_m_top">
|
|
|
+ <span class="chatTime">{{ item.createtime }}</span>
|
|
|
+ <span>科科</span>
|
|
|
+ </div>
|
|
|
+ <div class="c_c_i_u_m_bottom">
|
|
|
+ <span class="coptText" @click="copyText(item.aiContent)"></span>
|
|
|
+ <div
|
|
|
+ class="c_c_i_u_m_content chatContent"
|
|
|
+ v-html="item.content"
|
|
|
+ ></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="c_c_i_u_avatar">
|
|
|
+ <el-avatar
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ :src="require('../../../../assets/icon/pblCourse/userAvatar.png')"
|
|
|
+ fit="fit"
|
|
|
+ ></el-avatar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="c_c_i_ai">
|
|
|
+ <div class="c_c_i_ai_avatar">
|
|
|
+ <el-avatar
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
+ :src="
|
|
|
+ require('../../../../assets/icon/pblCourse/aiTeacherAvatar.png')
|
|
|
+ "
|
|
|
+ fit="fit"
|
|
|
+ ></el-avatar>
|
|
|
+ </div>
|
|
|
+ <div class="c_c_i_ai_message">
|
|
|
+ <div class="c_c_i_ai_m_top">
|
|
|
+ <span>小可老师</span>
|
|
|
+ <span class="chatTime">{{item.createtime}}</span>
|
|
|
+ </div>
|
|
|
+ <div class="c_c_i_ai_m_bottom">
|
|
|
+ <div
|
|
|
+ v-loading="item.loading"
|
|
|
+ class="c_c_i_ai_m_content chatContent"
|
|
|
+ v-html="item.aiContent"
|
|
|
+ ></div>
|
|
|
+ <span class="coptText" @click="copyText(item.aiContent)"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div class="c_controls">
|
|
|
+ <span class="c_controls_item" @click="clearChat">清空对话</span>
|
|
|
+ </div> -->
|
|
|
+ <div class="c_bottom" v-loading="chatLoading">
|
|
|
+ <div class="c_b_record">
|
|
|
+ <span></span>
|
|
|
+ </div>
|
|
|
+ <div class="c_b_inputArea">
|
|
|
+ <el-input
|
|
|
+ class="c_b_input"
|
|
|
+ @keyup.enter.native="send()"
|
|
|
+ v-model="textValue"
|
|
|
+
|
|
|
+ >
|
|
|
+ </el-input>
|
|
|
+ <span></span>
|
|
|
+ </div>
|
|
|
+ <div class="c_b_send" @click="send">
|
|
|
+ <span></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
- export default {
|
|
|
-
|
|
|
- }
|
|
|
+import { v4 as uuidv4 } from "uuid";
|
|
|
+import MarkdownIt from "markdown-it";
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ loading: false,
|
|
|
+ chatLoading:false,
|
|
|
+ userId:this.$route.query['userid'],
|
|
|
+ chatList: [],
|
|
|
+ textValue: "",
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 发送消息
|
|
|
+ send() {
|
|
|
+ if(this.chatLoading || this.loading)return this.$message.info("请稍等...")
|
|
|
+ if(!this.textValue.trim())return this.$message.info("请输入内容");
|
|
|
+ const _uuid = uuidv4();
|
|
|
+ this.chatLoading = true;
|
|
|
+ this.chatList.push({
|
|
|
+ role: "user",
|
|
|
+ content: `${this.textValue}`,
|
|
|
+ uid: _uuid,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: "",
|
|
|
+ oldContent: "",
|
|
|
+ filename: "",
|
|
|
+ index: this.chatList.length,
|
|
|
+ createtime:new Date().toLocaleString().replaceAll("/",'-'),
|
|
|
+ loading: true,
|
|
|
+ })
|
|
|
+
|
|
|
+ let params = {
|
|
|
+ model: "gpt-3.5-turbo",
|
|
|
+ temperature: 0,
|
|
|
+ max_tokens: 4096,
|
|
|
+ top_p: 1,
|
|
|
+ frequency_penalty: 0,
|
|
|
+ presence_penalty: 0,
|
|
|
+ messages: [{role:"user",content:this.textValue}],
|
|
|
+ uid: _uuid,
|
|
|
+ mind_map_question: "",
|
|
|
+ }
|
|
|
+ this.scrollBottom();
|
|
|
+ this.textValue = "";
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ if (res.data.FunctionResponse.result == "发送成功") {
|
|
|
+ } else {
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.$message.warning(res.data.FunctionResponse.result);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch((e) => {
|
|
|
+ this.chatLoading = false;
|
|
|
+ console.log(e);
|
|
|
+ });
|
|
|
+ // this.$message.info(`发送:${this.textValue}`);
|
|
|
+ // this.textValue = "";
|
|
|
+ this.getAiContent(_uuid)
|
|
|
+ },
|
|
|
+ getAiContent(_uid) {
|
|
|
+ let _source = new EventSource(`https://gpt4.cocorobo.cn/stream/${_uid}`); //http://gpt4.cocorobo.cn:8011/stream/ https://gpt4.cocorobo.cn/stream/
|
|
|
+ let _allText = "";
|
|
|
+ let _mdText = "";
|
|
|
+ const md = new MarkdownIt();
|
|
|
+ _source.onmessage = (_e) => {
|
|
|
+ if (_e.data.replace("'", "").replace("'", "") == "[DONE]") {
|
|
|
+ //对话已经完成
|
|
|
+ _mdText = _mdText.replace("_", "");
|
|
|
+ _source.close();
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isalltext = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).isShowSynchronization = true;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.insertChat(_uid);
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ //对话还在继续
|
|
|
+ let _text = "";
|
|
|
+ _text = _e.data.replaceAll("'", "");
|
|
|
+ if (_allText == "") {
|
|
|
+ _allText = _text.replace(/^\n+/, ""); //去掉回复消息中偶尔开头就存在的连续换行符
|
|
|
+ } else {
|
|
|
+ _allText += _text;
|
|
|
+ }
|
|
|
+ _mdText = _allText + "_";
|
|
|
+ _mdText = _mdText.replace(/\\n/g, "\n");
|
|
|
+ _mdText = _mdText.replace(/\\/g, "");
|
|
|
+ if (_allText.split("```").length % 2 == 0) _mdText += "\n```\n";
|
|
|
+ //转化返回的回复流数据
|
|
|
+ _mdText = md.render(_mdText);
|
|
|
+ this.chatList.find((i) => i.uid == _uid).aiContent = _mdText;
|
|
|
+ this.chatList.find((i) => i.uid == _uid).loading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ // 处理流数据
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 复制
|
|
|
+ copyText(_html) {
|
|
|
+ const div = document.createElement("div")
|
|
|
+ div.innerHTML = _html
|
|
|
+ const _text = div.innerText
|
|
|
+ navigator.clipboard.writeText(_text).then(_=>{
|
|
|
+ this.$message.success("复制成功")
|
|
|
+ }, function(err) {
|
|
|
+ this.$message.error(`无法复制:${err}`)
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 保存对话
|
|
|
+ //保存消息
|
|
|
+ insertChat(_uid) {
|
|
|
+ let _data = this.chatList.find((i) => i.uid == _uid);
|
|
|
+ if (!_data) return;
|
|
|
+ let params = {
|
|
|
+ userId: this.userId,
|
|
|
+ userName: "qgt",
|
|
|
+ groupId: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
+ answer: _data.aiContent,
|
|
|
+ problem: _data.content,
|
|
|
+ file_id: "",
|
|
|
+ alltext: _data.aiContent,
|
|
|
+ type: "chat",
|
|
|
+ filename: _data.filename,
|
|
|
+ session_name: `${this.userId}-pblCourse`,
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/insert_chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ console.log("保存对话")
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 获取对话记录
|
|
|
+ getChatList() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ this.chatList = [];
|
|
|
+ this.loading = true;
|
|
|
+ this.chatLoading = true;
|
|
|
+ let params = {
|
|
|
+ userid: this.userId,
|
|
|
+ groupid: "602def61-005d-11ee-91d8-005056b8q12w",
|
|
|
+ // session_name:``
|
|
|
+ session_name: `${this.userId}-pblCourse`,
|
|
|
+ };
|
|
|
+ this.ajax
|
|
|
+ .post("https://gpt4.cocorobo.cn/get_agent_park_chat", params)
|
|
|
+ .then((res) => {
|
|
|
+ let _data = JSON.parse(res.data.FunctionResponse);
|
|
|
+ if (_data.length > 0) {
|
|
|
+ console.log(_data)
|
|
|
+ let _chatList = [];
|
|
|
+ for (let i = 0; i < _data.length; i++) {
|
|
|
+ _chatList.push({
|
|
|
+ loading: false,
|
|
|
+ role: "user",
|
|
|
+ content: _data[i].problem,
|
|
|
+ uid: _data[i].id,
|
|
|
+ AI: "AI",
|
|
|
+ aiContent: _data[i].answer,
|
|
|
+ oldContent: _data[i].answer,
|
|
|
+ isShowSynchronization: false,
|
|
|
+ filename: _data[i].filename,
|
|
|
+ index: i,
|
|
|
+ is_mind_map: false,
|
|
|
+ fileid: _data[i].fileid,
|
|
|
+ createtime:_data[i].createtime
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.chatList = _chatList;
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.loading = false;
|
|
|
+ } else {
|
|
|
+ //没有对话记录
|
|
|
+ this.loading = false;
|
|
|
+ this.chatLoading = false;
|
|
|
+ }
|
|
|
+ resolve();
|
|
|
+ this.scrollBottom();
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ console.log(err);
|
|
|
+ this.$message.error("获取对话记录失败");
|
|
|
+ this.chatLoading = false;
|
|
|
+ this.scrollBottom();
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ //对话触底
|
|
|
+ scrollBottom(){
|
|
|
+ this.$nextTick(()=>{
|
|
|
+ this.$refs.chatRef.scrollTop = this.$refs.chatRef.scrollHeight;
|
|
|
+ })
|
|
|
+ },
|
|
|
+ //清除对话
|
|
|
+ clearChat(){
|
|
|
+ this.chatList = [];
|
|
|
+ this.scrollBottom();
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ mounted() {
|
|
|
+ this.getChatList().then(_=>{
|
|
|
+ this.scrollBottom();
|
|
|
+ })
|
|
|
+ },
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
-.chat{
|
|
|
+.chat {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
- background-color: pink;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border: solid 1px #f3f7fd;
|
|
|
+ box-shadow: 0 4px 10px 0 #1d388321;
|
|
|
+}
|
|
|
+
|
|
|
+.c_chat {
|
|
|
+ width: 100%;
|
|
|
+ height: calc(100% - 56px);
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 15px;
|
|
|
+ overflow: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_item {
|
|
|
+ background-color: none;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_user {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_u_message {
|
|
|
+ height: auto;
|
|
|
+ width: auto;
|
|
|
+ max-width: calc(100% - 50px - 40px);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-end;
|
|
|
+ margin-right: 5px;
|
|
|
+}
|
|
|
+.c_c_i_u_m_top {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_u_m_top > span {
|
|
|
+ margin-left: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_u_m_bottom {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+}
|
|
|
+
|
|
|
+.coptText {
|
|
|
+ min-width: 15px;
|
|
|
+ min-height: 15px;
|
|
|
+ display: block;
|
|
|
+ background: url("../../../../assets/icon/pblCourse/copyIcon.png") no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ margin: 0px 10px 6px 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_u_m_content {
|
|
|
+ width: auto;
|
|
|
+ height: auto;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #e2eeff;
|
|
|
+ border-radius: 8px 2px 8px 8px;
|
|
|
+ border: solid 1px #000000e5;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_u_avatar {
|
|
|
+ width: 45px;
|
|
|
+ height: 45px;
|
|
|
+ margin: 0px 0 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai {
|
|
|
+ margin-top: 10px;
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai_avatar {
|
|
|
+ width: 45px;
|
|
|
+ height: 45px;
|
|
|
+ margin: 0px 0 0 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai_message {
|
|
|
+ height: auto;
|
|
|
+ width: auto;
|
|
|
+ max-width: calc(100% - 50px - 40px);
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-left: 5px;
|
|
|
+}
|
|
|
+.c_c_i_ai_m_top {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+ margin-bottom: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai_m_top > span {
|
|
|
+ margin-left: 5px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai_m_bottom {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-end;
|
|
|
+}
|
|
|
+
|
|
|
+.c_c_i_ai_m_content {
|
|
|
+ min-width: 40px;
|
|
|
+ min-height: 25px;
|
|
|
+ width: auto;
|
|
|
+ height: auto;
|
|
|
+ padding: 10px;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 2px 8px 8px 8px;
|
|
|
+ border: solid 1px #000000e5;
|
|
|
+}
|
|
|
+
|
|
|
+.chatContent >>> ol {
|
|
|
+ margin-left: 25px;
|
|
|
+}
|
|
|
+
|
|
|
+.chatContent >>> ul {
|
|
|
+ margin-left: 25px;
|
|
|
+}
|
|
|
+
|
|
|
+.chatTime{
|
|
|
+ font-size: 14px;
|
|
|
+ margin: 0 10px;
|
|
|
+ color: #2c2f3b;
|
|
|
+}
|
|
|
+
|
|
|
+.c_controls{
|
|
|
+ width: 100%;
|
|
|
+ height: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_controls>span{
|
|
|
+ max-height: 30px;
|
|
|
+ width: auto;
|
|
|
+ padding: 5px 10px;
|
|
|
+ font-size: 14px;
|
|
|
+ border-radius: 15px;
|
|
|
+ box-shadow: 0 0 2px 0px gray;
|
|
|
+ margin-left: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.c_controls>span:hover{
|
|
|
+ background-color: #f3f7fd;
|
|
|
+}
|
|
|
+
|
|
|
+.c_bottom {
|
|
|
+ width: 100%;
|
|
|
+ height: 56px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+ border-top: solid 0.5px #e7e7e7;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_record {
|
|
|
+ width: 30px;
|
|
|
+ height: 30px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_record > span {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ background-image: url("../../../../assets/icon/pblCourse/recordIcon.png");
|
|
|
+ background-size: 100% 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_inputArea {
|
|
|
+ width: calc(100% - 140px);
|
|
|
+ background-color: #f3f3f3;
|
|
|
+ border-radius: 50px;
|
|
|
+ height: 80%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin: 0 15px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_input {
|
|
|
+ width: calc(100% - 40px);
|
|
|
+ margin-right: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_input >>> .el-input__inner {
|
|
|
+ border: none;
|
|
|
+ background-color: #f3f3f3;
|
|
|
+ outline: none;
|
|
|
+ border-radius: 50px 0 0 50px;
|
|
|
+ font-size: 1.2em;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_inputArea > span {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ background-image: url("../../../../assets/icon/pblCourse/fileIcon.png");
|
|
|
+ background-size: 100% 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 10px;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_send {
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background-color: #3681fc;
|
|
|
+ cursor: pointer;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.c_b_send > span {
|
|
|
+ width: 60%;
|
|
|
+ height: 60%;
|
|
|
+ background-image: url("../../../../assets/icon/pblCourse/sendIcon.png");
|
|
|
+ background-size: 100% 100%;
|
|
|
}
|
|
|
-</style>
|
|
|
+</style>
|