在Spring Boot项目中接入DeepSeek深度求索,感觉笨笨的呢

文章目录

    • 引言
    • 1. 什么是DeepSeek?
    • 2. 准备工作
      • 2.1 注册DeepSeek账号
    • 3.实战演示
      • 3.1 application增加DS配置
      • 3.2 编写service
      • 3.3 编写controller
      • 3.4 编写前端界面chat.html
      • 3.5 测试
    • 总结

引言

在当今快速发展的数据驱动时代,企业越来越重视数据的价值。为了更好地理解和利用数据,许多公司开始采用先进的数据分析和搜索技术。DeepSeek(深度求索)就是一款强大的深度学习驱动的搜索和推荐系统,可以帮助企业高效地处理和分析大规模数据。本文将详细介绍如何在Spring Boot项目中接入DeepSeek,帮助各位大大快速上手并利用其强大的功能。
在这里插入图片描述

1. 什么是DeepSeek?

DeepSeek 是一款基于深度学习的搜索和推荐系统,能够帮助企业从海量数据中快速提取有价值的信息。它结合了自然语言处理(NLP)、机器学习和深度学习技术,提供精准的搜索结果和个性化推荐。DeepSeek的主要特点包括:
精准搜索:通过深度学习算法,DeepSeek能够理解用户查询的意图,提供更精准的搜索结果。
个性化推荐:基于用户行为和偏好,DeepSeek能够为用户提供个性化的推荐内容。
高效处理:支持大规模数据处理,能够快速响应用户请求。
易于集成:提供丰富的API接口,方便与其他系统集成。

2. 准备工作

在开始接入DeepSeek之前,需要完成以下准备工作:

2.1 注册DeepSeek账号

