<template>
|
<div style="position: relative;height:calc(100vh - 20px);width: 100%;display: flex;justify-content: center">
|
<!-- 聊天消息列表 -->
|
<div class="chat-messages">
|
<div
|
v-for="(message, index) in messages"
|
:key="message + index"
|
:class="['message', message.role]"
|
@mouseover="handleMouseEnter(message)"
|
>
|
<div class="avatar">
|
<img :src="getAvatar(message.role)" alt="avatar" />
|
</div>
|
<div class="content">
|
<div class="text" :ref="'msg' + index">{{ message.content }}</div>
|
<div v-if="message.role === 'assistant'">
|
<div v-show="msgIndex === message" class="msg-op-list">
|
<el-button class="copy" v-show="false"/>
|
<el-tooltip class="item" effect="dark" content="复制" placement="top">
|
<i class="el-icon-copy-document msg-op msg-copy" @click="copyText(message.content)"/>
|
</el-tooltip>
|
<el-tooltip class="item" effect="dark" content="重新生成" placement="top">
|
<i class="el-icon-refresh msg-op msg-re" @click="reAnswer"/>
|
</el-tooltip>
|
</div>
|
</div>
|
</div>
|
<div v-if="message.role === 'user'">
|
<div v-show="msgIndex === message" style="display: flex">
|
<el-tooltip class="item" effect="dark" content="复制" placement="top">
|
<i class="el-icon-copy-document msg-op msg-copy" @click="copyText(message.content)"/>
|
</el-tooltip>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 输入框 -->
|
<div class="chat-input">
|
<el-input
|
v-model="inputMessage"
|
placeholder="请输入消息,按下回车发送"
|
@keyup.native.enter="sendMessage"
|
>
|
<div slot="append">
|
<el-button type="primary" @click="sendMessage" icon="el-icon-thumb"></el-button>
|
</div>
|
</el-input>
|
<!-- <div class="send-but" @click="sendMessage">-->
|
<!-- <svg t="1742455190051" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1160" width="32" height="32"><path d="M417.016025 991.681197h266.763504l286.972859-930.353884z" fill="#6E6E96" opacity=".2" p-id="1161"></path><path d="M318.168022 667.620127l106.879202 307.873376L985.008068 34.974312z" fill="#E5C0A8" p-id="1162"></path><path d="M425.051265 993.681924a18.180337 18.180337 0 0 1-17.186036-12.222619l-106.87516-307.873376a18.188421 18.188421 0 0 1 4.664319-19.15847L972.498476 21.777602a18.184379 18.184379 0 0 1 28.14355 22.497056L440.67714 984.797891a18.192463 18.192463 0 0 1-15.625875 8.884033z m-85.849345-320.940746l90.210525 259.868071L902.064828 138.741273 339.20192 672.741178z" fill="#6E6E96" p-id="1163"></path><path d="M51.287304 548.991206L985.008068 34.974312 318.168022 667.620127z" fill="#FFDAC1" p-id="1164"></path><path d="M318.16398 685.808548c-2.497876 0-5.01192-0.513318-7.384499-1.568246l-266.876675-118.628922a18.188421 18.188421 0 0 1-10.783713-15.848177 18.204588 18.204588 0 0 1 9.401393-16.713137L976.237207 19.041256a18.188421 18.188421 0 1 1 21.292578 29.129766L330.689739 680.816837a18.184379 18.184379 0 0 1-12.525759 4.991711z m-226.005273-138.555347l222.302919 98.811627L869.915784 119.097779 92.158707 547.253201z" fill="#6E6E96" p-id="1165"></path><path d="M985.008068 34.974312L425.281652 711.656315l429.48924 166.755482z" fill="#FFDAC1" p-id="1166"></path><path d="M854.770892 896.60426a18.196504 18.196504 0 0 1-6.584208-1.232771l-429.48924-166.759524a18.176295 18.176295 0 0 1-7.42896-28.551779L970.998942 23.382225a18.196504 18.196504 0 0 1 31.995453 14.368853l-130.245259 843.445569a18.224798 18.224798 0 0 1-8.87595 12.978448 18.325844 18.325844 0 0 1-9.102294 2.429165z m-399.409634-192.781092l384.887191 149.44819L956.969607 97.417181 455.361258 703.823168z" fill="#6E6E96" p-id="1167"></path><path d="M425.281652 993.681924a18.192463 18.192463 0 0 1-18.188421-18.188421v-263.837188a18.188421 18.188421 0 0 1 36.376842 0v263.837188a18.188421 18.188421 0 0 1-18.188421 18.188421z" fill="#6E6E96" p-id="1168"></path><path d="M985.008068 34.974312L518.147686 728.203736l-62.786428-24.380568zM417.016025 711.656315l78.937746 109.18711 32.504729-54.593555z" fill="#6E6E96" opacity=".2" p-id="1169"></path></svg>-->
|
<!-- </div>-->
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import ClipboardJS from 'clipboard';
|
import {sendKbMsg} from "@/api/chat";
|
import {Message} from "element-ui";
|
|
export default {
|
name: 'AiChat',
|
data() {
|
return {
|
messages: [
|
{
|
role: 'assistant',
|
content: '你好!我是你的 AI 助手,有什么可以帮你的吗?',
|
},
|
{
|
role: 'user',
|
content: '你好!我是你的 AI 助手,有什么可以帮你的吗?',
|
},
|
],
|
inputMessage: '',
|
sendMsgForm: {
|
query: "",
|
mode: "local_kb",
|
kb_name: "samples",
|
top_k: 3,
|
score_threshold: 2,
|
history: [
|
{
|
"content": "我们来玩成语接龙,我先来,生龙活虎",
|
"role": "user"
|
},
|
{
|
"content": "虎头虎脑",
|
"role": "assistant"
|
}
|
],
|
stream: true,
|
model: "qwen:7b",
|
temperature: 0.7,
|
max_tokens: 0,
|
prompt_name: "default",
|
return_direct: false
|
},
|
msgIndex: null,
|
msgRole: null
|
};
|
},
|
methods: {
|
handleMouseEnter(msgIndex) {
|
console.log("鼠标移入", msgIndex)
|
this.msgIndex = msgIndex
|
},
|
handleMouseLeave() {
|
console.log("鼠标移除")
|
this.msgIndex = null
|
},
|
// 重新生成
|
reAnswer() {
|
},
|
// 复制内容
|
copyText(content) {
|
const clipboard = new ClipboardJS('.copy', {
|
text: () => content
|
});
|
// 触发复制(需要一个隐藏的按钮)
|
document.querySelector('.copy').click();
|
clipboard.destroy();
|
Message.success("复制成功")
|
},
|
// 获取角色头像
|
getAvatar(role) {
|
const avatars = {
|
user: 'https://picsum.photos/200',
|
assistant: 'https://picsum.photos/200',
|
};
|
return avatars[role];
|
},
|
|
// 获取角色名称
|
getRoleName(role) {
|
const roleNames = {
|
user: '用户',
|
assistant: 'AI 助手',
|
};
|
return roleNames[role];
|
},
|
|
// 发送消息
|
async sendMessage() {
|
if (this.inputMessage.trim() === '') return;
|
|
// 添加用户消息
|
this.messages.push({
|
role: 'user',
|
content: this.inputMessage,
|
});
|
this.sendMsgForm.query = this.inputMessage
|
// 清空输入框
|
this.inputMessage = '';
|
|
sendKbMsg(this.sendMsgForm).then(res => {
|
console.log(res, "拿到回复了!!")
|
this.messages.push({
|
role: 'assistant',
|
content: '这是一条 AI 回复。',
|
});
|
})
|
},
|
},
|
};
|
</script>
|
|
<style scoped>
|
.send-but {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
width: 58px;
|
height: 54px;
|
background-color: #f6f6f6;
|
margin-left: 5px;
|
}
|
.send-but:hover {
|
cursor: pointer;
|
}
|
.ai-chat-dialog {
|
display: flex;
|
flex-direction: column;
|
border-radius: 8px;
|
overflow: hidden;
|
}
|
|
.chat-messages {
|
padding: 16px;
|
margin-top: 14px;
|
overflow-y: auto;
|
width: 800px;
|
height: 680px;
|
}
|
|
.message {
|
display: flex;
|
margin-bottom: 18px;
|
min-height: 75px;
|
}
|
|
.message.user {
|
align-items: center;
|
flex-direction: row-reverse;
|
}
|
|
.avatar img {
|
width: 40px;
|
height: 40px;
|
border-radius: 50%;
|
}
|
|
.content {
|
max-width: 70%;
|
margin: 0 12px;
|
padding: 8px 12px;
|
border-radius: 8px;
|
background-color: #fff;
|
/*box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);*/
|
}
|
|
.message.user .content {
|
background-color: #409eff;
|
color: #fff;
|
}
|
|
.name {
|
font-size: 12px;
|
color: #666;
|
margin-bottom: 4px;
|
}
|
|
.message.user .name {
|
color: #fff;
|
}
|
|
.text {
|
font-size: 14px;
|
}
|
|
.chat-input {
|
padding: 16px;
|
background-color: #fff;
|
width: 800px;
|
display: flex;
|
flex-direction: row;
|
justify-content: center;
|
align-items: center;
|
position: absolute;
|
bottom: 50px;
|
left: 50%; /* 将 div 的左边移动到父容器的 50% 位置 */
|
transform: translateX(-50%); /* 将 div 向左移动自身宽度的 50% */
|
}
|
|
.msg-op-list {
|
margin-top: 15px;
|
}
|
.msg-copy {
|
font-size: 18px;
|
}
|
.msg-re {
|
font-size: 20px;
|
}
|
.msg-op {
|
color: gray;
|
margin-right: 5px;
|
}
|
.msg-op:hover {
|
cursor: pointer;
|
}
|
</style>
|