springboot+webSocket对接chatgpt

webSocket对接参考

话不多说直接上代码

WebSocket

package com.student.config;import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;/*** @Description:* @Author: hwk* @Date: 2024-07-17 17:46* @Version: 1.0**/
@Slf4j
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocket {/*** 与某个客户端的连接会话,需要通过它来给客户端发送数据*/private Session session;/*** gpt密钥*/private static final String key = "";/*** 请求地址*/private static final String url = "";/*** 用户ID*/private String userId;//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。//虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。//  注:底下WebSocket是当前类名private static CopyOnWriteArraySet<WebSocket> webSockets = new CopyOnWriteArraySet<>();// 用来存在线连接用户信息private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<String, Session>();/*** 链接成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam(value = "userId") String userId) {try {this.session = session;this.userId = userId;webSockets.add(this);sessionPool.put(userId, session);log.info("【websocket消息】有新的连接,总数为:" + webSockets.size());} catch (Exception e) {}}/*** 链接关闭调用的方法*/@OnClosepublic void onClose() {try {webSockets.remove(this);sessionPool.remove(this.userId);log.info("【websocket消息】连接断开,总数为:" + webSockets.size());} catch (Exception e) {}}/*** 收到客户端消息后调用的方法** @param message*/@OnMessagepublic void onMessage(String message) {log.info("【websocket消息】收到客户端消息:" + message);JSONObject jsonObject = new JSONObject();JSONArray objects = new JSONArray();JSONObject messages = new JSONObject();messages.put("role", "user");messages.put("content", message);objects.add(messages);jsonObject.put("model", "gpt-3.5-turbo");jsonObject.put("messages", objects);jsonObject.put("max_tokens", 1024);jsonObject.put("temperature", 0);jsonObject.put("stream", true);Map<String, String> heads = new HashMap<>();heads.put("Content-Type", "application/json");heads.put("Accept", "application/json");heads.put("Authorization", "Bearer "+key);WebClient webClient = WebClient.create();Flux<String> stringFlux = webClient.post().uri(url).header("Content-Type", "application/json").header("Accept", "application/json").header("Authorization", "Bearer " + key).accept(MediaType.TEXT_EVENT_STREAM).bodyValue(jsonObject).retrieve().bodyToFlux(String.class);stringFlux.subscribe(s -> {if (!Objects.equals(s, "[DONE]")) {JSONObject parsed = JSONObject.parseObject(s);JSONArray choices = parsed.getJSONArray("choices");if (!choices.isEmpty()) {JSONObject dataJson = JSONObject.parseObject(choices.get(0).toString());String content = dataJson.getJSONObject("delta").getString("content");if (StringUtils.hasLength(content)) {try {content = content.replaceAll("\n", "<br>");content = content.replace(" ", "");log.info(content);if (sessionPool != null) {sessionPool.get(userId).getBasicRemote().sendText(content);}} catch (Exception e) {e.printStackTrace();}}}}});}/*** 发送错误时的处理** @param session* @param error*/@OnErrorpublic void onError(Session session, Throwable error) {log.error("用户错误,原因:" + error.getMessage());error.printStackTrace();}/*** 此为广播消息** @param message*/public void sendAllMessage(String message) {log.info("【websocket消息】广播消息:" + message);for (WebSocket webSocket : webSockets) {try {if (webSocket.session.isOpen()) {webSocket.session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息** @param userId* @param message*/public void sendOneMessage(String userId, String message) {Session session = sessionPool.get(userId);if (session != null && session.isOpen()) {try {log.info("【websocket消息】 单点消息:" + message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息(多人)** @param userIds* @param message*/public void sendMoreMessage(String[] userIds, String message) {for (String userId : userIds) {Session session = sessionPool.get(userId);if (session != null && session.isOpen()) {try {log.info("【websocket消息】 单点消息:" + message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}
}

WebSocketConfig

