Java对接科大讯飞星火大模型V2.0实战

Java对接讯飞认知大模型教程,先注册账号领取免费测试额度

获取个人免费额度

个人免费 购买 星火认知大模型V2.0

获取秘钥

平台地址: 讯飞开放平台

image

pom.xml 文件

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.java-websocket</groupId>
        <artifactId>Java-WebSocket</artifactId>
        <version>1.3.8</version>
    </dependency>

    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.16</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.67</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

核心调用类


package com.xunfei;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.HMac;
import com.alibaba.fastjson.JSONObject;
import com.xunfei.domain.RoleContent;
import com.xunfei.domain.request.Request;
import com.xunfei.domain.request.header.Header;
import com.xunfei.domain.request.parameter.Chat;
import com.xunfei.domain.request.parameter.Parameter;
import com.xunfei.domain.request.payload.Message;
import com.xunfei.domain.request.payload.Payload;
import com.xunfei.domain.response.payload.Text;
import com.xunfei.domain.response.Result;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.UriComponentsBuilder;


import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 讯飞大模型测试类
 *
 * @author Linzj
 * @date 2023/10/19/019 16:25
 */
public class XunFeiBigModelMain {

    private static final Logger log = LoggerFactory.getLogger(XunFeiBigModelMain.class);

    /**
     * 请求地址
     */
    private static final String HOST_URL = "https://spark-api.xf-yun.com/v2.1/chat";

    /**
     * v2版本
     */
    private static final String DOMAIN_2 = "generalv2";

    /**
     * APPID
     */
    private static final String APPID = "填你自己的";

    /**
     * APISecret
     */
    private static final String API_SECRET = "填你自己的";

    /**
     * APIKey
     */
    private static final String API_KEY = "填你自己的";

    /**
     * user表示是用户的问题
     */
    private static final String ROLE_USER = "user";

    /**
     * assistant表示AI的回复
     */
    private static final String ROLE_ASSISTANT = "assistant";

    /**
     * 接口响应内容集合
     */
    private static final LinkedList<Result> RESULT_LINKED_LIST = new LinkedList<>();

    /**
     * 对话历史存储集合
     */
    public static List<RoleContent> historyList = new LinkedList<>();

    public static void main(String[] args) throws MalformedURLException, URISyntaxException {
        System.out.println("您好,这里是星火认知大模型,请问有什么可以帮您的吗?");
        while (true) {
            Scanner scanner = new Scanner(System.in);
            String content = scanner.nextLine();
            // 如果键入“结束对话”,则跳出循环,终止程序
            if (Objects.equals(content, "结束对话")) {
                System.out.println("好的,再见!");
                break;
            }
            System.out.println("我:" + content);
            websocketClient(getAuthUrl(), createReqParams(content));
        }
    }


