SpringBoot 接入讯飞星火大模型实现对话

申请地址

https://xinghuo.xfyun.cn/sparkapi?scr=price
免费申请200万Token

开发文档

https://www.xfyun.cn/doc/spark/Web.html#_1-接口说明

页面最下面有相关demo可以参考

在这里插入图片描述

介绍

接口是以套接字的形式分段返回,而且非http请求,比较繁琐,官方也只给了比较简单的deom。

依赖项

  <!--okhttp3-->
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>

     <!-- 阿里JSON解析器 -->
            <dependency>
                <groupId>com.alibaba.fastjson2</groupId>
                <artifactId>fastjson2</artifactId>
            </dependency>

配置文件

xunfei:
    ai:
        hostUrl: https://spark-api.xf-yun.com/v3.5/chat
        appId: xxx
        apiSecret: xxx
        apiKey: xxx

控制台上可以查看 API认证字符串

在这里插入图片描述

读取配置文件

@Value("${xunfei.ai.hostUrl}")
private  String  hostUrl;

@Value("${xunfei.ai.appId}")
private  String appId;

@Value("${xunfei.ai.apiSecret}")
private  String apiSecret;

@Value("${xunfei.ai.apiKey}")
private  String apiKey;

权限校验

得到的是一个url,需要将http替换成ws

/**
     * 权限校验
     * @return String
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws MalformedURLException
     */
    private String getAuthUrl() throws NoSuchAlgorithmException, InvalidKeyException, MalformedURLException {
        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();
    }

构建请求参数

请求参数是与json格式进行发送,如果需要结合之前的信息继续回答需要携带历史记录。在官方的api文档也可以查看

#参数构造示例如下

{
        "header": {
            "app_id": "12345",
            "uid": "12345"
        },
        "parameter": {
            "chat": {
                "domain": "generalv3.5",
                "temperature": 0.5,
                "max_tokens": 1024, 
            }
        },
        "payload": {
            "message": {
                # 如果想获取结合上下文的回答,需要开发者每次将历史问答信息一起传给服务端,如下示例
                # 注意:text里面的所有content内容加一起的tokens需要控制在8192以内,开发者如有较长对话需求,需要适当裁剪历史信息
                "text": [
                    {"role":"system","content":"你现在扮演李白,你豪情万丈,狂放不羁;接下来请用李白的口吻和用户对话。"} #设置对话背景或者模型角色
                    {"role": "user", "content": "你是谁"} # 用户的历史问题
                    {"role": "assistant", "content": "....."}  # AI的历史回答结果
                    # ....... 省略的历史对话
                    {"role": "user", "content": "你会做什么"}  # 最新的一条问题,如无需上下文,可只传最新一条问题
                ]
        }
    }
}

JAVA构建


    private    String buildBody(String text,String uid){
        JSONObject body =new JSONObject();

       JSONObject header =new JSONObject();
        header.put("app_id",appId);
        header.put("uid",uid);
        body.put("header",header);

        JSONObject parameter =new JSONObject();
        JSONObject chat =new JSONObject();
        chat.put("domain","generalv3.5");
        parameter.put("chat",chat);

        body.put("parameter",parameter);

        JSONObject history =JSONObject.parseObject(text);
        body.put("payload",history);

        JSONObject back =new JSONObject();
        back.put("role","system");
        back.put("content","请回答我关于一些生产安全的内容");
        //定义会话背景
        
        history.getJSONObject("message").getJSONArray("text").add(0,back);
        return body.toJSONString();
    }

回复消息

