|
@@ -1,20 +1,58 @@
|
|
<template>
|
|
<template>
|
|
<div class="app-layout">
|
|
<div class="app-layout">
|
|
- <div class="sidebar">
|
|
|
|
|
|
+ <div class="side-bar">
|
|
<div class="logo-section">
|
|
<div class="logo-section">
|
|
<img src="@/assets/images/common/ai/logo.png" alt="新基础 小新" width="160" height="160" />
|
|
<img src="@/assets/images/common/ai/logo.png" alt="新基础 小新" width="160" height="160" />
|
|
<span class="logo-text">新基础 小新</span>
|
|
<span class="logo-text">新基础 小新</span>
|
|
</div>
|
|
</div>
|
|
|
|
+ <div>
|
|
|
|
+ <ul>
|
|
|
|
+ <li><el-text>我的学习压力大,每天睡不好怎么办?</el-text></li>
|
|
|
|
+ <li><el-text>帮我查一下2024年清华大学在四川省录取分数线</el-text></li>
|
|
|
|
+ </ul>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="main-content">
|
|
|
|
+ <div class="chat-container">
|
|
|
|
+ <div class="message-list">
|
|
|
|
+
|
|
|
|
+ </div>
|
|
|
|
+ <div class="content-box">
|
|
|
|
+ <div v-html="streamHtmlData"></div>
|
|
|
|
+ <!-- <span>{{streamData}}</span>-->
|
|
|
|
+ <span class="loading-dots"></span>
|
|
|
|
+ <span class="dot"></span>
|
|
|
|
+ <span class="dot"></span>
|
|
|
|
+ </div>
|
|
|
|
+ <el-button @click="stopMessage">停止回答</el-button>
|
|
|
|
+
|
|
|
|
+ </div>
|
|
|
|
+ <div class="input-container">
|
|
|
|
+ <el-input
|
|
|
|
+ v-model="inputMessage"
|
|
|
|
+ placeholder="请输入消息"
|
|
|
|
+ @keyup.enter="sendMessage"
|
|
|
|
+ ></el-input>
|
|
|
|
+ <el-button @click="sendMessage" :disabled="isSending" type="primary"
|
|
|
|
+ >发送</el-button
|
|
|
|
+ >
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- <div>
|
|
|
|
- <div class="content-box">
|
|
|
|
- <div v-html="streamHtmlData"></div>
|
|
|
|
-<!-- <span>{{streamData}}</span>-->
|
|
|
|
- <span class="loading-dots"></span>
|
|
|
|
- <span class="dot"></span>
|
|
|
|
- <span class="dot"></span>
|
|
|
|
|
|
+ <div class="control-bar">
|
|
|
|
+ <div class="control-button-box">
|
|
|
|
+ <div class="control-button">
|
|
|
|
+ <el-button style="width:140px">退出</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="control-button">
|
|
|
|
+ <el-button style="width:140px">静音</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="control-button">
|
|
|
|
+ <el-button style="width:140px">新会话</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="session-list-box">
|
|
|
|
+
|
|
</div>
|
|
</div>
|
|
- <el-button @click="stopMessage">停止回答</el-button>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
@@ -24,20 +62,22 @@
|
|
import { getToken } from '@/utils/auth'
|
|
import { getToken } from '@/utils/auth'
|
|
import { marked } from 'marked'
|
|
import { marked } from 'marked'
|
|
|
|
|
|
- let data = ref()
|
|
|
|
|
|
+ // 聊天记录
|
|
|
|
+ let chatRecordList = ref()
|
|
|
|
+ //
|
|
const streamData = ref(''); // 存储流式数据
|
|
const streamData = ref(''); // 存储流式数据
|
|
let streamHtmlData = ref(''); // 存储流式数据
|
|
let streamHtmlData = ref(''); // 存储流式数据
|
|
const isLoading = ref(false); // 加载状态
|
|
const isLoading = ref(false); // 加载状态
|
|
let reader = null; // 读取器实例
|
|
let reader = null; // 读取器实例
|
|
let controller = null; // AbortController用于中止请求
|
|
let controller = null; // AbortController用于中止请求
|
|
-
|
|
|
|
|
|
+ const inputMessage = ref('')
|
|
|
|
|
|
// 查看所有聊天记录
|
|
// 查看所有聊天记录
|
|
list();
|
|
list();
|
|
function list() {
|
|
function list() {
|
|
getAiChatRecordList().then(resp =>{
|
|
getAiChatRecordList().then(resp =>{
|
|
console.log(resp)
|
|
console.log(resp)
|
|
- data.value = resp;
|
|
|
|
|
|
+ chatRecordList.value = resp;
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
|
|
@@ -51,7 +91,7 @@
|
|
|
|
|
|
// 请求体
|
|
// 请求体
|
|
let form = {
|
|
let form = {
|
|
- "content": "生成一个高中学习计划表格"
|
|
|
|
|
|
+ "content": "我的学习压力大,每天睡不好怎么办?"
|
|
}
|
|
}
|
|
// 发送fetch请求
|
|
// 发送fetch请求
|
|
const response = await fetch('/dev-api/ai/chat/stream', {
|
|
const response = await fetch('/dev-api/ai/chat/stream', {
|
|
@@ -74,7 +114,7 @@
|
|
|
|
|
|
// 解码并追加数据
|
|
// 解码并追加数据
|
|
let chunk = decoder.decode(value, { stream: true });
|
|
let chunk = decoder.decode(value, { stream: true });
|
|
- chunk = chunk.replace(/\n\n/g, ' ').replace(/data:/g, '')
|
|
|
|
|
|
+ chunk = chunk.replace(/\n\n/g, '').replace(/data:/g, '')
|
|
streamData.value += chunk;
|
|
streamData.value += chunk;
|
|
streamHtmlData.value = marked(streamData.value)
|
|
streamHtmlData.value = marked(streamData.value)
|
|
}
|
|
}
|
|
@@ -120,10 +160,11 @@
|
|
.app-layout {
|
|
.app-layout {
|
|
display: flex;
|
|
display: flex;
|
|
height: 100vh;
|
|
height: 100vh;
|
|
|
|
+ width: 100vw;
|
|
}
|
|
}
|
|
|
|
|
|
- .sidebar {
|
|
|
|
- width: 200px;
|
|
|
|
|
|
+ .side-bar {
|
|
|
|
+ width: 20vw;
|
|
background-color: #f4f4f9;
|
|
background-color: #f4f4f9;
|
|
padding: 20px;
|
|
padding: 20px;
|
|
display: flex;
|
|
display: flex;
|
|
@@ -131,21 +172,62 @@
|
|
align-items: center;
|
|
align-items: center;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ .main-content {
|
|
|
|
+ width:60vw;
|
|
|
|
+ flex: 1;
|
|
|
|
+ padding: 20px;
|
|
|
|
+ overflow-y: auto;
|
|
|
|
+ }
|
|
|
|
+ .chat-container {
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ height: 100%;
|
|
|
|
+ }
|
|
|
|
+
|
|
.logo-section {
|
|
.logo-section {
|
|
display: flex;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
align-items: center;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*控制区*/
|
|
|
|
+ .control-bar{
|
|
|
|
+ width: 20vw;
|
|
|
|
+ background-color: #f4f4f9;
|
|
|
|
+ padding: 20px;
|
|
|
|
+/* display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ align-items: center;*/
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .control-button-box {
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ .control-button {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ margin: 4px 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .session-list-box{
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .message-list{
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* 内容区 */
|
|
.content-box {
|
|
.content-box {
|
|
/*max-height: 300px;*/
|
|
/*max-height: 300px;*/
|
|
- width: 80vw;
|
|
|
|
|
|
+ width: 50vw;
|
|
overflow-y: auto;
|
|
overflow-y: auto;
|
|
border: 1px solid #eee;
|
|
border: 1px solid #eee;
|
|
padding: 10px;
|
|
padding: 10px;
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|
|
background: #f9f9f9;
|
|
background: #f9f9f9;
|
|
}
|
|
}
|
|
|
|
+
|
|
pre {
|
|
pre {
|
|
white-space: pre-wrap;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
word-wrap: break-word;
|
|
@@ -178,4 +260,16 @@
|
|
opacity: 1;
|
|
opacity: 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /*输入框*/
|
|
|
|
+
|
|
|
|
+ .input-container {
|
|
|
|
+ display: flex;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .input-container .el-input {
|
|
|
|
+ flex: 1;
|
|
|
|
+ margin-right: 10px;
|
|
|
|
+ }
|
|
</style>
|
|
</style>
|