写在前面

关于deepseek这个gpt工具,我也是在前段时间小米实验室聘请DeepSeek-V2的关键开发者之一罗福莉上了热搜,我经过查询,才知道这个工具的。目前deepseek已经发展到了V3的版本,它提供了诸多的功能,比如:

  1. 信息查询:我可以快速检索并提供各种信息,包括科学知识、历史事件、文化习俗等。

  2. 语言翻译:我能够进行多种语言之间的翻译,帮助您跨越语言障碍。

  3. 学习辅导:我可以协助您理解复杂的概念,提供学习建议,甚至帮助您准备考试。

  4. 生活建议:我可以提供健康、饮食、锻炼等方面的建议,帮助您改善生活质量。

  5. 技术支持:我可以解答关于计算机、软件使用等技术问题,提供故障排除建议。

  6. 娱乐互动:我可以与您进行简单的对话,讲笑话,甚至参与一些文字游戏。

  7. 日程管理:我可以帮助您安排日程,提醒重要事件,助您更好地管理时间。

  8. 情感支持:虽然我没有情感,但我可以提供倾听和理解,为您提供心理支持的建议。

  9. 旅行规划:我可以提供旅行目的地的信息,帮助您规划行程。

  10. 商业咨询:我可以提供市场趋势分析、商业策略建议等。

美中不足的可能就是无法生成图片,但是对于我们日常查资料,已经可以满足我们的大多数需求了。下面的图是官网给出的与其他几个模型的对比: 69bd15aa2d69447e861d14b86875d680~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCW5qSS5Zyf6LGGc3Nz_q75.webp

目的

在前面的文章中,我在家里电脑做了穿透,是在家里部署了前端web的页面,但是目前没有什么实际用途,于是我突发奇想,着手自己开发一个gpt的页面,调用deepseek的接口即可。deepseek的接口调用不用科学上网的方式,而且价格也是目前我使用过里面,价格最低的,在我看来算是性价比比较高的一款了。至于为什么我不直接用官方的地址,后续可能我会自定义一些东西,集成到我自己的网站上面,官网的界面,就不太合适嵌入进去了。

着手去干

我使用的是vue3的项目,但是语法还是保留了vue2的语法,因为之前写过一些类似的,使用的是vue2,但是并不影响。下面先罗列一下要实现的功能

  1. 实现基础对话功能

  2. 添加缓存机制,在当前设备存储对话历史记录

  3. 允许多个会话窗口

  4. 允许修改会话窗口与删除会话窗口

  5. 允许会话通过打字机效果(这个算是最后补充的,一开始使用的是axios全量返回,时间周期花费较多)

项目环境准备

在使用过程中,我列出来我使用的几个插件:

  1. "@element-plus/icons-vue": "^2.3.1"

  2. "axios": "^1.7.9"

  3. "element-plus": "^2.9.1"

  4. "mobile-detect": "^1.4.5"

  5. "openai": "^4.77.0"

  6. "sass": "^1.83.0"

  7. "vue3-markdown-it": "^1.0.10"

因为考虑到我在手机上也会使用,因此加了一个手机端的判断(mobile-detect),但是这个可能不是很严谨,可以修改浏览器的参数被篡改,但是对于自己使用,是没有问题的。

而为了页面返回方便展示,我直接将返回,使用markdown语法进行了展示(vue3-markdown-it

其余的几个插件,应该也是很常见的,就是前端的UI框架、openai的请求插件、css预编译插件、axios请求插件

实现思路

对话实现:

下面的代码片段是官网给出的代码片段,只需要将<DeepSeek API Key>替换成自己的key即可进行对话,通过response.choices[0].message得到回答的语句。

// 初始化对话实例
from openai import OpenAI  
client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")
// 发送对话,获取返回
messages = [{"role": "user", "content": "What's the highest mountain in the world?"}]  
response = client.chat.completions.create(model="deepseek-chat", messages=messages)
console.log(response.choices[0].message)

至此,我们可以抓取到返回的数据,但是返回的是markdown的语法,因此如果直接把返回显示到客户端,用户看到的可能就是:

### 我是DeepSeek
**您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手*DeepSeek-V3*。**
如您有任何任何问题,我会尽我所能为您提供帮助。

这种展示效果并不友好,因此我使用了vue3-markdown-it这个插件来转换,这样页面就可以正常显示代码块了。而这个插件的使用也很简单,如下:

<template>
 <Markdown :source="source" />
</template>

<script>
 import Markdown from "vue3-markdown-it";
 export default {
   components: { Markdown },
   data(){
     return {
       source: '## 我是DeepSeek-V3'
     }
   }
 }
</script>

对话可以正常进行了,那么这时候我们就要添加一个其他的gpt都有的功能了,比如添加会话列表,删除会话列表,重命名等。

缓存储存对话历史记录

我这里没有使用数据库,因为这样的话,需要做用户登录校验,而这做起来就有点麻烦了,如果不做登录直接存库,就会出现如果地址泄露,记录也会被其他人读取到,可能会暴露个人隐私,所以我只做了浏览器的缓存,如果被泄露了,刷新一下sk码就可以了。

做本地缓存的话,就要实时去存储刷新缓存:

  1. 问询发出-存储到缓存

  2. 收到回答完成-存储缓存

  3. 如果收到的回答错误了-存储缓存并添加新的报错的记录并显示到页面

添加会话列表与删除会话,重命名

新增会话功能就类似于清屏,重新开始对话,但由于是新开的一个对话,因此也不用担心历史对话消失。但是为了减少对象数量,增加后续维护成本,这里调整了一下结构,例如:

69bd15aa2d69447e861d14b86875d680~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCW5qSS5Zyf6LGGc3Nz_q75.webp index就是当前选中的会话序号,crtTime就是当前新增这个会话的时间(不是修改的时间),title就是当前会话的名称,messages就是这个会话中的对话数组,思路如下:

  1. 设置一个session用于存储会话列表,并存储到缓存

  2. 设置一个index用于存储当前活动的对话序号,并存储到缓存

  3. 当session被新增或删除的时候,更新缓存session

  4. 当inedx被修改的时候,更新缓存的inedx

效果图

从下图可以看出,多个会话之间并没有影响,最终效果与预期一致(手机端的图片太长了,因此我在电脑上重新截取了一遍,这样看起来相对整齐一些)。

69bd15aa2d69447e861d14b86875d680~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCW5qSS5Zyf6LGGc3Nz_q75.webp

69bd15aa2d69447e861d14b86875d680~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCW5qSS5Zyf6LGGc3Nz_q75.webp

69bd15aa2d69447e861d14b86875d680~tplv-73owjymdk6-jj-mark-v1_0_0_0_0_5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5bCW5qSS5Zyf6LGGc3Nz_q75.webp