package com.student.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @Description: WebSocketConfig配置* @Author: hwk* @Date: 2024-07-17 17:44* @Version: 1.0**/
@Configuration
public class WebSocketConfig {/***   注入ServerEndpointExporter,*   这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

html代码

<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /><title>ChatGPT</title><script src="marked.min.js"></script><link rel="stylesheet" type="text/css" href="index.css"><style>.normal-text {color: black;}.rich-text {color: blue;font-weight: bold;}</style>
</head>
<body><h2>ChatGPT</h2><div id="message-container"><p id="message"></p></div><div id="footer"><input id="text" class="my-input" type="text" /><button onclick="send()">发送</button></div><div id="footer1"><br /><button onclick="closeWebSocket()">关闭WebSocket连接</button><button onclick="openWebSocket()">建立WebSocket连接</button></div><script>marked.setOptions({highlight: function (code, lang) {return hljs.highlightAuto(code).value;}});var websocket = null;// 判断当前浏览器是否支持WebSocket,是则创建WebSocketif ('WebSocket' in window) {console.log("浏览器支持WebSocket");websocket = new WebSocket("ws://127.0.0.1:8056/websocket/1");} else {alert('当前浏览器不支持WebSocket');}// 连接发生错误的回调方法websocket.onerror = function () {console.log("WebSocket连接发生错误");setMessageInnerHTML("WebSocket连接发生错误");};// 连接成功建立的回调方法websocket.onopen = function () {console.log("WebSocket连接成功");};// 接收到消息的回调方法websocket.onmessage = function (event) {if (event.data) {setMessageInnerHTML(event.data);}console.log(event.data);};// 连接关闭的回调方法websocket.onclose = function () {console.log("WebSocket连接关闭");};// 关闭WebSocket连接function closeWebSocket() {websocket.close();}// 发送消息function send() {var message = document.getElementById('text').value;websocket.send(message);}// 建立连接的方法function openWebSocket() {websocket = new WebSocket("ws://127.0.0.1:8056/websocket/1");websocket.onopen = function () {console.log("WebSocket连接成功");};}// 将消息显示在网页上function setMessageInnerHTML(innerHTML) {console.log(innerHTML);// var element = document.getElementById('message');// if (innerHTML.match(/```/g)) {//     element.innerHTML += marked(innerHTML); // 使用marked渲染Markdown// } else {//     element.innerHTML += innerHTML; // 直接添加普通文本消息// }document.getElementById('message').innerHTML += innerHTML;}// 如果websocket连接还没断开就关闭了窗口,后台server端会抛异常。// 所以增加监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接window.onbeforeunload = function () {closeWebSocket();};</script>
</body>
</html>

效果
在这里插入图片描述

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

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

相关文章

深度学习论文精读

深度学习论文精读 所有论文 包括已经精读完成和之后将要精读的论文&#xff0c;10年内深度学习里有影响力文章&#xff08;必读文章&#xff09;&#xff0c;或者近期比较有意思的文章。 感谢沐神&#xff01; 总论文数 67&#xff0c;阅读完成数 32 计算机视觉 - CNN 已…

前端笔试全攻略:30道经典面试题详解

引言 前端开发是一个充满挑战与机遇的领域&#xff0c;随着Web技术的不断发展&#xff0c;前端工程师需要掌握的知识体系也在不断扩展。无论是刚入门的新手还是资深开发者&#xff0c;在求职过程中都会面临各种技术笔试。本文将为你提供30道常见的前端笔试题及其详尽解答&…

FLINKCDC连接oracle导致归档日志暴增

前言 前段时间再用flinkcdc连接oracle的时候&#xff0c;oracle的归档日志疯狂的飙升,我经常去到归档目录下查看占用的内存情况。。 情况 在使用flinkcdc连接oracle的时候&#xff0c;发现归档日志飙升&#xff0c;查看了很多文档&#xff0c;该配置了都配置了&#xff0c; …

使用el-table实现自动滚动

文章目录 概要技术实现完整代码 概要 在前端开发大屏的时候&#xff0c;我们会用到表格数据展示&#xff0c;有时候为了使用户体验更加好&#xff0c;会增加表格自动滚动。下边我将以示例代码&#xff0c;用element UI的el-table来讲一下。 技术实现 1 .增加dom监听&#xf…

Linux搭建Kubernetes集群(单Master)【附图文】

文章目录 一、集群环境配置要求二、主机准备三、初始环境准备1.关闭防火墙2.关闭 selinux3.关闭swap4.加载 br_netfilter 模块5.允许iptables转发流量6.设置时间同步 四、安装Docker五、安装kubeadm, kubectl, kubelet六、在Master节点部署集群七、将 node 节点加入集群八、部署…

(一)Readme 了解kurator

Kurator 是一个开源的分布式云原生平台&#xff0c;旨在帮助用户构建自己的分布式云原生基础设施&#xff0c;并出金企业进行数字化转型。 概览 云原生软件栈&#xff1a;kurator结合了多种流行的云原生软件栈&#xff08;Kubernetes、Istio、Prometheus等&#xff09;&#…

学习笔记14:CNAME 记录值、TTL (Time to Live)、Redis 的 Pool 对象池、钩子函数、依赖注入

CNAME 记录值 CNAME 记录是一种DNS记录类型&#xff0c;它将一个域名映射到另一个域名。这通常用于将一个子域名指向另一个域名&#xff0c;或者将一个域名指向一个不同的顶级域。 用途&#xff1a;用于域名别名&#xff0c;负载均衡&#xff0c;或者在更换域名时保持服务的连…

CSS(四)——CSS Text(文本)

CSS Text(文本&#xff09; 文本颜色 颜色属性被用来设置文字的颜色。 颜色是通过CSS最经常的指定&#xff1a; 十六进制值 - 如: &#xff03;FF0000 一个RGB值 - 如: RGB(255,0,0) 颜色的名称 - 如: red 一个网页的背景颜色是指在主体内的选择&#xff0c;即<body…

【C#】Func、Action和Predicate

使用情景 根据不同参数值&#xff0c;执行不同方法&#xff0c;执行完方法后&#xff0c;执行相同的操作 函数 Func Func 委托表示有返回值的方法。它最多可以接受 16 个输入参数&#xff0c;并且必须返回一个值。在 Func 委托中&#xff0c;最后一个类型参数始终是返回类型…

【C语言】英寸英尺转换米

运行的结果为 我们百度一下 恒明显我们的答案错了,那这个是为什么呢? 问题就出现在计算的地方,c语言规定两个整数计算,那么小数的部分会被丢弃. 如果计算的两个数中有一个数为小数,那么会将两个数都变为小数在进行计算,结果也会是小数. 那么我们现在就有解决办法了. 方法一…

gbase8s自动同步数据及加入集群的脚本

cat remote.sh #!/bin/bash #此脚本永远在主节点上执行&#xff0c;需要同步的节点永远是备节点 #主节点pri开头&#xff0c;备节点hac开头 #开始执行脚本之前一定要关闭hac节点&#xff0c;并且系统空间要大于备份数据文件的大小 #执行之前请手动改好ip和主备节点的实例名及g…

开源浪潮下的航行:趋势洞察与个人航迹

引言 在全球经济与科技浪潮的推动下&#xff0c;开源软件项目如同一股不可阻挡的洪流&#xff0c;正以前所未有的速度席卷整个技术生态。它不仅促进了技术的快速迭代与创新&#xff0c;更搭建起了一个跨越国界、行业与组织的协作平台。本文旨在探讨当前开源项目的发展趋势&…

SSH不用每次都输入密码的方法

首先&#xff0c;打开自己电脑上的终端cmd 输入&#xff1a; ssh-keygen -t rsa 一直回车。 然后我的服务器因为某些原因不能直接复制到远程终端 所以我手动复制&#xff0c;先打开要复制的公钥。这个地址就看你的程序默认给你创建的文件在哪里了。 cat .ssh/id_rsa.pub 这个--…

【时时三省】unity test 测试框架 下载

目录 1&#xff0c;unity test 测试框架介绍 2&#xff0c;源码下载 3&#xff0c;目录架构 4&#xff0c;git for window 下载安装方法&#xff1a; 1&#xff0c;unity test 测试框架介绍 Unity是一个用于C语言的轻量级单元测试框架。它由Throw The Switch团队开发&#…

Umi-OCR:功能强大且易于使用的本地照片识别软件

Umi-OCR是一款开源且免费的离线OCR&#xff08;光学字符识别&#xff09;软件&#xff0c;可让您轻松从照片中提取文本。它支持多种语言&#xff0c;并具有许多其他功能使其成为照片识别任务的绝佳选择。 Umi-OCR的优势 离线操作&#xff1a; Umi-OCR无需互联网连接即可工作&…

【算法】分割回文串

难度&#xff1a;中等 题目&#xff1a; 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1&#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;[[“a”,“a”,“b”],[“aa”,“b”]] 示…

PyMySQL库的使用方法

过程和步骤&#xff1a; 安装 PyMySQL 首先&#xff0c;需要使用 pip 安装 PyMySQL 库&#xff1a; pip install pymysql连接数据库 使用 PyMySQL.connect() 方法可以建立到 MySQL 数据库的连接&#xff1a; import pymysql# 配置数据库连接参数 config {host: localhost…

鸿蒙开发仓颉语言【在工程中使用Hyperion TCP框架】

3. 在工程中使用Hyperion TCP框架 3.1 导入Hyperion TCP框架的静态库 在工程的module.json中引入Hyperion TCP框架的静态库&#xff1a; "package_requires": {"package_option": {"hyperion_hyperion.buffer": "${path_to_hyperion_proj…

启发式缓存和本地存储缓存

启发式缓存详解 当服务器响应中没有包含 Expires、Cache-Control: max-age 或 Cache-Control:s-maxage 时,浏览器会采用一个启发式的算法来确定缓存的时间。 1. 启发式缓存的计算方法 通常,启发式缓存会根据响应头中的 Date 和 Last-Modified 之间的时间差来计算缓存时间。 …

【算法】01背包

算法-01背包 前置知识 DP 思路 01背包一般分为两种&#xff0c;不妨叫做价值01背包和判断01背包。 价值01背包 01背包问题是这样的一类问题&#xff1a;给定一个背包的容量 m m m 和 n n n 个物品&#xff0c;每个物品有重量 w w w 和价值 v v v&#xff0c;求不超过背…