SpringBoot接入星火认知大模型

文章目录

  • 准备工作
  • 整体思路
  • 接入大模型
    • 服务端和大模型连接
    • 客户端和服务端的连接
    • 测试

准备工作

  1. 到讯飞星火大模型上根据官方的提示申请tokens
    申请成功后可以获得对应的secret,key还有之前创建的应用的appId,这些就是我们要用到的信息

    在这里插入图片描述

  2. 搭建项目

整体思路

考虑到敏感信息等安全性问题,这里和大模型的交互都放到后端去做。
在这里插入图片描述

客户端,服务端,星火大模型均通过Websocket的方式建立连接,用户询问问题时向SpringBoot服务端发送消息,服务端接收到后,创建与星火大模型的连接,并访问大模型,获取到请求结果后发送给客户端

如果想实现根据上下文问答,就要把历史问题和历史回答结果全部传回大模型服务端

请求参数的构建和响应参数解析参照官方文档Web API文档

接入大模型

服务端和大模型连接

/*** 与大模型建立Socket连接** @author gwj*/
@Slf4j
public class BigModelNew extends WebSocketListener {public static final String appid = "appid";// 对话历史存储集合public static Map<Long,List<RoleContent>> hisMap = new ConcurrentHashMap<>();public static String totalAnswer = ""; // 大模型的答案汇总private static String newAsk = "";public static synchronized void ask(String question) {newAsk = question;}public static final Gson gson = new Gson();// 项目中需要用到的参数private Long userId;private Boolean wsCloseFlag;// 构造函数public BigModelNew(Long userId, Boolean wsCloseFlag) {this.userId = userId;this.wsCloseFlag = wsCloseFlag;}// 由于历史记录最大上线1.2W左右,需要判断是能能加入历史public boolean canAddHistory() {int len = 0;List<RoleContent> list = hisMap.get(userId);for (RoleContent temp : list) {len = len + temp.getContent().length();}if (len > 12000) {list.remove(0);list.remove(1);list.remove(2);list.remove(3);list.remove(4);return false;} else {return true;}}// 线程来发送参数class ModelThread extends Thread {private WebSocket webSocket;private Long userId;public ModelThread(WebSocket webSocket, Long userId) {this.webSocket = webSocket;this.userId = userId;}public void run() {try {JSONObject requestJson = new JSONObject();JSONObject header = new JSONObject();  // header参数header.put("app_id", appid);header.put("uid", userId+UUID.randomUUID().toString().substring(0,16));JSONObject parameter = new JSONObject(); // parameter参数JSONObject chat = new JSONObject();chat.put("domain", "4.0Ultra");chat.put("temperature", 0.5);chat.put("max_tokens", 4096);parameter.put("chat", chat);JSONObject payload = new JSONObject(); // payload参数JSONObject message = new JSONObject();JSONArray text = new JSONArray();// 历史问题获取List<RoleContent> list = hisMap.get(userId);if (list != null && !list.isEmpty()) {//log.info("his:{}",list);for (RoleContent tempRoleContent : list) {text.add(JSON.toJSON(tempRoleContent));}}// 最新问题RoleContent roleContent = new RoleContent();roleContent.setRole("user");roleContent.setContent(newAsk);text.add(JSON.toJSON(roleContent));hisMap.computeIfAbsent(userId, k -> new ArrayList<>());hisMap.get(userId).add(roleContent);message.put("text", text);payload.put("message", message);requestJson.put("header", header);requestJson.put("parameter", parameter);requestJson.put("payload", payload);// System.out.println(requestJson);webSocket.send(requestJson.toString());// 等待服务端返回完毕后关闭while (true) {// System.err.println(wsCloseFlag + "---");Thread.sleep(200);if (wsCloseFlag) {break;}}webSocket.close(1000, "");} catch (Exception e) {log.error("【大模型】发送消息错误,{}",e.getMessage());}}}@Overridepublic void onOpen(WebSocket webSocket, Response response) {super.onOpen(webSocket, response);log.info("上线");ModelThread modelThread = new ModelThread(webSocket,userId);modelThread.start();}@Overridepublic void onMessage(WebSocket webSocket, String text) {JsonParse json = gson.fromJson(text, JsonParse.class);if (json.getHeader().getCode() != 0) {log.error("发生错误,错误码为:{} sid为:{}", json.getHeader().getCode(),json.getHeader().getSid());//System.out.println(json);webSocket.close(1000, "");}List<Text> textList = json.getPayload().getChoices().getText();for (Text temp : textList) {// 向客户端发送回答信息,如有存储问答需求,在此处存储ModelChatEndpoint.sendMsgByUserId(userId,temp.getContent());totalAnswer = totalAnswer + temp.getContent();}if (json.getHeader().getStatus() == 2) {// 可以关闭连接,释放资源if (canAddHistory()) {RoleContent roleContent = new RoleContent();roleContent.setRole("assistant");roleContent.setContent(totalAnswer);hisMap.get(userId).add(roleContent);} else {hisMap.get(userId).remove(0);RoleContent roleContent = new RoleContent();roleContent.setRole("assistant");roleContent.setContent(totalAnswer);hisMap.get(userId).add(roleContent);}//收到响应后让等待的线程停止等待wsCloseFlag = true;}}@Overridepublic void onFailure(WebSocket webSocket, Throwable t, Response response) {super.onFailure(webSocket, t, response);try {if (null != response) {int code = response.code();System.out.println("onFailure code:" + code);System.out.println("onFailure body:" + response.body().string());if (101 != code) {System.out.println("connection failed");System.exit(0);}}} catch (IOException e) {e.printStackTrace();}}// 鉴权方法public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {URL url = new URL(hostUrl);// 时间SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);format.setTimeZone(TimeZone.getTimeZone("GMT"));String date = format.format(new Date());// 拼接String preStr = "host: " + url.getHost() + "\n" + "date: " + date + "\n" + "GET " + url.getPath() + " HTTP/1.1";// System.err.println(preStr);// SHA256加密Mac mac = Mac.getInstance("hmacsha256");SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "hmacsha256");mac.init(spec);byte[] hexDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));// Base64加密String sha = Base64.getEncoder().encodeToString(hexDigits);// System.err.println(sha);// 拼接String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha);// 拼接地址HttpUrl httpUrl = Objects.requireNonNull(HttpUrl.parse("https://" + url.getHost() + url.getPath())).newBuilder().//addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).//addQueryParameter("date", date).//addQueryParameter("host", url.getHost()).//build();return httpUrl.toString();}
}

