效果
前端样式体验链接:https://livequeen.top/deepseekshow
准备工作
1、注册deepseek官网账号
地址:DeepSeek
点击进入右上角【API开放平台】,并进行账号注册。
2、注册完成后,依次点击【API keys】-【生成API key】,记住自己保存好API keys,他只会显示一次,如果忘了,就要重新生成了!
然后点击【接口文档】,就可以看到官方API文档了!
3、在接口文档中,点击【首次调用API】,然后选择对应的语言,就可以看到示例代码了
代码示例
这里用vue+node.js做一个上面效果动态图的简单示例:
一、后端
1、 引入依赖,在终端中输入如下指令
npm install openai
2、新建一个工具类【deepseek.js】,用于执行deepseek的API并返回结果,如下(可直接复制):
// Please install OpenAI SDK first: `npm install openai`
const OpenAI = require('openai')
// api参数配置
const openai = new OpenAI({
baseURL: 'https://api.deepseek.com',
apiKey: 'sk-c63c***********************e1e0b70'
})
/**
* message 消息列表
* role 角色
* content 对话内容
* name 某个角色的参与者,用于区分相同角色(选填)
* model 模型 [deepseek-chat, deepseek-reasoner] deepseek-chat 模型已全面升级为 DeepSeek-V3。
*/
async function deepSeekChat (contents) {
// 执行获取结果
const completion = await openai.chat.completions.create({
messages: [{
role: 'system',
content: contents
}],
model: 'deepseek-chat'
})
// 返回结果
return completion.choices[0].message.content
}
module.exports = {
deepSeekChat
}
3、在你自己的后端接口中通过异步调用的方式,来传参调用上面工具类里面的deepSeekChat()方法 ,如下:
// 引用前面deepseek工具类的方法
const {deepSeekChat} = require('../utils/deepseek')
// 后端接口(异步)
router.post('/deepseek', async (req, res) => {
// 调用前面deepseek工具类的方法
let data = await deepSeekChat(req.body.contents)
// 返回结果
res.end(JSON.stringify({
traceId: req.traceId,
code: 200,
data: data
}))
})
二、前端
1、h5布局
<template>
<div class="mess_dialog" v-loading="isloading">
<!-- 对话框头部 -->
<div class="dlog_header">
<h1>DeepSeek对话</h1>
</div>
<!-- 对话框内容 -->
<div id="content_overflow" class="dlog_content" ref="scrollContainer" @scroll="handleScroll">
<div v-for="(item, index) in messnowList" :key="index" class="dlog_content_item" style="margin-left: 5px;">
<!-- AI消息展示 -->
<div v-if="item.role === 'system'" class="content_other">
<!-- 头像 -->
<div>
<el-avatar :size="35" :src="require('../../../assets/image/ai.png')" style="margin-top: 5px;"></el-avatar>
</div>
<div class="mess_other">
<!-- 发送时间 -->
<div>
<span style="font-size: 8px;">{{item.date}}</span>
</div>
<!-- 发送内容 -->
<div class="content_other_bgd">
<span class="mess_content_msg">{{item.content}}</span>
</div>
<!-- 复制按钮 -->
<div class="iconCopy" @click="onCopy(item.content)">
<i class="el-icon-copy-document"></i>
</div>
</div>
</div>
<!--本用户的消息展示-->
<div v-else-if="item.role === 'user'" class="content_me">
<div class="mess_me">
<!-- 发送时间 -->
<div>
<span style="font-size: 8px;">{{item.date}}</span>
</div>
<!-- 发送内容 -->
<div class="content_me_bgd">
<span class="mess_content_msg">{{item.content}}</span>
</div>
</div>
<!-- 头像 -->
<div>
<el-avatar :size="35" :src="userAvatar" style="margin-top: 5px;"></el-avatar>
</div>
</div>
</div>
</div>
<!--对话框底部-->
<div class="dlog_footer">
<div class="footer_content">
<el-input type="textarea" :rows="4" v-model="mess" maxlength="500" show-word-limit @keydown.enter.native="keyDown"></el-input>
<el-button type="primary" @click="Wssendmess()" style="float: right;margin-top: 5px;">发送</el-button>
</div>
</div>
</div>
</template>
2、css样式
<style scoped>
.mess_dialog {
height: 100%;
width: 100%;
max-width: 800px;
position: relative;
margin: 0 auto;
display: flex;
flex-direction: column; /* 垂直排列 */
}
.dlog_header {
display: flex;
justify-content: center;
flex: 1;
}
.dlog_content {
flex: 7;
overflow-y: auto;
overflow-x: hidden;
}
.content_other{
width: 80%;
display: flex;
justify-content: flex-start;
margin: 11px 18px;
}
.mess_other{
text-align: left;
margin-left: 10px;
}
.content_me{
width: 80%;
display: flex;
justify-content: flex-end;
float: right;
margin: 11px 18px;
}
.mess_me{
text-align: right;
margin-right: 10px;
}
.mess_content_msg{
font-size: 16px;
font-weight: 300;
margin: 2px;
}
/*其他用户的气泡*/
.content_other_bgd {
border-radius: 6px;
position: relative;
display: inline-block;
padding: 0px 6px;
width: auto;
height: auto;
line-height: 34px;
background: #e3e1e1;
z-index: 0;
}
/*气泡前的小三角指向*/
.content_other_bgd::before {
border-style: solid;
border-width: 0 11px 11px 0;
border-color: transparent #e3e1e1 transparent transparent;
content: "";
position: absolute;
top: 10px; left: -8px;
margin-top: -9px;
display: block;
width: 0px;
height: 0px;
z-index: 0;
}
/*我方的气泡*/
.content_me_bgd {
border-radius: 6px;
position: relative;
display: inline-block;
padding: 0px 6px;
width: auto;
height: auto;
line-height: 34px;
background: #95ec69;
z-index: 0;
text-align: left;
}
.content_me_bgd::after {
border-style: solid;
border-width: 0 0 11px 11px;
border-color: transparent transparent transparent #95ec69;
content: "";
position: absolute;
top: 10px; right: -8px;
margin-top: -10px;
display: block;
width: 0px;
height: 0px;
z-index: -1;
}
.iconCopy{
padding: 7px;
margin-top: 3px;
width: 20px;
border-radius: 5px;
display: flex;
justify-content: center;
}
.el-icon-copy-document{
color: #a2a2a2;
}
.iconCopy:hover {
background-color: #ecebeb;
}
.iconCopy:hover .el-icon-copy-document{
color: #3d9aff;
}
.iconCopy:active {
background-color: #dedede;
}
.iconCopy:active .el-icon-copy-document{
color: #0b7bf5;
}
.dlog_footer{
width: 100%;
flex: 2;
padding: 10px 0;
}
</style>
3、js函数
<script>
import userAvatar from '@/assets/image/userAvatar.png'
import moment from 'moment/moment'
import cookie from '../../../utils/cookie'
import base from '../../../api/base'
export default {
name: 'Index',
data () {
return {
mess: '', // 输入的信息
userAvatar: userAvatar, // 默认用户头像
autoScroll: true, // 是否需要自动滚动到底部
messnowList: [], // 当前对话用户的-聊天内容列表
isloading: false // 加载中,默认关闭
}
},
watch: {
// 监听当前消息列表,更新时,保持滚动条位于底部
messnowList: {
handler (newValue, oldValue) {
this.scrollToBottom()
},
deep: true
}
},
methods: {
// 监听用户滑动情况,判断是否需要自动定位底部
handleScroll () {
// 绑定组件
const container = this.$refs.scrollContainer
// 判断用户是否手动向上滚动超过底部位置30px
if (container.scrollHeight - container.scrollTop - container.clientHeight > 50) {
this.autoScroll = false // 用户手动滚动,停止自动滚动
} else {
this.autoScroll = true // 用户滚动到底部,恢复自动滚动
}
},
// 定位到底部
scrollToBottom () {
this.$nextTick(() => {
var message = document.getElementById('content_overflow')
if (this.autoScroll) {
// 滚动滑钮到滚动条顶部的距离=滚动条的高度
message.scrollTop = message.scrollHeight
}
})
},
// enter发送消息,ctrl+enter换行
keyDown (e) {
if (e.ctrlKey && e.keyCode === 13) { // 用户点击了ctrl+enter触发
this.mess += '\n'
} else { // 用户点击了enter触发
this.Wssendmess()
e.preventDefault() // 阻止浏览器默认换行操作
return false
}
},
// 发送按钮
Wssendmess () {
var message = this.mess.trim()
this.mess = ''
// 开启加载
this.isloading = true
// 判断是否有字符输入
if (message === null | message === '') {
this.$notify({
title: '提示',
message: '发送内容不能为空!',
type: 'warning'
})
// 关闭加载
this.isloading = false
} else {
// 用户发言,恢复自动滚动
this.autoScroll = true
// 保存到数据集合中
let date = moment().format('YYYY-MM-DD HH:mm:ss')
let item = this.data_rule('user', message, date)
this.messnowList.push(item)
// 执行接口
this.$api.deepseek(message)
.then(res => {
// 关闭加载
this.isloading = false
if (res.data.code === 200) {
this.chatAI(res.data.data)
} else {
this.chatAI('服务器繁忙,请稍后重试!')
}
})
.catch(err => {
// 关闭加载
this.isloading = false
this.chatAI('服务器繁忙,请稍后重试!')
console.log(err)
})
}
},
// 规范数据格式
data_rule (role, content, date) {
return {
role: role,
content: content,
date: date
}
},
/**
* 模拟AI机器人打字效果
* @param content 返回的全部文本
*/
chatAI (content) {
// 获取返回结果
let data = content
// 临时储存结果(一个个字符)
let dataTemp = data[0]
let date = moment().format('YYYY-MM-DD HH:mm:ss')
// 循环一个个字符赋予,模拟机器人打字效果
let item2 = this.data_rule('system', dataTemp + '_', date)
this.messnowList.push(item2)
let nowSize = this.messnowList.length - 1
if (data.length > 1) {
for (let i = 1; i < data.length; i++) {
setTimeout(() => {
if (i === data.length - 1) {
dataTemp = dataTemp + data[i]
item2 = this.data_rule('system', dataTemp, date)
} else {
dataTemp = dataTemp + data[i]
item2 = this.data_rule('system', dataTemp + '_', date)
}
this.messnowList[nowSize] = item2
// 更新组件监听
this.$forceUpdate()
// 更新滚动条定位
this.scrollToBottom()
}, 100 * i)
}
}
},
// 复制按钮
onCopy (content) {
// 复制到粘贴板
navigator.clipboard.writeText(content)
.then(() => {
this.$message.success('复制成功')
})
.catch(err => {
this.$message.error('复制失败,原因:' + err)
})
}
}
}
</script>