首先,访问DeepSeek的API开放平台( https://platform.deepseek.com/sign_in),注册一个账号。注册完成后,登录账号并创建一个新的项目,获取项目ID和API密钥。
在这里插入图片描述

注意:生成key后需要充值后才能正常调用其API。

3.实战演示

3.1 application增加DS配置

ds:key: 填写在官网申请的keyurl: https://api.deepseek.com/chat/completions

3.2 编写service

/*** DsChatService* @author senfel* @version 1.0* @date 2025/3/13 17:30*/
public interface DsChatService {/*** chat* @param userId* @param question* @author senfel* @date 2025/3/13 17:30* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/SseEmitter chat(String userId,String question);
}
/*** DsChatServiceImpl* @author senfel* @version 1.0* @date 2025/3/13 17:31*/
@Service
@Slf4j
public class DsChatServiceImpl implements DsChatService {@Value("${ds.key}")private String dsKey;@Value("${ds.url}")private String dsUrl;// 用于保存每个用户的对话历史private final Map<String, List<Map<String, String>>> sessionHistory = new ConcurrentHashMap<>();private final ExecutorService executorService = Executors.newCachedThreadPool();private final ObjectMapper objectMapper = new ObjectMapper();/*** chat* @param userId* @param question* @author senfel* @date 2025/3/13 17:36* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/@Overridepublic SseEmitter chat(String userId,String question) {SseEmitter emitter = new SseEmitter(-1L);executorService.execute(() -> {try {log.info("流式回答开始, 问题: {}", question);// 获取当前用户的对话历史List<Map<String, String>> messages = sessionHistory.getOrDefault(userId, new ArrayList<>());// 添加用户的新问题到对话历史Map<String, String> userMessage = new HashMap<>();userMessage.put("role", "user");userMessage.put("content", question);Map<String, String> systemMessage = new HashMap<>();systemMessage.put("role", "system");systemMessage.put("content", "senfel的AI助手");messages.add(userMessage);messages.add(systemMessage);// 调用 DeepSeek APItry (CloseableHttpClient client = HttpClients.createDefault()) {HttpPost request = new HttpPost(dsUrl);request.setHeader("Content-Type", "application/json");request.setHeader("Authorization", "Bearer " + dsKey);Map<String, Object> requestMap = new HashMap<>();requestMap.put("model", "deepseek-chat");requestMap.put("messages", messages);requestMap.put("stream", true);String requestBody = objectMapper.writeValueAsString(requestMap);request.setEntity(new StringEntity(requestBody, StandardCharsets.UTF_8));try (CloseableHttpResponse response = client.execute(request);BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8))) {StringBuilder aiResponse = new StringBuilder();String line;while ((line = reader.readLine()) != null) {if (line.startsWith("data: ")) {System.err.println(line);String jsonData = line.substring(6);if ("[DONE]".equals(jsonData)) {break;}JsonNode node = objectMapper.readTree(jsonData);String content = node.path("choices").path(0).path("delta").path("content").asText("");if (!content.isEmpty()) {emitter.send(content);aiResponse.append(content); // 收集 AI 的回复}}}// 将 AI 的回复添加到对话历史Map<String, String> aiMessage = new HashMap<>();aiMessage.put("role", "assistant");aiMessage.put("content", aiResponse.toString());messages.add(aiMessage);// 更新会话状态sessionHistory.put(userId, messages);log.info("流式回答结束, 问题: {}", question);emitter.complete();}} catch (Exception e) {log.error("处理 DeepSeek 请求时发生错误", e);emitter.completeWithError(e);}} catch (Exception e) {log.error("处理 DeepSeek 请求时发生错误", e);emitter.completeWithError(e);}});return emitter;}}

3.3 编写controller

/*** DsController* @author senfel* @version 1.0* @date 2025/3/13 17:21*/
@RestController
@RequestMapping("/deepSeek")
@Slf4j
public class DsController {@Resourceprivate DsChatService dsChatService;/*** chat page* @param modelAndView* @author senfel* @date 2025/3/13 17:39* @return org.springframework.web.servlet.ModelAndView*/@GetMapping()public ModelAndView chat(ModelAndView modelAndView) {modelAndView.setViewName("chat");return modelAndView;}/*** chat* @param question* @author senfel* @date 2025/3/13 17:39* @return org.springframework.web.servlet.mvc.method.annotation.SseEmitter*/@PostMapping(value = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter chat(@RequestBody String question) {//TODO 默认用户ID,实际场景从token获取String userId = "senfel";return dsChatService.chat(userId, question);}
}

3.4 编写前端界面chat.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>DeepSeek Chat</title><script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script><style>:root {--primary-color: #5b8cff;--user-bg: linear-gradient(135deg, #5b8cff 0%, #3d6ef7 100%);--bot-bg: linear-gradient(135deg, #f0f8ff 0%, #e6f3ff 100%);--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);}body {font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;margin: 0;padding: 20px;display: flex;justify-content: center;min-height: 100vh;background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);}.chat-container {width: 100%;max-width: 800px;height: 90vh;background: rgba(255, 255, 255, 0.95);border-radius: 20px;box-shadow: var(--shadow);backdrop-filter: blur(10px);display: flex;flex-direction: column;overflow: hidden;}.chat-header {padding: 24px;background: var(--primary-color);color: white;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);}.chat-header h1 {margin: 0;font-size: 1.8rem;font-weight: 600;letter-spacing: -0.5px;}.chat-messages {flex: 1;padding: 20px;overflow-y: auto;display: flex;flex-direction: column;gap: 12px;}.chat-message {max-width: 75%;padding: 16px 20px;border-radius: 20px;line-height: 1.5;animation: messageAppear 0.3s ease-out;position: relative;word-break: break-word;}.chat-message.user {background: var(--user-bg);color: white;align-self: flex-end;border-bottom-right-radius: 4px;box-shadow: var(--shadow);}.chat-message.bot {background: var(--bot-bg);color: #2d3748;align-self: flex-start;border-bottom-left-radius: 4px;box-shadow: var(--shadow);}.chat-input {padding: 20px;background: rgba(255, 255, 255, 0.9);border-top: 1px solid rgba(0, 0, 0, 0.05);display: flex;gap: 12px;}.chat-input input {flex: 1;padding: 14px 20px;border: 2px solid rgba(0, 0, 0, 0.1);border-radius: 16px;font-size: 1rem;transition: all 0.2s ease;background: rgba(255, 255, 255, 0.8);}.chat-input input:focus {outline: none;border-color: var(--primary-color);box-shadow: 0 0 0 3px rgba(91, 140, 255, 0.2);}.chat-input button {padding: 12px 24px;border: none;border-radius: 16px;background: var(--primary-color);color: white;font-size: 1rem;font-weight: 500;cursor: pointer;transition: all 0.2s ease;display: flex;align-items: center;gap: 8px;}.chat-input button:hover {background: #406cff;transform: translateY(-1px);}.chat-input button:disabled {background: #c2d1ff;cursor: not-allowed;transform: none;}.chat-input button svg {width: 18px;height: 18px;fill: currentColor;}@keyframes messageAppear {from {opacity: 0;transform: translateY(10px);}to {opacity: 1;transform: translateY(0);}}.typing-indicator {display: inline-flex;gap: 6px;padding: 12px 20px;background: var(--bot-bg);border-radius: 20px;align-self: flex-start;}.typing-dot {width: 8px;height: 8px;background: rgba(0, 0, 0, 0.3);border-radius: 50%;animation: typing 1.4s infinite ease-in-out;}.typing-dot:nth-child(2) {animation-delay: 0.2s;}.typing-dot:nth-child(3) {animation-delay: 0.4s;}@keyframes typing {0%,100% {transform: translateY(0);}50% {transform: translateY(-4px);}}@media (max-width: 640px) {body {padding: 10px;}.chat-container {height: 95vh;border-radius: 16px;}.chat-message {max-width: 85%;}}</style>
</head>
<body>
<div class="chat-container"><div class="chat-header"><h1>DeepSeek Chat</h1></div><div class="chat-messages" id="chatMessages"></div><div class="chat-input"><input type="text" id="questionInput" placeholder="输入消息..." onkeydown="handleKeyDown(event)"><button id="sendButton" disabled><svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z" /></svg>发送</button></div>
</div>
<script>const questionInput = document.getElementById('questionInput');const sendButton = document.getElementById('sendButton');const chatMessages = document.getElementById('chatMessages');let isBotResponding = false;// 输入验证questionInput.addEventListener('input', () => {sendButton.disabled = questionInput.value.trim().length === 0;});// 回车发送function handleKeyDown(e) {if (e.key === 'Enter' && !sendButton.disabled && !isBotResponding) {sendButton.click();}}// 修改后的消息处理逻辑let currentBotMessage = null; // 当前正在更新的AI消息async function handleBotResponse(response) {const reader = response.body.getReader();const decoder = new TextDecoder();let buffer = '';currentBotMessage = displayMessage('bot', '');try {while (true) {const { done, value } = await reader.read();if (done) {// 处理最后剩余的数据if (buffer) processLine(buffer);break;}buffer += decoder.decode(value, { stream: true });const lines = buffer.split('\n');// 保留未完成的行在缓冲区buffer = lines.pop() || '';lines.forEach(line => {if (line.startsWith('data:')) {const data = line.replace(/^data:\s*/g, '').trim();if (data === '[DONE]') return;currentBotMessage.textContent += data;}});chatMessages.scrollTop = chatMessages.scrollHeight;}} finally {currentBotMessage = null;}}// 发送逻辑sendButton.addEventListener('click', async () => {if (isBotResponding) return;const question = questionInput.value.trim();if (!question) return;questionInput.value = '';sendButton.disabled = true;isBotResponding = true;// 显示用户消息(新消息始终出现在下方)displayMessage('user', question);try {// 显示加载状态const typingIndicator = createTypingIndicator();const response = await fetch('/deepSeek/chat', {method: 'POST',headers: {'Content-Type': 'application/json','Accept': 'text/event-stream'},body: JSON.stringify({ question }),});typingIndicator.remove();await handleBotResponse(response); // 处理流式响应} catch (error) {displayMessage('bot', '暂时无法处理您的请求,请稍后再试');} finally {isBotResponding = false;questionInput.focus();}});// 创建消息元素function displayMessage(sender, content) {const messageDiv = document.createElement('div');messageDiv.className = `chat-message ${sender}`;messageDiv.textContent = content;chatMessages.appendChild(messageDiv);chatMessages.scrollTop = chatMessages.scrollHeight;return messageDiv;}// 创建输入指示器function createTypingIndicator() {const container = document.createElement('div');container.className = 'typing-indicator';container.innerHTML = `<div class="typing-dot"></div><div class="typing-dot"></div><div class="typing-dot"></div>`;chatMessages.appendChild(container);chatMessages.scrollTop = chatMessages.scrollHeight;return container;}
</script>
</body>
</html>

3.5 测试

  • 启动项目,访问 http://localhost:9999/deepSeek 即可出现页面,开始对话即可
    在这里插入图片描述

总结

通过本文,我们详细介绍了如何在Spring Boot项目中接入DeepSeek深度求索。从准备工作到实现搜索和推荐功能,再到处理异常,我们一步一步地完成了整个接入过程。希望本文能够帮助您快速上手并充分利用DeepSeek的强大功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34834.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据分析】读取文件

3. 读取指定列 针对只需要读取数据中的某一列或多列的情况&#xff0c;pd.read_csv()函数提供了一个参数&#xff1a;usecols&#xff0c;将包含对应的columns的列表传入该参数即可。 上面&#xff0c;我们学习了读取 "payment" 和 "items_count" 这…

Ubuntu 优化 Vim 指南

Vim 是一款功能强大的文本编辑器&#xff0c;通过合适的配置&#xff0c;可以变成一个接近 IDE 的高效开发工具。本指南提供 最精简、最实用 的 Vim 配置&#xff0c;满足 代码补全、语法高亮、代码格式化、目录管理等常用需求。 1. 必须安装的软件 首先&#xff0c;确保你的系…

信创环境下TOP5甘特图工具对比:从功能到适配性测评

在数字化转型的浪潮中&#xff0c;项目管理的高效与否直接决定了企业能否在激烈的市场竞争中脱颖而出。而甘特图作为项目管理中不可或缺的工具&#xff0c;其重要性不言而喻。尤其是在信创环境日益受到重视的当下&#xff0c;选择一款适配性强、功能完备的甘特图工具&#xff0…

MinIO的预签名直传机制

我们传统使用MinIo做OSS对象存储的应用方式往往都是在后端配置与MinIO的连接和文件上传下载的相关接口&#xff0c;然后我们在前端调用这些接口完成文件的上传下载机制&#xff0c;但是&#xff0c;当并发量过大&#xff0c;频繁访问会对后端的并发往往会对服务器造成极大的压力…

【NLP 38、实践 ⑩ NER 命名实体识别任务 Bert 实现】

去做具体的事&#xff0c;然后稳稳托举自己 —— 25.3.17 数据文件&#xff1a; 通过网盘分享的文件&#xff1a;Ner命名实体识别任务 链接: https://pan.baidu.com/s/1fUiin2um4PCS5i91V9dJFA?pwdyc6u 提取码: yc6u --来自百度网盘超级会员v3的分享 一、配置文件 config.py …

Windows下安装MongoDB 8

在Windows下安装MongoDB&#xff0c;首先需要确定自己的Windows系统版本以及MongoDB社区版所能支持的系统版本。这里使用的是Windows 10操作系统和MongoDB 8.0.4版本。由于MongoDB 6版本之后&#xff0c;不再默认安装Mongo Shell&#xff0c;所以本节分为两部分&#xff1a;安装…

【Node.js入门笔记4---fs 目录操作】

Node.js入门笔记4 Node.js---fs 目录操作一、目录操作1.fs.mkdir()&#xff1a;创建目录。异步&#xff0c;非阻塞。创建单个目录创建多个目录创建目前之前需要确认是否存在&#xff1a; 2. fs.mkdirSync()&#xff1a;用于创建一个新的目录。异步&#xff0c;非阻塞。3.fs.rmd…

DeepSeek-R1思路训练多模态大模型-Vision-R1开源及实现方法思路

刚开始琢磨使用DeepSeek-R1风格训练多模态R1模型&#xff0c;就看到这个工作&#xff0c;本文一起看看&#xff0c;供参考。 先提出问题&#xff0c;仅靠 RL 是否足以激励 MLLM 的推理能力&#xff1f; 结论&#xff1a;不能&#xff0c;因为如果 RL 能有效激励推理能力&#…

Python学习第十八天

Django模型 定义&#xff1a;模型是 Django 中用于定义数据库结构的 Python 类。每个模型类对应数据库中的一张表&#xff0c;类的属性对应表的字段。 作用&#xff1a;通过模型&#xff0c;Django 可以将 Python 代码与数据库表结构关联起来&#xff0c;开发者无需直接编写 S…

总结 HTTP 协议的基本格式, 相关知识以及抓包工具fiddler的使用

目录 1 HTTP是什么 2 HTTP协议格式 3 HTTP请求(Request) 3.1 认识URL 3.2 方法 3.3 认识请求"报头"(header) 3.3.1 Host 3.3.2 Content-Length 3.3.3 Content-Type 3.3.4 User-Agent (简称UA) 3.3.5 Referer 3.3.6 Cookie和Session 4 HTTP响应详解 4.…

【sql靶场】第15、16关-post提交盲注保姆级教程

目录 【sql靶场】第15、16关-post提交盲注保姆级教程 1.知识回顾 ‌GET请求‌ ‌POST请求‌ or与and 2.第十五关 1.布尔盲注的手动注入 1.判断 2.数据库名长度 3.数据库名字符 4.表名数 5.表名长度 6.表名符 7.字段数 8.字段长度 9.字段符 2.布尔盲注的脚本注入…

【C++】 —— 笔试刷题day_6

刷题day_6&#xff0c;继续加油哇&#xff01; 今天这三道题全是高精度算法 一、大数加法 题目链接&#xff1a;大数加法 题目解析与解题思路 OK&#xff0c;这道题题目描述很简单&#xff0c;就是给我们两个字符串形式的数字&#xff0c;让我们计算这两个数字的和 看题目我…

redis终章

1. 缓存(cache) Redis最主要的用途&#xff0c;三个方面1.存储数据&#xff08;内存数据库&#xff09;&#xff1b;2.缓存[redis最常用的场景]&#xff1b;3.消息队列。 缓存(cache)是计算机中的⼀个经典的概念.核⼼思路就是把⼀些常⽤的数据放到触⼿可及(访问速度更快)的地⽅…

Matlab 多输入系统极点配置

1、内容简介 略 Matlab 172-多输入系统极点配置 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 clc close all clear A [-6.5727 1.1902 0 -53.4085;1.1902 -6.5727 0 -53.4085;0.5294 0.5294 0 17.7502;0 0 1 0]; B [1.3797 -0.2498;-0.2498 1.3797;-0.1111 -0.1…

国产编辑器EverEdit - 脚本(解锁文本编辑的无限可能)

1 脚本 1.1 应用场景 脚本是一种功能扩展代码&#xff0c;用于提供一些编辑器通用功能提供不了的功能&#xff0c;帮助用户在特定工作场景下提高工作效率&#xff0c;几乎所有主流的编辑器、IDE都支持脚本。   EverEdit的脚本支持js(语法与javascript类似)、VBScript两种编程…

Flutter 小技巧之通过 MediaQuery 优化 App 性能

许久没更新小技巧系列&#xff0c;温故知新&#xff0c;在两年半前的《 MediaQuery 和 build 优化你不知道的秘密》 我们聊过了在 Flutter 内 MediaQuery 对应 rebuild 机制&#xff0c;由于 MediaQuery 在 MaterialApp 内&#xff0c;并且还是一个 InheritedWidget &#xff0…

AI-医学影像分割方法与流程

AI医学影像分割方法与流程–基于低场磁共振影像的病灶识别 – 作者:coder_fang AI框架&#xff1a;PaddleSeg 数据准备&#xff0c;使用MedicalLabelMe进行dcm文件标注&#xff0c;产生同名.json文件。 编写程序生成训练集图片&#xff0c;包括掩码图。 代码如下: def doC…

【蓝桥杯每日一题】3.16

&#x1f3dd;️专栏&#xff1a; 【蓝桥杯备篇】 &#x1f305;主页&#xff1a; f狐o狸x 目录 3.9 高精度算法 一、高精度加法 题目链接&#xff1a; 题目描述&#xff1a; 解题思路&#xff1a; 解题代码&#xff1a; 二、高精度减法 题目链接&#xff1a; 题目描述&…

人工智能组第一次培训——deepseek本地部署和知识库的建立

deepseek本地部署的用处 减少对网络依赖性&#xff1a; 在断网环境下&#xff0c;依然可以使用预先下载的AI模型进行处理&#xff0c;避免因网络不稳定而无法完成任务。 提高响应速度&#xff1a; 数据和模型已经在本地设备上准备好&#xff0c;可以直接调用&#xff0c;不…

windows协议不再续签,华为再无windows可用,将于四月发布鸿蒙PC

大家好&#xff0c;我是国货系创始人张云泽&#xff0c;最近不少小伙伴在后台问&#xff1a;“听说Windows协议要到期了&#xff1f;我的电脑会不会变砖&#xff1f;”还有人说&#xff1a;“华为笔记本以后用不了Windows了&#xff1f;鸿蒙系统能用吗&#xff1f;”今天咱们就…