基于OKHTTP3的请求库,连接websocket

 /**
     * 回复消息
     * @param text
     * @return
     * @throws MalformedURLException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public String answer(String text,String uid) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException, ExecutionException, InterruptedException, TimeoutException {
        String authUrl =getAuthUrl().replace("http://", "ws://").replace("https://", "wss://");
        Request request = new Request.Builder().url(authUrl).build();
        OkHttpClient client = new OkHttpClient.Builder().build();
        StringBuilder sb =new StringBuilder();
        CompletableFuture<String> messageReceived = new CompletableFuture<>();
        String body = buildBody(text,uid);
        WebSocket webSocket =client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
            webSocket.send(body);
            //发送消息
            }
            @Override
            public void onMessage(WebSocket webSocket, String text) {
                JSONObject obj = JSON.parseObject(text);
                  String str= obj.getJSONObject("payload").getJSONObject("choices").getJSONArray("text").getJSONObject(0).getString("content");
                  sb.append(str);
                  if(obj.getJSONObject("header").getLong("status")==2){
                      webSocket.close(1000, "Closing WebSocket connection");
                      messageReceived.complete(text); // 将收到的消息传递给 CompletableFuture
                  }
            }

        } );
        String result = messageReceived.get(30, TimeUnit.SECONDS);; // 阻塞等待消息返回
        webSocket.close(1000, "Closing WebSocket connection");
        return sb.toString();
    }

Controller

   @PostMapping("/chat")
    public AjaxResult chat(String text,String uid) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException, ExecutionException, InterruptedException, TimeoutException {
        return  success( model.answer(text,uid));
    }

运行效果

在这里插入图片描述

完整代码

Controller层

@RestController
@RequestMapping("/course")
public class QueryController extends BaseController {
    @Autowired
    private CognitiveMode model;
    
    @PostMapping("/chat")
    public AjaxResult chat(String text,String uid) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException, ExecutionException, InterruptedException, TimeoutException {
        return  success( model.answer(text,uid));
    }


}
package com.ruoyi.framework.ai;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Component
public class CognitiveMode {
    @Value("${xunfei.ai.hostUrl}")
    private  String  hostUrl;
    @Value("${xunfei.ai.appId}")
    private  String appId;
    @Value("${xunfei.ai.apiSecret}")
    private  String apiSecret;
    @Value("${xunfei.ai.apiKey}")
    private  String apiKey;



    /**
     * 回复消息
     * @param text
     * @return
     * @throws MalformedURLException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public String answer(String text,String uid) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException, ExecutionException, InterruptedException, TimeoutException {
        String authUrl =getAuthUrl().replace("http://", "ws://").replace("https://", "wss://");
        Request request = new Request.Builder().url(authUrl).build();
        OkHttpClient client = new OkHttpClient.Builder().build();
        StringBuilder sb =new StringBuilder();
        CompletableFuture<String> messageReceived = new CompletableFuture<>();
        String body = buildBody(text,uid);
        WebSocket webSocket =client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
            webSocket.send(body);
            }
            @Override
            public void onMessage(WebSocket webSocket, String text) {
                JSONObject obj = JSON.parseObject(text);
                  String str= obj.getJSONObject("payload").getJSONObject("choices").getJSONArray("text").getJSONObject(0).getString("content");
                  sb.append(str);
                  if(obj.getJSONObject("header").getLong("status")==2){
                      webSocket.close(1000, "Closing WebSocket connection");
                      messageReceived.complete(text); // 将收到的消息传递给 CompletableFuture
                  }
            }

        } );
        String result = messageReceived.get(30, TimeUnit.SECONDS);; // 阻塞等待消息返回
        webSocket.close(1000, "Closing WebSocket connection");
        return sb.toString();
    }

    private    String buildBody(String text,String uid){
        JSONObject body =new JSONObject();

       JSONObject header =new JSONObject();
        header.put("app_id",appId);
        header.put("uid",uid);
        body.put("header",header);

        JSONObject parameter =new JSONObject();
        JSONObject chat =new JSONObject();
        chat.put("domain","generalv3.5");
        parameter.put("chat",chat);

        body.put("parameter",parameter);

        JSONObject history =JSONObject.parseObject(text);
        body.put("payload",history);

        JSONObject back =new JSONObject();
        back.put("role","system");
        back.put("content","请回答我关于一些xxx的内容");
        history.getJSONObject("message").getJSONArray("text").add(0,back);



        return body.toJSONString();
    }


    /**
     * 权限校验
     * @return String
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws MalformedURLException
     */
    private String getAuthUrl() throws NoSuchAlgorithmException, InvalidKeyException, MalformedURLException {
        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();
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Sam Altman计划筹集5至7万亿美元;OPPO发布AI时代新功能

&#x1f989; AI新闻 &#x1f680; Sam Altman计划筹集5至7万亿美元&#xff0c;建立全球芯片帝国 摘要&#xff1a;Sam Altman宣布计划筹集5至7万亿美元来建立全球芯片帝国&#xff0c;以满足日益增长的AI基础设施需求。他已在全球寻求资金&#xff0c;包括中东土豪。此外…

开发JSP自定义标记

开发JSP自定义标记 您已经学习了如何用JavaBean处理JSP页面的业务逻辑。除此以外,您还可以用自定义标记处理JSP应用程序中反复出现的业务逻辑要求。 tag是程序中使用的执行重复性任务的可重用单元。例如, 是使主体文本在网页中间出现的HTML标记。JSP可用于创建于XML标记类似…

​(三)hadoop之hive的搭建1

下载 访问官方网站https://hive.apache.org/ 点击downloads 点击Download a release now! 点击https://dlcdn.apache.org/hive/ 选择最新的稳定版 复制最新的url 在linux执行下载命令 wget https://dlcdn.apache.org/hive/hive-3.1.3/apache-hive-3.1.3-bin.tar.gz 2.解压…

SpringBoot全局异常捕获处理实现方案

在Spring Boot中实现全局异常处理可以通过以下方式&#xff1a; 使用ControllerAdvice注释创建一个全局异常处理类&#xff0c;并使用ExceptionHandler注释来定义具体异常的处理方法。 import your.package.IllegalNumberException; import org.springframework.http.HttpSta…

继续教育试题答案?学生党都在用的九款搜题工具来了 #其他#笔记#知识分享

今天分享拥有拍照搜题、文字搜题、语音搜题、多重搜题等搜题模式&#xff0c;可以快速查找问题解析&#xff0c;加深对题目答案的理解。 1.题老大 这是一个公众号 适合大学生找答案。包含了大学网课答案&#xff0c;期末复习资料&#xff0c;新视野英语&#xff0c;考研答案…

[office] excel如何计算毛重和皮重的时间间隔 excel计算毛重和皮重时间间隔方法 #笔记#学习方法

excel如何计算毛重和皮重的时间间隔 excel计算毛重和皮重时间间隔方法 在日常工作中经常会到用excel&#xff0c;有时需要计算毛重和皮重的时间间隔&#xff0c;具体的计算方式是什么&#xff0c;一起来了解一下吧 在日常工作中经常会到用excel&#xff0c;在整理编辑过磅数据…

「daily updating」k3s + openfaas serverless bench 踩坑指南持续更新中

OpenFaas从入门到实战 – 踩坑指南 &#xff5c; k3dOpenFaas | deploy your first python function https://blog.alexellis.io/first-faas-python-function/ https://docs.openfaas.com/deployment/kubernetes/ 搭建环境&#xff1a;第一种方法失败&#xff0c;第二种方法…

灰度发布浅见

在之前的稳定性生产文章中有一项对于研发人员比较重要的措施是变更管控&#xff0c;关于变更管控其实在实际生产活动中有很多措施&#xff0c;因为对于不太的行业&#xff0c;其行业特点和稳定性生产的要求也不一样&#xff0c;例如下图&#xff0c;我们可以看到信通院调研的不…

[职场] 大厂群面的基本题型 #学习方法#其他

大厂群面的基本题型 大厂群面的基本题型 群面&#xff0c;又叫做“无领导小组面试”。历年来是企业校招时&#xff0c;进行大批量刷人的有效方法。流行于互联网、快消、银行、四大等多个行业。因为难度大、情况复杂、淘汰率高&#xff0c;又被称为“死亡面试”。 无领导小组…

微信小程序(四十)API的封装与调用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.在单独的js文件中写js接口 2.以注册为全局wx的方式调用接口 源码&#xff1a; utils/testAPI.js const testAPI{/*** * param {*} title */simpleToast(title提示){//可传参&#xff0c;默认为‘提示’wx.sho…

CSS3 基本语法

CSS3 基本语法 1. CSS3 新增长度单位 rem 根元素字体大小的倍数&#xff0c;只与根元素字体大小有关。vw 视口宽度的百分之多少 10vw 就是视口宽度的 10% 。vh 视口高度的百分之多少 10vh 就是视口高度的 10% 。vmax 视口宽高中大的那个的百分之多少。&#xff08;了解即可&am…

【复现】泛微云桥 e-Bridge SQL注入漏洞_44

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 泛微云桥&#xff08;e-Bridge&#xff09;是上海泛微公司在”互联网”的背景下研发的一款用于桥接互联网开放资源与企业信息化系…

AI新工具(20240210) Osam - Osam是一个启用本地运行的开源llm;Whishper - Whishper是一个开源的语音工具

Osam - Osam是一个启用本地运行的开源“一切分割”模型工具&#xff0c;支持多种接口和自定义视觉模型。 Osam是一个开源工具&#xff0c;它允许本地运行“可对任何内容进行分割”的模型(Segment-Anything Models)&#xff0c;灵感来源于Ollama。使用Osam&#xff0c;用户可以…

猪圈密码.

1.介绍 又称朱高密码、共济会密码、共济会暗号、共济会员密码&#xff0c;是一种以格子为基础的简单替代式密码。即时使用符号&#xff0c;也不影响密码分析&#xff0c;亦可用其他替代式密码。 2.产生背景 这是一种外形古怪的密码&#xff0c;已经传递了几百年。没有人明确…

Minecraft的红石教程之电梯

一.前言 我记得是上初中的时候&#xff0c;就看到了这类电梯。现在我在看现在这类电梯的相关视频&#xff0c;大多是盗用创意未能领会其中的红石运作规律&#xff0c;于是我就删繁就简写了这篇。 二.步骤 1.材料 粘性活塞&#xff0c;黏液块&#xff0c;红石&#xff0c;红…

洛谷p4391 无限传输

考察字符串周期的题 题目链接 结论 要求字串 s s s的最短循环字串长就是&#xff1a; a n s n − p m t [ n ] ansn-pmt[n] ansn−pmt[n] 证明如下&#xff1a; 这是最大的前缀和后缀 现在我们做如下操作&#xff1a; 补全字段 a a a和字段 b b b&#xff0c;按子段 a a a的…

Javaweb之SpringBootWeb案例之事务管理的详细解析

1. 事务管理 1.1 事务回顾 在数据库阶段我们已学习过事务了&#xff0c;我们讲到&#xff1a; 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位。事务会把所有的操作作为一个整体&#xff0c;一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功&am…

第三百一十六回

[tod] 我们在上一章回中介绍了"如何在输入框中处理光标"相关的内容&#xff0c;本章回中将介绍如何添加输入框默认值.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 在项目中经常使用输入框获取用户输入的内容&#xff0c;有时候在输入框中反复输入相…

多模态知识图谱:感知与认知的交汇

目录 前言1 多模态知识图谱的概念1.1 感知系统与认知系统的连接1.2 信息形式的整合与融合1.3 全面、多维度的认知基础 2 多模态的作用2.1 模态的知识互补2.2 模态实体消歧2.3 模态语义搜索2.4 知识图谱补全2.5 多模态任务增强 3 多模态知识图谱发展历史3.1 初期模态数据整合3.2…

数据结构——5.4 树、森林

5.4 树、森林 概念 树的存储结构 双亲表示法 孩子表示法 孩子兄弟表示法&#xff08;二叉树表示法&#xff09;&#xff1a; 二叉树每个结点有三个变量 ① 二叉树结点值&#xff1a;原树结点的值 ② 二叉树左孩子&#xff1a;原树结点的最左孩子 ③ 二叉树右孩子&#xff1a…