当前位置: 首页 > news >正文

springboot整合阿里云百炼DeepSeek,实现sse流式打印

1.开通阿里云百炼,获取到key

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
官方文档地址
https://bailian.console.aliyun.com/?tab=api#/api/?type=model&url=https%3A%2F%2Fhelp.aliyun.com%2Fdocument_detail%2F2868565.html

2.新建SpringBoot项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>devicewx-ai</groupId><artifactId>devicewx-ai</artifactId><version>1.0-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.15</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--阿里云deepseek--><!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --><dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.18.3</version></dependency><!-- 集成redis依赖  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.16</version></dependency></dependencies></project>

3.工具类

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** redis工具类* @Author: albc* @Date: 2024/07/17/15:31* @Description: good good study,day day up*/
@Component
public class RedisUtil {@Resourceprivate RedisTemplate<String, Object> redisTemplate;// =============================common============================/*** 指定缓存失效时间** @param key  键* @param time 时间(秒)*/public boolean expire(String key, long time) {try {if (time > 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据key 获取过期时间** @param key 键 不能为null* @return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在** @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存** @param key 可以传一个值 或多个*/@SuppressWarnings("unchecked")public void del(String... key) {if (key != null && key.length > 0) {if (key.length == 1) {redisTemplate.delete(key[0]);} else {//redisTemplate.delete(CollectionUtils.arrayToList(key));}}}// ============================String=============================/*** 普通缓存获取** @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入** @param key   键* @param value 值* @return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间** @param key   键* @param value 值* @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期* @return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time > 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增** @param key   键* @param delta 要增加几(大于0)*/public long incr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递增因子必须大于0");}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减** @param key   键* @param delta 要减少几(小于0)*/public long decr(String key, long delta) {if (delta < 0) {throw new RuntimeException("递减因子必须大于0");}return redisTemplate.opsForValue().increment(key, -delta);}// ================================Map=================================/*** HashGet** @param key  键 不能为null* @param item 项 不能为null*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 获取hashKey对应的所有键值** @param key 键* @return 对应的多个键值*/public Map<Object, Object> hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet** @param key 键* @param map 对应多个键值*/public boolean hmset(String key, Map<String, Object> map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间** @param key  键* @param map  对应多个键值* @param time 时间(秒)* @return true成功 false失败*/public boolean hmset(String key, Map<String, Object> map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** @param key   键* @param item  项* @param value 值* @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间* @return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值** @param key  键 不能为null* @param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}/*** 判断hash表中是否有该项的值** @param key  键 不能为null* @param item 项 不能为null* @return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/*** hash递增 如果不存在,就会创建一个 并把新增后的值返回** @param key  键* @param item 项* @param by   要增加几(大于0)*/public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);}/*** hash递减** @param key  键* @param item 项* @param by   要减少记(小于0)*/public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);}// ============================set=============================/*** 根据key获取Set中的所有值** @param key 键*/public Set<Object> sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据value从一个set中查询,是否存在** @param key   键* @param value 值* @return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/*** 将数据放入set缓存** @param key    键* @param values 值 可以是多个* @return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将set数据放入缓存** @param key    键* @param time   时间(秒)* @param values 值 可以是多个* @return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count = redisTemplate.opsForSet().add(key, values);if (time > 0) {expire(key, time);}return count;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度** @param key 键*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的** @param key    键* @param values 值 可以是多个* @return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count = redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}// ===============================list=================================/*** 获取list缓存的内容** @param key   键* @param start 开始* @param end   结束 0 到 -1代表所有值*/public List<Object> lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 获取第一个元素并弹出** @param key key* @return 第一个元素*/public Object lPop(String key) {try {return redisTemplate.opsForList().leftPop(key);} catch (Exception e) {return null;}}/*** 阻塞时间获取* @param key* @param timeout 秒* @return*/public Object lPop(String key,long timeout) {try {return redisTemplate.opsForList().leftPop(key,timeout,TimeUnit.SECONDS);} catch (Exception e) {return null;}}/*** 获取list缓存的长度** @param key 键*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过索引 获取list中的值** @param key   键* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存** @param key   键* @param value 值*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @param time  时间(秒)*/public boolean lSet(String key, Object value, long time) {try {redisTemplate.opsForList().rightPush(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @return*/public boolean lSet(String key, List<Object> value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** @param key   键* @param value 值* @param time  时间(秒)* @return*/public boolean lSet(String key, List<Object> value, long time) {try {redisTemplate.opsForList().rightPushAll(key, value);if (time > 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据索引修改list中的某条数据** @param key   键* @param index 索引* @param value 值* @return*/public boolean lUpdateIndex(String key, long index, Object value) {try {redisTemplate.opsForList().set(key, index, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 移除N个值为value** @param key   键* @param count 移除多少个* @param value 值* @return 移除的个数*/public long lRemove(String key, long count, Object value) {try {Long remove = redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {e.printStackTrace();return 0;}}}

3.启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** @Author: albc* @Date: 2025/04/17/10:03* @Description: good good study,day day up*/
@SpringBootApplication
public class AiApplication {public static void main(String[] args) {SpringApplication.run(AiApplication.class,args);System.out.println("启动成功");}
}

4.测试类


import lombok.Data;/*** @Author: albc* @Date: 2025/04/17/10:12* @Description: good good study,day day up*/
@Data
public class TestDto {private String content;}

5.测试方法


import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.atkj.dto.TestDto;
import com.atkj.util.RedisUtil;
import io.reactivex.Flowable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;/*** @Author: albc* @Date: 2025/04/17/10:02* @Description: good good study,day day up*/
@RequestMapping("/test")
@RestController
public class TestController {/*** 问题分析*/private static StringBuilder reasoningContent = new StringBuilder();/*** 完整回复*/private static StringBuilder finalContent = new StringBuilder();private static boolean isFirstPrint = true;@Autowiredprivate RedisUtil redisUtil;@PostMapping("/testRdisListSet")public String testRdisList(){return "Ai测试方法";}@PostMapping("/testAi")@ResponseBodypublic void testAi(HttpServletResponse httpServletResponse,@RequestBody TestDto testDto){//正式版本自定义线程池,禁止创建线程new Thread(()->{try {String content = testDto.getContent();Generation gen = new Generation();Message userMsg = Message.builder().role(Role.USER.getValue()).content(content).build();streamCallWithMessage(gen, userMsg);
//             打印最终结果
//            if (reasoningContent.length() > 0) {
//                System.out.println("\n====================完整回复====================");
//                System.out.println(finalContent.toString());
//            }} catch (ApiException | NoApiKeyException | InputRequiredException e) {System.out.println("An exception occurred:"+e.getMessage());}}).start();httpServletResponse.setContentType("text/event-stream");httpServletResponse.setCharacterEncoding("utf-8");SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String s = "";while (true) {Object deep = redisUtil.lPop("deep",5);if (deep == null){break;}s = "data: " + deep + "\n\n";try {PrintWriter pw = httpServletResponse.getWriter();Thread.sleep(10L);pw.write(s);pw.flush();} catch (IOException | InterruptedException e) {e.printStackTrace();}}}private void handleGenerationResult(GenerationResult message) {String reasoning = message.getOutput().getChoices().get(0).getMessage().getReasoningContent();String content = message.getOutput().getChoices().get(0).getMessage().getContent();if (!reasoning.isEmpty()) {// reasoningContent.append(reasoning);if (isFirstPrint) {System.out.println("====================思考过程====================");isFirstPrint = false;}redisUtil.lSet("deep", reasoning);System.out.print(reasoning);}if (!content.isEmpty()) {//finalContent.append(content);if (!isFirstPrint) {System.out.println("\n====================完整回复====================");isFirstPrint = true;}redisUtil.lSet("deep", content);System.out.print(content);}}private static GenerationParam buildGenerationParam(Message userMsg) {return GenerationParam.builder()// 若没有配置环境变量,请用百炼API Key将下行替换为:.apiKey("sk-xxx") //qwen-plus,deepseek-r1.apiKey("sk-123123123123123123123123123123123").model("deepseek-r1").messages(Arrays.asList(userMsg))// 不可以设置为"text".resultFormat(GenerationParam.ResultFormat.MESSAGE).incrementalOutput(true).build();}public void streamCallWithMessage(Generation gen, Message userMsg)throws NoApiKeyException, ApiException, InputRequiredException {GenerationParam param = buildGenerationParam(userMsg);Flowable<GenerationResult> result = gen.streamCall(param);result.blockingForEach(message -> handleGenerationResult(message));}
}

6.配置文件

server:port: 18868
spring:redis:host: 192.168.11.198port: 7366password: 123321database: 0

7.测试结果

http://127.0.0.1:18868/test/testAi

在这里插入图片描述

相关文章:

