前端接入DeepSeek
2025.07.29今天我学习了如何把DeepSeek接入到前端页面进行使用,效果如下:
一、去deepseek官网创建apiKey。
DeepSeek
(注意:需要充值才能使用deepseek)
二、deepseekAPI.js
在api目录下创建deepseekAPI.js组件
import axios from 'axios';// 移除 interface 声明
// 简单的 JSDoc 注释替代类型注释
/*** @param {Array} messages - 消息数组* @returns {Promise<Object>} 返回消息对象*/
const apiKey = 'xxxxxxxxxxxxxxxx';//换成你自己的apiKey
const headers = {'Authorization': `Bearer ${apiKey}`,"Content-Type": "application/json","Accept": "application/json",
}// 调用方法
export const getDeepSeekReply = async (messages) => {const params = {messages: messages,model: "deepseek-chat",max_tokens: 1500,temperature: 0.7,top_p: 1,frequency_penalty: 0,presence_penalty: 0,};try {const response = await axios.post('https://api.deepseek.com/chat/completions', params, {headers: headers});return response.data.choices[0].message;} catch (error) {console.error('Axios error:', error);return { content: '获取失败.', role: 'assistant' };}
}// 获取当前余额
export const getRemainingNum = async () => {try {const response = await axios.get('https://api.deepseek.com/user/balance', {headers: headers});return response.data.balance_infos[0].total_balance;} catch (error) {console.error('Axios error:', error);return { content: '获取失败.', role: 'assistant' };}
}
三、新页面
包含打印机效果,以及复制文本内容功能。
<template><div class="app-container"><div class="chat-container"><div class="messages-container" ref="messagesContainer"><div v-for="(message, index) in messages" :key="index" :class="['message', message.type]"><div class="message-content"><div class="avatar"><el-avatar icon="el-icon-user-solid"/></div><div class="text-content"><div class="sender">{{ message.sender }}</div><!-- 修改文本显示方式 --><div class="text" v-if="message.type === 'received' && message.isTyping"><div><el-tooltip content="复制"><el-button icon="el-icon-document-copy" type="text" @click="copy_content(message)" /></el-tooltip></div><span v-for="(char, charIndex) in message.displayedText" :key="charIndex">{{ char }}</span><span class="typing-cursor">|</span></div><div class="text" v-else><div v-if="message.type === 'received'"><el-tooltip content="复制"><el-button icon="el-icon-document-copy" type="text" @click="copy_content(message)" /></el-tooltip></div>{{ message.text }}</div><div class="time">{{ message.time }}</div></div></div></div></div><div v-if="isLoading" class="loading">正在加载...</div><div class="input-container"><el-input type="textarea" v-model="newMessage" placeholder="输入消息..." @keydown.enter.native.prevent="sendMessage" ref="messageInput"/><button @click="sendMessage" :disabled="!newMessage.trim() || isTyping" class="send-button">发送</button></div></div></div>
</template><script>import { getDeepSeekReply } from '@/api/deepseekApi';import moment from 'moment';
import axios from 'axios'export default {name: 'ChatInterface',data() {return {newMessage: '',messages: [],isLoading: false,isTyping: false, // 标记AI是否正在打字copy_text:'',//复制文本is_copy:false,//是否复制成功}},methods: {async sendMessage() {if (!this.newMessage.trim() || this.isTyping) return;this.is_copy = false;// 添加新消息this.messages.push({type: 'sent',sender: 'admin',text: this.newMessage,time: moment().format('HH:mm'),});// 保存输入内容并清空输入框let input_message = this.newMessage;this.newMessage = '';this.isLoading = true;try {let demo_text = await getDeepSeekReply([{content:input_message,role:'user'}]);let message = demo_text.content;// 开始打字机效果this.startTypingEffect(message);} catch (error) {console.error('请求失败:', error);this.messages.push({type: 'received',sender: 'AI',text: '抱歉,获取回复失败,请稍后重试。',time: moment().format('HH:mm'),});this.isLoading = false;}},startTypingEffect(fullText) {this.isLoading = false;this.isTyping = true;// 添加一个空的AI消息占位const messageIndex = this.messages.length;this.messages.push({type: 'received',sender: 'AI',text: fullText, // 保存完整文本displayedText: '', // 当前显示的文本isTyping: true, // 标记正在打字time: moment().format('HH:mm'),});let currentIndex = 0;const typingSpeed = 10; // 打字速度(毫秒)const typeNextChar = () => {if (currentIndex < fullText.length) {// 逐字添加字符this.messages[messageIndex].displayedText += fullText.charAt(currentIndex);currentIndex++;// 滚动到底部// this.$nextTick(() => {// this.scrollToBottom();// });// 继续打字setTimeout(typeNextChar, typingSpeed);} else {// 打字完成this.messages[messageIndex].isTyping = false;this.isTyping = false;// 滚动到底部this.$nextTick(() => {this.scrollToBottom();});}};// 开始打字typeNextChar();},// 滚动到底部scrollToBottom() {const container = this.$refs.messagesContainer;if (container) {container.scrollTop = container.scrollHeight;}},// 复制文本内容copy_content(row){this.copy_text = row.text;//复制文本内容document.execCommand('copy');// 只有在https local受信任的网址才能使用// navigator.clipboard.writeText(row.text).then(()=>{// this.$message.success('复制成功');// })},copyListener(event){const clipboardData = event.clipboardData || window.clipboardData;clipboardData.setData('text', this.copy_text);event.preventDefault();if(!this.is_copy){this.is_copy = true;this.$message.success('复制成功');}}},mounted() {// 组件挂载后滚动到底部this.scrollToBottom();// 聚焦输入框this.$refs.messageInput.focus();window.addEventListener('copy', this.copyListener);//复制文本}
}
</script><style scoped>
.chat-container {display: flex;flex-direction: column;width: 100%;height: 80vh;margin: 0 auto;border: 1px solid #e0e0e0;border-radius: 8px;overflow: hidden;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}.messages-container {flex: 1;overflow-y: auto;padding: 20px;background-color: #f9f9f9;
}.message {margin-bottom: 15px;
}.message-content {display: flex;align-items: flex-start;
}.avatar img {width: 40px;height: 40px;border-radius: 50%;margin-right: 10px;
}.text-content {max-width: 70%;
}.sender {font-size: 12px;color: #666;margin-bottom: 4px;
}.text {background-color: white;padding: 10px 15px;border-radius: 18px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);word-wrap: break-word;white-space: pre-wrap;}.time {font-size: 11px;color: #999;margin-top: 4px;text-align: right;
}/* 发送的消息样式 */
.message.sent .message-content {flex-direction: row-reverse;
}.message.sent .avatar {margin-right: 0;margin-left: 10px;
}.message.sent .text-content {text-align: right;
}.message.sent .text {background-color: #4A90E2;color: white;border-radius: 18px 4px 18px 18px;
}.message.sent .time {text-align: right;
}/* 接收的消息样式 */
.message.received .text {background-color: #99de68;border-radius: 4px 18px 18px 18px;
}.input-container {display: flex;padding: 15px;background-color: white;border-top: 1px solid #e0e0e0;
}textarea {flex: 1;padding: 10px;border: 1px solid #e0e0e0;border-radius: 20px;resize: none;height: 60px;font-family: inherit;font-size: 14px;outline: none;
}textarea:focus {border-color: #4A90E2;
}.send-button {margin-left: 10px;padding: 0 25px;background-color: #4A90E2;color: white;border: none;border-radius: 20px;cursor: pointer;font-size: 14px;transition: background-color 0.3s;
}.send-button:hover:not(:disabled) {background-color: #357ABD;
}.send-button:disabled {background-color: #cccccc;cursor: not-allowed;
}/* 滚动条样式 */
.messages-container::-webkit-scrollbar {width: 6px;
}.messages-container::-webkit-scrollbar-track {background: #f1f1f1;
}.messages-container::-webkit-scrollbar-thumb {background: #c1c1c1;border-radius: 3px;
}.messages-container::-webkit-scrollbar-thumb:hover {background: #a8a8a8;
}.loading {text-align: center;color: #666;margin-top: 10px;
}/* 添加打字机光标样式 */
.typing-cursor {display: inline-block;width: 2px;height: 1em;background-color: #333;margin-left: 2px;animation: blink 1s infinite;
}@keyframes blink {0%, 100% { opacity: 1; }50% { opacity: 0; }
}</style>