在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.mzph.cn/bicheng/73771.shtml

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

相关文章

Cursor在内网环境配置自定义DeepSeek API

关键字 Cursor、DeepSeek、API配置、内网代理、HTTP/2 背景环境 使用Cursor集成环境开发程序。但是我使用公司的内网并不能使用cursor自带的模型&#xff0c;于是我就想使用DeepSeek官方的API服务。 环境&#xff1a;Windows 11系统 解决过程 网络检测 首先进行环境检测&am…

RabbitMQ 集群降配

这里写自定义目录标题 摘要检查状态1. 检查 RabbitMQ 服务状态2. 检查 RabbitMQ 端口监听3. 检查 RabbitMQ 管理插件是否启用4. 检查开机自启状态5. 确认集群高可用性6. 检查使用该集群的服务是否做了断开重连 实操1. 负载均衡配置2. 逐个节点降配&#xff08;滚动操作&#xf…

设计模式之外观模式:原理、实现与应用

引言 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过提供一个统一的接口来简化复杂系统的使用。外观模式隐藏了系统的复杂性&#xff0c;使得客户端可以通过一个简单的接口与系统交互。本文将深入探讨外观模式的原理、实现方式以及实…

进行交通流预测,使用KAN+Transformer模型

理论基础 KAN&#xff08;Knowledge Augmented Network&#xff09; KAN 是一种知识增强网络&#xff0c;其核心思想是将先验知识融入到神经网络中&#xff0c;以此提升模型的性能与泛化能力。在交通流预测领域&#xff0c;先验知识可以是交通规则、历史交通模式等。通过把这…

TF中 Arg 节点

TF中 Arg 节点 在 TensorFlow 的计算图中&#xff0c;_Arg 节点&#xff08;Argument Node&#xff09;表示函数的输入参数&#xff0c;是计算图中负责接收外部输入数据的节点。它的名字来源于“Argument”&#xff08;参数&#xff09;&#xff0c;直接对应函数调用时传入的张…

Educational Codeforces Round 176 (Rated for Div. 2)

A.To Zero 签到题 void solve() { int n,k;cin>>n>>k;int k2k/2*2;int k1(k2<k)?k:k-1;int cnt0;if(n%21){n-k1;cnt;cnt(n/k2)(n%k2!0);}else {cnt(n/k2)(n%k2!0);}cout<<cnt<<endl;}B.Array Recoloring 手推一下可以发现&#xff0c;答案其实就…

Kubernetes的Service详解

一、Service介绍 在 kubernetes 中&#xff0c; pod 是应用程序的载体&#xff0c;我们可以通过 pod 的 ip 来访问应用程序&#xff0c;但是 pod 的 ip 地址不是固定的&#xff0c;这也就意味着不方便直接采用pod 的 ip 对服务进行访问。 为了解决这个问题&#xff0c;kuberne…

基于Nvidia Jetson Nano边缘计算设备使用TensorRT部署YOLOv8模型实现目标检测推理

0、背景 最近拿到一台边缘计算设备&#xff0c;在部署YOLO模型的过程中遇到一些问题&#xff0c;特此记录。 设备介绍信息&#xff1a;NVIDIA Jetson Orin Nano T201Developer Kit 开发套件 开发者套件&#xff1a;Jetson Orin Nano T201 8GB开发套件 使用指南文档&#x…

让人感到疑惑的const

const 关键字在不同的编程语言中有着不同的含义和限制&#xff0c;但通常它被用来声明一个常量或只读变量。然而&#xff0c;在 JavaScript 中&#xff0c;const 的行为有时可能会让人感到困惑&#xff0c;因为它并不总是意味着“不可变”&#xff08;immutable&#xff09;。让…

Python 列表全面解析

关于Python列表的详细教程&#xff0c;涵盖增删改查、切片、列表推导式及核心方法 一、 列表基础 1.1 创建列表 列表是Python中最常用的数据结构之一&#xff0c;支持动态存储多种类型的元素。 # 空列表 empty_list []# 初始化列表 numbers [1, 2, 3, 4] fruits ["a…