其中用来接收响应参数相关实体类

@Data
public class JsonParse {Header header;Payload payload;
}
@Data
public class Header {int code;int status;String sid;
}
@Data
public class Payload {Choices choices;
}
@Data
public class Choices {List<Text> text;
}
@Data
public class Text {String role;String content;
}
@Data
public class RoleContent {String role;String content;
}

客户端和服务端的连接

/*** 接收客户端请求** @author gwj* @date 2024/10/29 16:51*/
@ServerEndpoint(value = "/ws/model", configurator = GetUserConfigurator.class)
@Component
@Slf4j
public class ModelChatEndpoint {private static AtomicInteger online = new AtomicInteger(0);private static final ConcurrentHashMap<Long,ModelChatEndpoint> wsMap = new ConcurrentHashMap<>();private static BigModelConfig config;@Resourceprivate BigModelConfig modelConfig;@PostConstructpublic void init() {config = modelConfig;}private Session session;private Long userId;@OnOpenpublic void onOpen(EndpointConfig config, Session session) {String s = config.getUserProperties().get("id").toString();userId = Long.parseLong(s);this.session = session;wsMap.put(userId,this);online.incrementAndGet();log.info("用户{},连接成功,在线人数:{}",userId,online);}@OnClosepublic void onClose() {wsMap.remove(userId);online.incrementAndGet();log.info("{},退出,在线人数:{}",userId,online);}@OnErrorpublic void onError(Session session, Throwable error) {log.error("连接出错,{}", error.getMessage());}@OnMessagepublic void onMessage(String message,Session session) throws Exception {BigModelNew.ask(message);//构建鉴权urlString authUrl = BigModelNew.getAuthUrl(config.getHostUrl(), config.getApiKey(), config.getApiSecret());OkHttpClient client = new OkHttpClient.Builder().build();String url = authUrl.replace("http://", "ws://").replace("https://", "wss://");Request request = new Request.Builder().url(url).build();WebSocket webSocket = client.newWebSocket(request,new BigModelNew(this.userId, false));log.info("收到客户端{}的消息:{}", userId, message);}private void sendMsg(String message) {try {this.session.getBasicRemote().sendText(message);} catch (IOException e) {log.error("客户端{}发送{}失败",userId,message);}}/*** 根据userId向用户发送消息** @param userId 用户id* @param message 消息*/public static void sendMsgByUserId(Long userId,String message) {if (userId != null && wsMap.containsKey(userId)) {wsMap.get(userId).sendMsg(message);}}}

测试

在这里插入图片描述
在这里插入图片描述

这样就简单实现了一个ai问答功能

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

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

相关文章

新老项目不同node版本,使用nvm控制node版本切换(mac、window)

window系统电脑的链接&#xff1a;https://blog.csdn.net/qq_40269801/article/details/136450961 以下是mac版本的操作方式&#xff1a; 1、打开终端 克隆 NVM 仓库&#xff1a; git clone https://github.com/nvm-sh/nvm.git ~/.nvm 2、运行安装脚本&#xff1a; cd ~/.n…

kafka如何获取 topic 主题的列表?

大家好&#xff0c;我是锋哥。今天分享关于【kafka如何获取 topic 主题的列表&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; kafka如何获取 topic 主题的列表&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中&#xff0c;可以…

半参数模型

4. 半参数模型 (Semi-parametric Model) 半参数模型结合了参数化和非参数化的方法。可以在整体上采用线性回归&#xff0c;但在局部允许非线性变化。这样做的目的是在保持模型的线性解释性的同时&#xff0c;捕捉细微的弧度趋势。 例如&#xff0c;可以定义&#xff1a; y …

spring 学习路线梳理(二)注解

1.通过注解的方式创建bean 1.1 定义dao层的接口和实现 public interface ILoginDao {public String login(); }Slf4j Repository public class LoginDaoImpl implements ILoginDao {public LoginDaoImpl(){System.out.println("spring create bean call");}Override…

【创建型】单例模式

单例模式使用的场景&#xff1a;需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即&#xff1a;重量级对象)&#xff0c;但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等) 1. 饿汉式&#xff08;静态常量&#xf…

怎么安装行星减速电机才是正确的

行星减速电机由于其高效、精密的传动能力&#xff0c;广泛应用于自动化设备、机器人、机床以及其他需要精准控制的领域。正确的安装行星减速电机对于确保设备的性能与延长使用寿命至关重要。 一、前期准备 在进行行星减速电机的安装之前&#xff0c;必须做好充分的前期准备工作…

代码随想录算法训练营第三十四天 | 01背包问题 416.分割等和子集

01背包问题—1(dp为二维数组)&#xff1a; 文章链接 题目链接&#xff1a;卡码网 46 思路&#xff1a; 因为有物品和背包容量两个方面&#xff0c;因此我们使用二维数组保存递推的结果 ① dp数组及下标的含义&#xff1a; dp[i][j]&#xff0c;其中 i 是第 i 个物品&#x…

什么品牌的护眼台灯比较好?五款护眼效果比较明显的护眼台灯

在当今信息爆炸的时代背景下&#xff0c;挑选一款真正符合个人需求的护眼台灯&#xff0c;确实是一项不小的挑战。市场上品牌众多、型号繁杂&#xff0c;功能特点各不相同&#xff0c;价格区间也相当广泛&#xff0c;许多消费者在选购时往往感到迷茫不已。当大家询问“什么品牌…

cv.dnn.blobFromImage参数详解

例如&#xff1a; image cv.imread(imgs/img.png) blob cv.dnn.blobFromImage(image, scalefactor1.0, size(224, 224), mean(0, 0, 0), swapRBTrue, cropFalse) print("原始图像形状:", image.shape) print("Blob数据形状:", blob.shape)1. image 含义…

消息队列-Rabbitmq(消息发送,消息接收)

将来我们开发业务功能的时候&#xff0c;肯定不会在控制台收发消息&#xff0c;而是应该基于编程的方式。由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不…

电脑没有下载声卡驱动怎么办?电脑声卡驱动安装方法

在日常使用电脑的过程中&#xff0c;我们可能会遇到电脑没有声音的问题&#xff0c;这往往与声卡驱动缺失或损坏有关。声卡驱动是连接电脑硬件&#xff08;声卡&#xff09;与操作系统之间的桥梁&#xff0c;确保音频信号能够正常输入输出。那么&#xff0c;当电脑没有声卡驱动…

人工智能与数据安全:Facebook如何应对隐私挑战

在数字时代&#xff0c;数据隐私和安全成为了用户和企业关注的核心问题。作为全球最大的社交媒体平台之一&#xff0c;Facebook面临着日益严峻的隐私挑战。近年来&#xff0c;频繁发生的数据泄露事件和对用户隐私的质疑&#xff0c;使得Facebook在保护用户数据方面倍感压力。为…

使用RabbitMQ实现微服务间的异步消息传递

使用RabbitMQ实现微服务间的异步消息传递 RabbitMQ简介 安装RabbitMQ 在Ubuntu上安装RabbitMQ 在CentOS上安装RabbitMQ 配置RabbitMQ 创建微服务 生产者服务 安装依赖 生产者代码 消费者服务 消费者代码 运行微服务 消息模式 直接模式 生产者代码 消费者代码 扇出模式 生产…

【MySQL】MySQL安装以及各种报错处理

前言&#xff1a; 本节内容讲述在Ubuntu环境下怎么进行MySQL的安装。 以及一些安装过程中遇到的报错如何处理的问题。 ps:注意&#xff0c; 本篇文章不是图形化界面的MySQL安装教程哦。想要安装图形化界面的MySQL的友友们可以另寻资源了。 目录 更新软件包列表 安装M…

Servlet 3.0 注解开发

文章目录 Servlet3.0注解开发修改idea创建注解的servlet模板内容讲解 关于servlet3.0注解开发的疑问_配置路径省略了属性urlPatterns内容讲解内容小结 Servlet3.0注解开发 【1】问题 说明&#xff1a;之前我们都是使用web.xml进行servlet映射路径的配置。这样配置的弊端&…

FPGA时序分析和约束学习笔记(3、Timequest时序路径详解和优化)

FPGA时序分析和约束学习笔记&#xff08;3、Timequest时序路径详解和优化&#xff09; Timequest中Data Path分析 Data Arrival Path clock path&#xff1a;时钟信号到达源寄存器时钟端口的时间 data path&#xff1a;数据从源寄存器Q端口出发到达目标寄存器D端口的时间 D…

windows与windows文件共享

目录 基础设置主机共享文件端设置从机接受文件端设置 基础设置 1、先确保两台电脑直接能够ping通&#xff0c;这是文件共享的前提&#xff0c;如果ping不通就去查找对应的原因&#xff0c;一般都是防火墙的原因。 在ping通的情况下&#xff1a; 2、先找到高级共享设置 3、对专…

前端页面整屏滚动fullpage.js简单使用

官网CSS,JS地址 fullPage.js/dist/fullpage.min.js at master alvarotrigo/fullPage.js GitHub fullPage.js/dist/fullpage.min.css at master alvarotrigo/fullPage.js GitHub <!DOCTYPE html> <html lang"en"><head><meta charset"…

Rust整合Elasticsearch

Elasticsearch是什么 Lucene&#xff1a;Java实现的搜索引擎类库 易扩展高性能仅限Java开发不支持水平扩展 Elasticsearch&#xff1a;基于Lucene开发的分布式搜索和分析引擎 支持分布式、水平扩展提高RestfulAPI&#xff0c;可被任何语言调用 Elastic Stack是什么 ELK&a…

opencv-day2-图像预处理1

图像预处理 在计算机视觉和图像处理领域&#xff0c;图像预处理能够提高后续处理&#xff08;如特征提取、目标检测等&#xff09;的准确性和效率。 常见的图像预处理操作&#xff1a; 图像色彩空间转换 图像大小调整 图像仿射变换 图像翻转 图像裁剪 图像二值化处理 图…