  • Modbus TCP转Profibus DP主站网关:跨协议集成的核心枢纽
  • HTTP/1.1 对头堵塞问题
  • JMeter中设置HTTPS请求
  • MySQL游标(cursor)详解
  • 3 提示词工程指南-提示词编辑 - 持续更新
  • LWIP_MQTT连接ONENET
  • Java 中常用队列用法详解
  • OpenGL shader开发实战学习笔记:第十一章 立方体贴图和天空盒
  • 计算机网络基础概论
  • Linux中docker容器拉取镜像失败解决方案
  • HCIP(OSPF )(2)
  • 第一篇:linux之虚拟环境与centos安装
  • 在ubuntu20.04上安装ros2
  • 【软考-系统架构设计师】OSI体系解析
  • 远程医疗系统安全升级:构建抗CC攻击的全方位防护网
  • SpringBoot_第十章(启动过程)
  • 代码学习总结(三)
  • 离散化--
  • 金融数据库转型实战读后感
  • 目标检测概述
  • 第十二届警博会在京开幕:12个国家和地区835家企业参展
  • 乌拉圭前总统何塞·穆希卡去世
  • 图讯丨习近平出席中国-拉美和加勒比国家共同体论坛第四届部长级会议开幕式
  • 王毅人民日报撰文:共商发展振兴,共建中拉命运共同体
  • 上海下周最高气温在30℃附近徘徊,夏天越来越近
  • 王毅同巴基斯坦副总理兼外长达尔通电话