    /**
     * websocket 连接
     *
     * @param authUrl   鉴权地址
     * @param reqParams 请求参数
     * @throws URISyntaxException 异常
     */
    private static void websocketClient(String authUrl, String reqParams) throws URISyntaxException {
        String url = authUrl.replace("http://", "ws://").replace("https://", "wss://");
        URI uri = new URI(url);
        WebSocketClient webSocketClient = new WebSocketClient(uri) {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                RESULT_LINKED_LIST.clear();
                send(reqParams);
            }

            @Override
            public void onMessage(String s) {
                // 错误码,0表示正常
                final int successCode = 0;
                // 会话状态,2代表最后一个结果
                final int lastStatus = 2;

                Result result = JSONObject.parseObject(s, Result.class);
                com.xunfei.domain.response.header.Header header = result.getHeader();
                if (Objects.equals(successCode, header.getCode())) {
                    RESULT_LINKED_LIST.add(result);
                } else {
                    log.error("大模型接口响应异常,错误码:{},sid:{}", header.getCode(), header.getSid());
                }

                // 如果是最后的结果,整合答复数据打印出来
                if (Objects.equals(lastStatus, header.getStatus())) {
                    printReply();
                }
            }

            @Override
            public void onClose(int i, String s, boolean b) {
                // log.info("WebSocket连接已关闭,原因:{},状态码:{},是否远程关闭:{}", i, s, b);
            }

            @Override
            public void onError(Exception e) {
                log.error("大模型接口调用发生异常,异常原因:{},异常位置:{}", e.getMessage(), e.getStackTrace()[0]);
            }
        };
        webSocketClient.connect();
    }

    /**
     * 生成请求参数
     *
     * @param content 对话内容
     * @return 请求参数
     */
    public static String createReqParams(String content) {
        // 组装接口请求参数
        Header header = new Header();
        header.setAppId(APPID);

        Chat chat = new Chat();
        chat.setDomain(DOMAIN_2);
        Parameter parameter = new Parameter();
        parameter.setChat(chat);

        Message message = new Message();
        if (historyList.isEmpty()) {
            com.xunfei.domain.request.payload.Text text = new com.xunfei.domain.request.payload.Text();
            text.setRole(ROLE_USER);
            text.setContent(content);
            message.setText(Collections.singletonList(text));

            // 添加历史对话集合
            RoleContent roleContent = new RoleContent();
            roleContent.setRole(ROLE_USER);
            roleContent.setContent(content);
            historyList.add(roleContent);
        } else {
            // 添加历史对话集合
            RoleContent roleContent = new RoleContent();
            roleContent.setRole(ROLE_USER);
            roleContent.setContent(content);
            historyList.add(roleContent);
            delHistory();

            List<com.xunfei.domain.request.payload.Text> textList = historyList.stream()
                    .map(item -> {
                        com.xunfei.domain.request.payload.Text text = new com.xunfei.domain.request.payload.Text();
                        text.setContent(item.getContent());
                        text.setRole(item.getRole());
                        return text;
                    })
                    .collect(Collectors.toList());
            message.setText(textList);
        }

        Payload payload = new Payload();
        payload.setMessage(message);

        Request request = new Request();
        request.setHeader(header);
        request.setParameter(parameter);
        request.setPayload(payload);
        return JSONObject.toJSONString(request);
    }


    /**
     * URL鉴权
     *
     * @return 请求url
     * @throws MalformedURLException 异常
     */
    private static String getAuthUrl() throws MalformedURLException {
        String date = DateUtil.format(new Date(), DatePattern.HTTP_DATETIME_FORMAT);
        URL url = new URL(HOST_URL);
        String preStr = "host: " + url.getHost() + "\n" +
                "date: " + date + "\n" +
                "GET " + url.getPath() + " HTTP/1.1";

        HMac hMac = SecureUtil.hmacSha256(API_SECRET.getBytes(StandardCharsets.UTF_8));
        byte[] digest = hMac.digest(preStr);
        String signature = Base64.encode(digest);
        String authorizationOrigin = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                API_KEY, "hmac-sha256", "host date request-line", signature);
        String authorization = Base64.encode(authorizationOrigin);
        return UriComponentsBuilder.fromUriString(HOST_URL)
                .queryParam("authorization", authorization)
                .queryParam("date", date)
                .queryParam("host", url.getHost()).toUriString();
    }

    /**
     * 如果历史数据太大,将前面的历史数据清除一些
     */
    public static void delHistory() {
        // 由于历史记录最大上线1.2W左右,如果最大值,删除前面的数据
        final int maxLength = 12000;
        Iterator<RoleContent> iterator = historyList.iterator();
        while (iterator.hasNext()) {
            iterator.next();
            int historyLength = historyList.stream()
                    .map(RoleContent::getContent)
                    .collect(Collectors.joining()).length();
            if (historyLength > maxLength) {
                iterator.remove();
            } else {
                break;
            }
        }
    }

    /**
     * 打印星火认知大模型回复内容
     */
    private static void printReply() {
        String content = RESULT_LINKED_LIST.stream()
                .map(item -> item.getPayload().getChoices().getText())
                .flatMap(Collection::stream)
                .map(Text::getContent)
                .collect(Collectors.joining());
        RoleContent roleContent = new RoleContent();
        roleContent.setRole(ROLE_ASSISTANT);
        roleContent.setContent(content);
        historyList.add(roleContent);
        System.out.println("星火认知大模型:" + content);
    }
}

相关文档

通用鉴权URL生成说明

其他一些实体类就不详细写了,文末有项目地址,可以自行获取,或者照着官方文档自己写一下

最终效果

image

对接完成,全部代码已提交至Gitee 讯飞大模型

posted @ 2023-10-20 15:03  Kllin  阅读(1692)  评论(4编辑  收藏  举报