Vue2下项目集成DeepSeek API
1.使用命令下载vue2项目
vue create deepseek
2.进入到deepseek项目里 下载依赖 启动
1.进入到项目里
cd deepseek2.下载依赖
npm install3.下载deepseek所需要的依赖
npm install axios
npm install markdown
npm install marked
npm install html-loader
npm install dompurify3.启动
npm run serve
3.接下来就是核心代码了 搭建最基础问答页面
3-1 App.vue 替换成以下内容
<template><div id="app"><div class="chat-container"><div class="chat-content"><div class="chatBox"><div><imgsrc="https://cdn.deepseek.com/platform/favicon.png"style="color: blue; margin: 10px 10px 5px 10px"class="avatar"alt="机器人头像"/><h1 style="color: limegreen; margin: 0px 10px 0px 10px">嗨~Vue3-DeepSeek</h1><div style="margin: 0px 10px 0px 10px">你身边的智能小帮手,我可以帮你搜索、答疑、写作,请把你的任务交给我吧~</div></div><divv-if="errorMessage"class="error-message">{{ errorMessage }}</div><div class="chat-messages"><divv-for="(message, index) in currentMessages":key="index"class="message"><divv-if="message.sender === 'user'"class="user-message-container"><article class="message-content user-message">{{ message.text }}</article><imgsrc="../src/assets/ermimi.jpg"class="avatar user-avatar"alt="用户头像"/></div><divv-elseclass="bot-message-container"><imgsrc="https://cdn.deepseek.com/platform/favicon.png"class="avatar bot-avatar"alt="机器人头像"/><articleclass="message-content bot-message"v-html="renderMarkdown(message.text)":data-completed="message.completed || !isStreaming"></article></div></div></div><div class="chat-input"><textareav-model="inputMessage"placeholder="请输入您的问题"@keyup.enter.exact="handleSend"rows="6":disabled="isStreaming"/><button@click="handleButtonClick":disabled="!inputMessage.trim() && !isStreaming">{{ isStreaming ? "停止生成" : "发送" }}</button></div></div></div></div></div>
</template><script>
import marked from "marked";
import DOMPurify from "dompurify";
import { postStream } from "./deepSeek.js";export default {name: "App",data() {return {currentMessages: [],inputMessage: "",errorMessage: "",currentBotMessage: "",isStreaming: false,abortController: null,conversationId: null,// 头像URL可以存储在data中以便动态更改userAvatar: "",botAvatar: "",};},created() {this.generateConversationId();},methods: {generateConversationId() {this.conversationId = "conv-" + Date.now();},renderMarkdown(content) {content = content || "";content = content.replace(/<think>/g,'<div class="thinking-container"><img src="https://cdn-icons-png.flaticon.com/512/1055/1055687.png" class="thinking-icon"><span class="deepThink">');if (!content.includes("</think>")) {content = content.concat("</span></div>");}if (content.includes("</think>")) {content = content.replace(/<\/span><\/div>/g, "");content = content.replace(/<\/think>/g, "</span></div>");}const html = marked(content);const sanitizedHtml = DOMPurify.sanitize(html);const tempDiv = document.createElement("div");tempDiv.innerHTML = sanitizedHtml.toString();const deepThinkElements = tempDiv.querySelectorAll(".deepThink");deepThinkElements.forEach((element) => {if (element.textContent.trim() === "") {element.textContent = "暂无推理过程";}});return tempDiv.innerHTML;},async handleSend() {if (!this.inputMessage.trim() || this.isStreaming) return;this.abortController = new AbortController();const userMessage = {sender: "user",text: this.inputMessage,conversationId: this.conversationId,};this.currentMessages.push(userMessage);const botMessageIndex = this.currentMessages.length;this.currentMessages.push({sender: "system",text: "",completed: false,conversationId: this.conversationId,});const conversationHistory = this.buildConversationHistory();this.inputMessage = "";this.isStreaming = true;this.currentBotMessage = "";try {const response = await postStream({messages: conversationHistory,model: "deepseek-chat",stream: true,conversation_id: this.conversationId,},{signal: this.abortController.signal,});const reader = response.body.getReader();const decoder = new TextDecoder();while (this.isStreaming) {const { done, value } = await reader.read();if (done) break;const text = decoder.decode(value);const lines = text.split("\n\n").filter((line) => line.trim());for (const line of lines) {if (line.trim() === "data: [DONE]") {this.finishGeneration(botMessageIndex);return;}if (line.startsWith("data: ")) {try {const jsonStr = line.substring(6);const data = JSON.parse(jsonStr);console.log(data, "data==data");if (data.choices?.[0]?.delta?.content) {this.currentBotMessage += data.choices[0].delta.content;this.$set(this.currentMessages, botMessageIndex, {sender: "system",text: this.currentBotMessage,completed: false,conversationId: this.conversationId,});this.$nextTick(() => {const container = this.$el.querySelector(".chat-messages");container.scrollTop = container.scrollHeight;});}} catch (e) {console.error("解析JSON出错:", e);}}}}} catch (error) {if (error.name !== "AbortError") {console.error("流式请求出错:", error);this.errorMessage = "请求出错: " + error.message;this.$set(this.currentMessages, botMessageIndex, {sender: "system",text: "请求出错: " + error.message,completed: true,conversationId: this.conversationId,});}} finally {if (this.isStreaming) {this.finishGeneration(botMessageIndex);}}},buildConversationHistory() {const currentConversationMessages = this.currentMessages.filter((msg) => msg.conversationId === this.conversationId);const recentMessages = currentConversationMessages.slice(-10);return recentMessages.map((message) => {return {role: message.sender === "user" ? "user" : "assistant",content: message.text,};});},finishGeneration(index) {this.isStreaming = false;if (this.abortController) {this.abortController.abort();this.abortController = null;}this.$set(this.currentMessages, index, {...this.currentMessages[index],completed: true,});},handleButtonClick() {if (this.isStreaming) {this.finishGeneration(this.currentMessages.length - 1);} else {this.handleSend();}},startNewConversation() {this.generateConversationId();},},
};
</script>
<style scoped>
#app {display: flex;height: 100vh;margin: 0;padding: 0;background-color: #f9f9f9;
}
.chat-container {display: flex;width: 100%;height: 100%;border: 1px solid #e0e0e0;border-radius: 10px;overflow: hidden;background-color: white;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.chat-content {width: 100%;height: 100%;padding: 15px;box-sizing: border-box;
}
.chatBox {display: flex;flex-direction: column;height: 92%;width: 100%;border: 1px solid #e0e0e0;border-radius: 10px;overflow: hidden;background-color: white;
}
.error-message {background-color: #f8d7da;color: #721c24;padding: 12px;margin-bottom: 12px;border-radius: 8px;text-align: center;
}
.chat-messages {flex: 1;padding: 15px;overflow-y: auto;
}
.message {margin-bottom: 15px;display: flex;align-items: flex-start;
}
.user-message-container {display: flex;justify-content: flex-end;width: 100%;align-items: flex-start;gap: 10px;
}
.bot-message-container {display: flex;justify-content: flex-start;width: 100%;align-items: flex-start;gap: 10px;
}
.avatar {width: 40px;height: 40px;border-radius: 50%;object-fit: cover;flex-shrink: 0;
}
.user-avatar {border: 2px solid #2196f3;
}
.bot-avatar {border: 2px solid #4caf50;
}
.message-content {max-width: calc(80% - 50px);padding: 10px 15px;border-radius: 18px;line-height: 1.4;word-wrap: break-word;
}
.user-message {background-color: #e3f2fd;margin-left: 20%;
}
.bot-message {background-color: #f5f5f5;margin-right: 20%;
}
.chat-input {display: flex;padding: 15px;border-top: 1px solid #e0e0e0;background-color: #fff;
}
.chat-input textarea {flex: 1;padding: 12px;border: 1px solid #e0e0e0;border-radius: 8px;margin-right: 12px;resize: none;min-height: 60px;max-height: 150px;font-family: inherit;font-size: 14px;
}
.chat-input textarea:focus {outline: none;border-color: #2196f3;
}
.chat-input button {padding: 0 20px;height: 48px;background-color: #2196f3;color: white;border: none;border-radius: 8px;cursor: pointer;font-size: 14px;transition: background-color 0.2s;
}
.chat-input button:hover {background-color: #1976d2;
}
.chat-input button:disabled {background-color: #b0bec5;cursor: not-allowed;
}
.bot-message:not([data-completed="true"]):after {content: "|";animation: blink 1s infinite;color: #666;
}
@keyframes blink {0%,100% {opacity: 1;}50% {opacity: 0;}
}
/* 深度思考样式 */
.deepThink {color: #666;font-style: italic;background-color: #f0f0f0;padding: 8px 12px;border-radius: 8px;display: inline-block;margin-top: 5px;
}
.thinking-container {display: flex;align-items: center;gap: 8px;margin: 5px 0;
}
.thinking-icon {width: 16px;height: 16px;opacity: 0.6;
}
</style>
3-2 和App.vue 同级下 建个deepseek.js(接口及集合DeepSeek一些配置)
const DEEPSEEK_API_KEY = ""; // 替换为你的 DeepSeek API Key// /**
// * 调用 DeepSeek API 示例
// * @param {Object} data 请求参数
// * @returns {Promise} API 响应
// */
// export function postStream(data) {
// return fetch("https://api.deepseek.com/chat/completions", {
// method: "post",
// body: JSON.stringify(data),
// headers: {
// Authorization: `Bearer ${DEEPSEEK_API_KEY}`,
// "Content-Type": "application/json",
// },
// });
// }/*** 调用 DeepSeek API 示例* @param {Object} data 请求参数* @returns {Promise} API 响应*/
export function postStream(data) {// 确保传入的data对象包含model和参数配置const requestData = {// 指定模型版本model: "deepseek-reasoner",// 模型版本配置model_version: "DeepSeek-V3.2-Exp",// 添加思考模式配置params: {// 是否启用思考模式thinking_mode: true,// 其他可选参数temperature: 0.7,max_tokens: 4096,// 更多参数...},// 合并用户传入的其他数据...data,};return fetch("https://api.deepseek.com/chat/completions", {method: "post",body: JSON.stringify(requestData),headers: {Authorization: `Bearer ${DEEPSEEK_API_KEY}`,"Content-Type": "application/json",},});
}
