DeepSeek + Vue实战开发
利用DeepSeek V3模型、siliconflow大模型一站式云服务平台以及vue3.0实现一个在线人工智能客服对话系统。
因为deepseek官网的api密钥使用起来比较缓慢,所以可以使用第三方的,具体操作请自行查阅资料。
siliconflow官网
SiliconFlow, Accelerate AGI to Benefit Humanity硅基流动致力于打造规模化、标准化、高效能 AI Infra 平台,提供高效能、低成本的多品类 AI 模型服务,助力开发者和企业聚焦产品创新。https://siliconflow.cn/zh-cn/
完整运行代码
运行之前请先修改请求头(headers)中的密钥(token)以及对话模型(model)
请注意:这里的使用的是siliconflow中的token
<template>
<div class="chatbot-container">
<div
class="avatar"
@click="toggleChat"
:style="{
transform: isChatOpen
? 'scale(0.9) rotate(-8deg)'
: 'scale(1) rotate(0)',
}"
></div>
<div
class="chat-dialog"
:class="{ active: isChatOpen }"
v-click-outside="closeChat"
>
<div class="dialog-header">
<h3>在线客服</h3>
<div class="close-btn" @click="toggleChat">×</div>
</div>
<div class="dialog-body">
<div class="message-container" ref="scrollbarRef">
<div
v-for="(message, index) in messages"
:key="index"
:class="[
'message-bubble',
message.type === 'user' ? 'user-message' : 'bot-message',
]"
>
{{ message.content }}
</div>
</div>
<div class="input-area">
<input
v-model="inputMessage"
type="text"
class="message-input"
placeholder="输入消息..."
@keypress.enter="sendMessage"
/>
<button class="send-button" @click="sendMessage">发送</button>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { nextTick, ref } from "vue";
const isChatOpen = ref(false);
const inputMessage = ref("");
const messages = ref([]);
const toggleChat = () => {
isChatOpen.value = !isChatOpen.value;
if (isChatOpen.value && messages.value.length === 0) {
messages.value.push({
type: "bot",
content: "您好!我是智能客服小助手,很高兴为您服务。请问有什么可以帮您?",
});
}
};
const closeChat = () => {
isChatOpen.value = false;
};
const sendMessage = () => {
const message = inputMessage.value.trim();
if (message) {
messages.value.push({
type: "user",
content: message,
});
inputMessage.value = "";
const messageContainer = document.querySelector(".message-container");
try {
setTimeout(async () => {
messages.value.push({
type: "bot",
content: "正在思考中...",
});
nextTick(() => {
// 滚动到底部
messageContainer.scrollTop = messageContainer.scrollHeight;
});
// 发送请求
const response = await fetch(
"https://api.siliconflow.cn/v1/chat/completions",
{
method: "POST",
headers: {
Authorization:
"Bearer 你的siliconflow密钥",
"Content-Type": "application/json",
},
body: JSON.stringify({
frequency_penalty: 0,
max_tokens: 1024,
model: "deepseek-ai/DeepSeek-V3",
temperature: 0,
top_k: 49,
top_p: 0.7,
messages: [
{
role: "user",
content: message,
},
],
}),
}
);
const data = await response.json();
// 过滤 "正在思考中..." 消息
messages.value = messages.value.filter((item) => {
return item.content.indexOf("正在思考中") === -1;
});
if (response.choices) {
// 处理响应数据
messages.value.push({
type: "bot",
content: data.choices[0].message.content,
});
} else {
// 处理错误情况
messages.value.push({
type: "bot",
content: "抱歉,我现在无法回答您的问题,请稍后再试。",
});
}
nextTick(() => {
// 滚动到底部
messageContainer.scrollTop = messageContainer.scrollHeight;
});
}, 1000);
// 滚动到底部
} catch (error) {
console.error("Error:", error);
}
}
};
</script>
<style>
/* 原有样式保持不变 */
:root {
--primary-color: #4a90e2;
--hover-color: #357abd;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f0f2f5;
margin: 0;
font-family: "Microsoft YaHei", sans-serif;
}
.chatbot-container {
position: fixed;
bottom: 30px;
right: 30px;
z-index: 1000;
}
/* 新增头像样式 */
.avatar {
width: 60px;
height: 60px;
border-radius: 50%;
cursor: pointer;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
box-shadow: 0 8px 20px rgba(74, 144, 226, 0.3);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
background-color: #357abd;
}
.avatar:hover {
transform: scale(1.1) rotate(8deg);
box-shadow: 0 12px 25px rgba(74, 144, 226, 0.4);
}
.avatar::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 30px;
height: 30px;
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-3 12H7v-2h10v2zm0-3H7v-2h10v2zm0-3H7V6h10v2z"/></svg>')
no-repeat center;
}
/* 聊天对话框 */
.chat-dialog {
position: absolute;
bottom: 80px;
right: 0;
width: 320px;
background: white;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.1);
transform: scale(0);
transform-origin: bottom right;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.chat-dialog.active {
transform: scale(1);
}
.dialog-header {
padding: 16px;
background: var(--primary-color);
border-radius: 12px 12px 0 0;
color: white;
display: flex;
align-items: center;
}
.dialog-header h3 {
margin: 0;
font-size: 16px;
font-weight: 500;
}
.close-btn {
margin-left: auto;
cursor: pointer;
padding: 0px 4px;
border-radius: 50%;
background: rgba(0, 0, 0, 0.1);
}
.dialog-body {
padding: 16px;
height: 300px;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.message-container {
flex: 1;
overflow-y: auto;
margin-bottom: 16px;
display: flex;
flex-direction: column;
}
.input-area {
display: flex;
gap: 8px;
padding-top: 12px;
border-top: 1px solid #eee;
}
.message-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 20px;
outline: none;
transition: border-color 0.3s;
}
.message-input:focus {
border-color: var(--primary-color);
}
.send-button {
padding: 8px 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 20px;
cursor: pointer;
transition: background 0.3s;
font-size: 14px;
}
.send-button:hover {
background: var(--hover-color);
}
.message-bubble {
padding: 8px 12px;
margin-bottom: 8px;
border-radius: 5px;
animation: fadeIn 0.3s ease;
max-width: 80%;
display: inline-block;
word-break: break-all;
}
.user-message {
background: var(--primary-color);
color: white;
margin-left: auto;
}
.bot-message {
background: #f1f1f1;
color: #333;
margin-right: auto;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 响应式设计 */
@media (max-width: 480px) {
.chatbot-container {
bottom: 20px;
right: 20px;
}
.chat-dialog {
width: 90vw;
bottom: 70px;
}
.avatar {
width: 50px;
height: 50px;
}
}
</style>
效果在线预览
ps:文本对话请求可能会有连接超时的问题!