【Ratis】ReferenceCountedObject接口的作用及参考意义

Apache Ratis的项目源码里,大量用到了自定义的ReferenceCountedObject接口。 本文就来学习一下这个接口的作用,并借鉴一下它解决的问题和实现原理。 功能与作用 ReferenceCountedObject 是一个接口,用于管理对象的引用计数。它的主要功能和作用包括: 引用计数管理: 提供…

leetcode-50.Pow(x,n)

快速计算次方的方法。 首先&#xff0c;先保证n是正数。 如果n<0&#xff0c;就让x取反&#xff0c;n取绝对值。 然后考虑怎么快速乘法。 考虑 x 7 x 1 2 4 x ∗ x 2 ∗ x 4 x^7x^{124}x*x^2*x^4 x7x124x∗x2∗x4&#xff0c;可以发现&#xff0c;本来乘6次x&#xff0…

基于javaweb的SpringBoot公司日常考勤系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

游戏引擎学习第167天

回顾和今天的计划 我们不使用引擎&#xff0c;也不依赖库&#xff0c;只有我们自己和我们的小手指在敲击代码。 今天我们会继续进行一些工作。首先&#xff0c;我们会清理昨天留下的一些问题&#xff0c;这些问题我们当时没有深入探讨。除了这些&#xff0c;我觉得我们在资产…

深度学习框架PyTorch——从入门到精通(5)自动微分

使用torch.autograd自动微分 张量、函数和计算图计算梯度禁用梯度追踪关于计算图的更多信息张量梯度和雅可比乘积 在训练神经网络时&#xff0c;最常用的算法是反向传播。在该算法中&#xff0c;参数&#xff08;模型权重&#xff09;根据损失函数的梯度相对于给定参数进行调整…

以食为药:缓解老人手抖的饮食策略

手抖&#xff0c;在医学上称为震颤&#xff0c;是老年人常见的症状之一。其成因复杂&#xff0c;可能涉及神经系统病变、甲状腺功能异常、药物副作用等。除了积极就医治疗&#xff0c;合理的饮食对于缓解手抖症状、提高老人生活质量具有重要意义。 老人手抖时&#xff0c;身体能…

JUC大揭秘:从ConcurrentHashMap到线程池,玩转Java并发编程!

目录 JUC实现类 ConcurrentHashMap 回顾HashMap ConcurrentHashMap CopyOnWriteArrayList 回顾ArrayList CopyOnWriteArrayList: CopyOnWriteArraySet 辅助类 CountDownLatch 线程池 线程池 线程池优点 ThreadPoolExecutor 构造器各个参数含义&#xff1a; 线程…

C++之list类及模拟实现

目录 list的介绍 list的模拟实现 定义节点 有关遍历的重载运算符 list的操作实现 &#xff08;1&#xff09;构造函数 (2)拷贝构造函数 &#xff08;3&#xff09;赋值运算符重载函数 &#xff08;4&#xff09;析构函数和clear成员函数 &#xff08;5&#xff09;尾…

Elasticsearch 向量检索详解

文章目录 1、向量检索的用途2、适用场景2.1 自然语言处理&#xff08;NLP&#xff09;&#xff1a;2.2 图像搜索&#xff1a;2.3 推荐系统2.4 音视频搜索 3、向量检索的核心概念3.1 向量3.2 相似度计算3.3 向量索引 4、案例&#xff1a;基于文本的语义搜索5、总结 向量检索是 E…

自学软硬件第755 docker容器虚拟化技术

见字如面&#xff0c; 这里是AIGC创意人_竹相左边&#xff0c; 正在通过AI自学软硬件工程师&#xff0c;目标手搓可回收火箭玩具。 我很喜欢 《流浪地球 2》中 &#xff0c;马兆&#xff1a;没有硬件支撑&#xff0c;你破解个屁。 写作背景 今天在剪视频&#xff0c;然后看…