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

news2024/11/18 14:53:57

申请地址

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();
    }

}

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

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

相关文章

基于JAVA的教学资源共享平台 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课程资源模块2.4 课程作业模块2.5 课程评价模块 三、系统设计3.1 用例设计3.2 类图设计3.3 数据库设计3.3.1 课程档案表3.3.2 课程资源表3.3.3 课程作业表3.3.4 课程评价表 四、系统展…

Go语言每日一练——链表篇(八)

传送门 牛客面试笔试必刷101题 ----------------两个链表的第一个公共结点 题目以及解析 题目 解题代码及解析 解析 这一道题使用的还是双指针算法&#xff0c;我们先求出两个链表的长度差n&#xff0c;然后定义快慢指针&#xff0c;让快指针先走n步&#xff0c;最后快慢指…

苹果iOS设备备份管理神器imazing3中文版免费下载

如果您是一位资深果粉&#xff0c;那您对imazing这款iOS设备管理神器一定很熟悉。不过也有很多小伙伴只是听过这款软件的名字&#xff0c;不知道它具体是做什么的。今天就让小编跟大家说下imazing是什么软件&#xff0c;再给大家分享它最好用的两个功能。 imazing是什么&#x…

C语言之:编译和链接

目录 1. 翻译环境和运行环境翻译环境 2. 翻译环境&#xff1a;预编译编译汇编链接预处理&#xff08;预编译&#xff09;编译词法分析语法分析语义分析汇编链接运行环境 1. 翻译环境和运行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 第一种是翻译环境&a…

Taro+ vue3 + template nut-ui 4.0 + pinia 的前端框架模板搭建

1.展示 目前我们有一个需要做H5 微信小程序的需求。当然我们可选的框架有很多,比如说:uni-app Taro京东框架 去做这些前端需求 2.介绍 Taro ①.项目的具体结构 Taro框架中 的目录结构 大体上都是一样的 page页面 store ② 项目的store 状态管理 状态管理使用的是pinia v…

Jumserver 安装

一、Jumserver 官网地址 Jumserver官网地址 二、Jumserver的基本概率 1、4a概率 首先&#xff0c;堡参机提供了运维安全审计的4A规范 Authentication: 身份鉴别&#xff0c;防止身份冒用和复用(开发10人&#xff0c;测试5人&#xff0c;运维2人&#xff09; Authorizatton:授…

探索C语言的内存魔法:动态内存管理解析

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C语言学习 贝蒂的主页&#xff1a;Betty‘s blog 1. 静态开辟内存 通过前面的学习&#xff0c;我们已经掌握了两种开辟内存的方…

“深度解析Java虚拟机:运行时数据区域、垃圾收集、内存分配与回收策略、类加载机制“

"深度解析Java虚拟机&#xff1a;运行时数据区域、垃圾收集、内存分配与回收策略、类加载机制" Java 虚拟机一、运行时数据区域程序计数器Java 虚拟机栈本地方法栈堆方法区运行时常量池直接内存 二、垃圾收集判断一个对象是否可被回收1. 引用计数算法2. 可达性分析算…

Python图形用户界面

目录 Python中的图形用户界面开发库 安装wxPython 第一个wxPython程序 自定义窗口类 在窗口中添加控件 事件处理 布局管理 盒子布局管理器 重构事件处理示例 盒子布局管理器嵌套示例 控件 文本输入控件 复选框和单选按钮 列表 静态图片控件 我们之前的程序运行结…

python 基础知识点(蓝桥杯python科目个人复习计划36)

今日复习计划&#xff1a;DFS搜索基础 1.简介 搜索方法&#xff1a;穷举问题解空间部分&#xff08;所有情况&#xff09;&#xff0c;从而求出问题的解。 深度优先搜索&#xff1a;本质上是暴力枚举 深度优先&#xff1a;尽可能一条路走到底&#xff0c;走不了再回退。 2…

面向对象编程:理解其核心概念与应用

引言 在编程的世界中&#xff0c;面向对象编程&#xff08;Object-Oriented Programming, OOP&#xff09;已成为一种主流的编程范式。它提供了一种组织和管理代码的有效方式&#xff0c;使得代码更加模块化、可重用和易于维护。本文将带您深入探讨面向对象编程的核心概念及其…

春节每日一题~(自除数)

728. 自除数 - 力扣&#xff08;LeetCode&#xff09; #include <stdlib.h> int* selfDividingNumbers(int left, int right, int* returnSize) { int* result (int*)malloc((right - left 1) * sizeof(int)); if (result NULL) { // 内存分配失败 *returnSize …

展示wandb的数据

import wandb import matplotlib.pyplot as plt# 初始化 wandb API api wandb.Api()# 假设您想要访问的项目名为 my_project&#xff0c;并且您的 wandb 用户名为 my_username project_name "aicolab/RWKV-5-Test"# 获取项目中的runs runs api.runs(project_name)…

ClickHouse--02--安装

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 安装官网 &#xff1b;[https://clickhouse.com/docs/zh/getting-started/install](https://clickhouse.com/docs/zh/getting-started/install)![在这里插入图片描述…

Spring基础 - SpringMVC请求流程和案例

Spring基础 - SpringMVC请求流程和案例 什么是MVC 用一种业务逻辑、数据、界面显示分离的方法&#xff0c;将业务逻辑聚集到一个部件里面&#xff0c;在改进和个性化定制界面及用户交互的同时&#xff0c;不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理…

OpenCV 笔记(21):图像色彩空间

1. 图像色彩空间 图像色彩空间是用于定义颜色范围的数学模型。 它规定了图像中可以使用的颜色以及它们之间的关系。它决定了图像中可以显示的颜色范围。不同的色彩空间可以包含不同的颜色范围&#xff0c;因此选择合适的色彩空间对于确保图像在不同设备上看起来一致非常重要。…

使用AI开发一个红包封面生成器

使用 VUE3&#xff0c;和 Express 开发一个红包封面。 生成效果如下 赠送领取封面&#xff1a;链接 体验地址&#xff1a;https://hongbao.digitalmodel.top/

聊聊JIT优化技术

&#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是小徐&#x1f947;☁️博客首页&#xff1a;CSDN主页小徐的博客&#x1f304;每日一句&#xff1a;好学而不勤非真好学者 &#x1f4dc; 欢迎大家关注&#xff01; ❤️ 我们知道&#xff0c;想要把高级语言转变成计算…

2024年【上海市安全员C3证】考试试卷及上海市安全员C3证模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【上海市安全员C3证】考试试卷及上海市安全员C3证模拟考试题&#xff0c;包含上海市安全员C3证考试试卷答案和解析及上海市安全员C3证模拟考试题练习。安全生产模拟考试一点通结合国家上海市安全员C3证考试最新…

CS50x 2024 - Lecture 3 - Algorithms

TABLE OF CONTENTS 00:00:00 - Introduction 一种统计班上人数的方法&#xff0c;全部站起来&#xff0c;两两配对&#xff0c;一个坐下&#xff0c;循环 00:01:01 - Overview 00:02:58 - Attendance 00:09:40 - Linear Search 00:24:58 - Binary Search 二分搜索 分而治…