vue3+deepseek 实现简单的问答(vue deep原理)
概述
本文档描述了基于 DeepSeek API 实现的智能助手 Web 应用的技术实现细节。该应用提供文本聊天和语音输入功能,支持与 DeepSeek 大模型进行交互。
功能特性
- 文本聊天:用户可通过文本输入与 AI 进行交互
- 语音输入:支持按住说话进行语音输入
- 响应式设计:适配移动端和 Web 端
- 消息展示:区分用户消息和 AI 回复
- 加载状态:显示加载动画提升用户体验
技术栈
- Vue 3 (Composition API)
- Axios (HTTP 请求)
- Web Speech API (语音识别)
- Vant UI (部分组件)
- DeepSeek API (AI 交互)
API 配置
javascript
复制
const apiKey = '自己的key';
const baseURL = 'https://api.deepseek.com';
核心组件
模板结构
html
复制
<template>
<div class="chat-container">
<!-- 标题 -->
<div class="title">智能助手</div>
<!-- 消息列表 -->
<div class="inner">
<!-- 消息项 -->
<div v-for="(msg, index) in messages" :key="index" :class="['msgbox', msg.role == 'user' ? 'msgboxright' : 'msgboxleft']">
<!-- 头像 -->
<div class="headImg" v-if="msg.role != 'user'">
<img src="机器人头像URL" />
</div>
<!-- 消息内容 -->
<div :class="['message', msg.role]">
{{ msg.content }}
</div>
<!-- 用户头像 -->
<div class="headImg" v-if="msg.role == 'user'">
<img src="用户头像URL" />
</div>
</div>
<!-- 加载动画 -->
<div v-if="isLoading" class="snippet" data-title=".dot-elastic">
<div class="stage">
<div class="dot-elastic"></div>
</div>
</div>
</div>
<!-- 底部输入区域 -->
<div class="footer">
<div class="talk">
<!-- 语音/文本输入切换 -->
<div v-if="flag" class="aa" @touchstart="startListening" @touchend="stopListening">
{{ talkFlag ? '讲话中...' : '按住说话' }}
</div>
<!-- 文本输入框 -->
<input placeholder="请输入您的问题" v-else v-model="userInput" @keyup.enter="sendToDeepSeek" />
<!-- 发送按钮/切换按钮 -->
<div v-if="userInput" @click.stop="sendToDeepSeek">
<img v-if="!flag" src="发送图标URL" class="send" />
</div>
<div v-else @click.prevent.stop="changeFlag">
<img :src="flag ? '键盘图标URL' : '语音图标URL'" class="jianpan" />
</div>
</div>
</div>
</div>
</template>
运行 HTML
脚本逻辑
javascript
复制
import { ref, onMounted } from 'vue';
import axios from 'axios';
// 响应式数据
const messages = ref([{ role: 'system', content: '您好,请问有什么可以帮助您的吗?' }]);
const flag = ref(true); // 语音/文本输入标志
const userInput = ref(''); // 用户输入
const isLoading = ref(false); // 加载状态
const recognition = ref(null); // 语音识别对象
const transcript = ref(''); // 语音识别文本
const talkFlag = ref(false); // 语音识别状态
// 初始化语音识别
const initSpeechRecognition = () => {
if (window.webkitSpeechRecognition) {
recognition.value = new window.webkitSpeechRecognition();
recognition.value.continuous = true;
recognition.value.interimResults = true;
recognition.value.lang = 'zh-CN';
} else {
alert('你的浏览器不支持语音识别功能');
}
};
// 开始语音识别
const startListening = (e) => {
e.preventDefault();
talkFlag.value = true;
if (recognition.value) {
recognition.value.start();
recognition.value.onresult = (event) => {
transcript.value = Array.from(event.results)
.map(result => result[0])
.map(result => result.transcript)
.join('');
};
}
};
// 停止语音识别
const stopListening = (e) => {
e.preventDefault();
talkFlag.value = false;
if (recognition.value) {
if (transcript.value) {
messages.value.push({ role: 'user', content: transcript.value });
setTimeout(() => {
scrollNext();
handelMes();
});
}
recognition.value.stop();
}
};
// 发送消息到DeepSeek
const sendToDeepSeek = () => {
messages.value.push({ role: 'user', content: userInput.value });
userInput.value = '';
setTimeout(() => {
scrollNext();
handelMes();
});
};
// 处理AI回复
const handelMes = async () => {
try {
isLoading.value = true;
const response = await axios.post(
`${baseURL}/chat/completions`,
{
model: 'deepseek-chat',
messages: [...messages.value],
temperature: 0.7,
stream: false
},
{
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}
}
);
messages.value.push(response.data.choices[0].message);
setTimeout(() => {
scrollNext();
});
} catch (error) {
console.error('API调用失败:', error.response?.data || error.message);
} finally {
isLoading.value = false;
}
};
// 滚动到最新消息
const scrollNext = () => {
let list = document.getElementsByClassName('msgbox');
let tmp = list[list.length - 1];
let bottom = tmp.getBoundingClientRect().top;
window.scrollTo({
top: bottom,
left: 0,
behavior: 'smooth'
});
};
// 切换输入模式
const changeFlag = () => {
userInput.value = '';
transcript.value = '';
talkFlag.value = false;
flag.value = !flag.value;
};
onMounted(() => {
initSpeechRecognition();
});
样式设计
css
复制
.chat-container {
min-height: 100vh;
overflow-y: auto;
.title {
color: #fff;
font-size: 20px;
line-height: 60px;
padding: 0px 20px;
font-weight: bold;
background: rgb(0, 162, 255);
}
.inner {
padding: 20px;
}
.msgbox {
display: flex;
font-size: 14px;
margin-bottom: 30px;
.headImg {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
margin-right: 15px;
img {
width: 100%;
height: 100%;
object-fit: fill;
}
}
.message {
max-width: 80%;
background: #fff;
padding: 12px 16px;
border-radius: 12px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
}
.msgboxright {
justify-content: end;
.headImg {
margin-left: 15px;
}
}
.footer {
display: flex;
bottom: 0px;
width: 100%;
height: 80px;
padding: 0px 20px;
position: fixed;
background: #fff;
align-items: center;
justify-content: center;
.talk {
width: 100%;
border-radius: 30px;
border: 1px solid #e9e7e7;
height: 50px;
display: flex;
align-items: center;
padding: 0px 15px;
justify-content: space-between;
.aa {
font-size: 14px;
font-weight: bold;
line-height: 50px;
text-align: center;
width: 100%;
}
input {
width: 70%;
border: 0;
padding: 0px 5px;
font-size: 14px;
}
.send, .jianpan {
width: 30px;
height: 30px;
}
}
}
}
/* 加载动画样式 */
.dot-elastic {
position: relative;
width: 5px;
height: 5px;
margin: auto;
border-radius: 50%;
background-color: rgb(0, 162, 255);
color: rgb(0, 162, 255);
animation: dotElastic 1s infinite linear;
}
/* 动画关键帧定义 */
@keyframes dotElasticBefore {
0% { transform: scale(1, 1); }
25% { transform: scale(1, 1.5); }
50% { transform: scale(1, 0.67); }
75% { transform: scale(1, 1); }
100% { transform: scale(1, 1); }
}
@keyframes dotElastic {
0% { transform: scale(1, 1); }
25% { transform: scale(1, 1); }
50% { transform: scale(1, 1.5); }
75% { transform: scale(1, 1); }
100% { transform: scale(1, 1); }
}
@keyframes dotElasticAfter {
0% { transform: scale(1, 1); }
25% { transform: scale(1, 1); }
50% { transform: scale(1, 0.67); }
75% { transform: scale(1, 1.5); }
100% { transform: scale(1, 1); }
}
部署说明
- 在 DeepSeek 平台注册账号并获取 API Key
- 替换代码中的 apiKey 为您的实际 Key
- 构建并部署 Vue 应用
注意事项
- API Key 应妥善保管,避免泄露
- 语音识别功能需要浏览器支持 Web Speech API
- 生产环境应考虑添加 API 调用频率限制和错误处理
- 对于敏感信息,建议在后端处理 API 调用而非前端
示例效果
可通过以下链接查看实际效果:
https://h5-dev.ennejb.cn/h5_application/#/test