ChatGLM Java SDK:智谱 AI 通用语言模型 Zhipu ChatGLM Java SDK

这篇具有很好参考价值的文章主要介绍了ChatGLM Java SDK:智谱 AI 通用语言模型 Zhipu ChatGLM Java SDK。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

智谱清言 AI 通用大语言模型 ChatGLM Java SDK - Github

此项目是由 JavaJDK11 的长期版本开发,设备环境需要 JDK >= 11


🚩 当前 ChatGLM Java SDK 最新为 0.1.1 Beta 版本。

Java Maven Dependency (BlueChatGLM)调用

<dependency>
  <groupId>top.pulselink</groupId>
  <artifactId>bluechatglm</artifactId>
  <version>0.1.1-Beta</version>
</dependency>

Java Gradle (BlueChatGLM)调用

implementation group: 'top.pulselink', name: 'bluechatglm', version: '0.1.1-Beta'

Java sbt (BlueChatGLM)调用

libraryDependencies += "top.pulselink" % "bluechatglm" % "0.1.1-Beta"

1. Utils 工具

1.1 NTP 网络时间服务器

它通过互联网或局域网上的时间服务器来提供高精度,高安全的时间信息,确保所有设备都使用相同的时间是关键的。这里的应用是对于 JWT 验证使用

//获取网络时间协议服务器(NTP Server)

    private long getNTPTime() throws IOException {
        int port = 123;
        InetAddress address = InetAddress.getByName("ntp.aliyun.com");

        try (DatagramSocket socket = new DatagramSocket()) {
            byte[] buf = new byte[48];
            buf[0] = 0x1B;
            DatagramPacket requestPacket = new DatagramPacket(buf, buf.length, address, port);
            socket.send(requestPacket);

            DatagramPacket responsePacket = new DatagramPacket(new byte[48], 48);
            socket.receive(responsePacket);

            byte[] rawData = responsePacket.getData();
            long secondsSince1900 = 0;
            for (int i = 40; i <= 43; i++) {
                secondsSince1900 = (secondsSince1900 << 8) | (rawData[i] & 0xff);
            }
            return (secondsSince1900 - 2208988800L) * 1000;
        }
    }

1.2 保存 API 密钥

保存 API 密钥并将其存储在调用 chatglm_api_key.txt 文件的本地文件中:

    private static String loadApiKey() {                    //加载 API 密钥
        try (BufferedReader reader = new BufferedReader(new FileReader(API_KEY_FILE))) {
            return reader.readLine();
        } catch (IOException e) {
            return null; // If the file doesn't exist or an error occurs, return null
        }
    }

    private static void saveApiKey(String apiKey) {           //保存 API 密钥
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(API_KEY_FILE))) {
            writer.write(apiKey);
        } catch (IOException e) {
            e.printStackTrace(); // Handle the exception according to your needs
        }
    }

1.3 保存聊天内容文件

用户聊天和 ChatGLM 回复将保存在chatglm_history.txt 中,聊天内容 txt 文件将在每个会话结束时删除。

private void createHistoryFileIfNotExists() {                //检查是否存在文件
    Path filePath = Paths.get(historyFilePath);
    if (Files.exists(filePath)) {
        try {
            Files.delete(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    try {
        Files.createFile(filePath);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

    private void registerShutdownHook() {                      //关闭程序的时候删除历史聊天记录
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                Files.deleteIfExists(Paths.get(historyFilePath));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }));
    }

2. 易于使用的 SDK

2.1 易于调用且使用的 Java Maven 库

相对于很多人来说,使用这个 SDK 的难度较低🤩。以下的三个示例是使用 Scanner 输入你的问题,控制台将输出 ChatGLM 回答:

调用SSE请求,示例代码如下 (目前已解决无法输入中文等问题,可以正常使用):

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String apiKeyss = loadApiKey();                          //加载 API 密钥

        if (apiKeyss == null) {                                  //如果不存在文件或者密钥为空,则需要输入密钥
            System.out.println("Enter your API key:");
            apiKeyss = scanner.nextLine();
            saveApiKey(apiKeyss);
        }

        while (scanner.hasNext()) {
            String userInput = scanner.nextLine();

             ChatClient chats = new ChatClient(apiKeyss);      //初始 ChatClient (实例化)
             chats.registerShutdownHook();                     //删除聊天的历史文件
             chats.SSEInvoke(userInput);                    //将你输入的问题赋值给流式请求的
             System.out.print(chats.getResponseMessage()); //打印出 ChatGLM 的回答内容
            System.out.println();
        }
    }

调用异步请求,示例代码如下:

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String apiKeyss = loadApiKey();                          //加载 API 密钥

        if (apiKeyss == null) {                                  //如果不存在文件或者密钥为空,则需要输入密钥
            System.out.println("Enter your API key:");
            apiKeyss = scanner.nextLine();
            saveApiKey(apiKeyss);
        }
        while (scanner.hasNext()) {
            String userInput = scanner.nextLine();

             ChatClient chats = new ChatClient(apiKeyss);      //初始 ChatClient (实例化)
             chats.registerShutdownHook();                     //删除聊天的历史文件
             chats.AsyncInvoke(userInput);                    //将你输入的问题赋值给异步请求的
             System.out.print(chats.getResponseMessage()); //打印出 ChatGLM 的回答内容
            System.out.println();
        }
    }

调用同步请求,示例代码如下:

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String apiKeyss = loadApiKey();                          //加载 API 密钥

        if (apiKeyss == null) {                                  //如果不存在文件或者密钥为空,则需要输入密钥
            System.out.println("Enter your API key:");
            apiKeyss = scanner.nextLine();
            saveApiKey(apiKeyss);
        }
        while (scanner.hasNext()) {
            String userInput = scanner.nextLine();

             ChatClient chats = new ChatClient(apiKeyss);      //初始 ChatClient (实例化)
             chats.registerShutdownHook();                     //删除聊天的历史文件
             chats.SyncInvoke(userInput);                    //将你输入的问题赋值给同步请求的
             System.out.print(chats.getResponseMessage()); //打印出 ChatGLM 的回答内容
            System.out.println();
        }
    }

2.2 资深开发者👨🏼‍💻

对于资深开发者,我们会后续跟进开发工作,目前的版本是 ChatGLM 4 的语言模型版本,并且已经解决了SSE中文输入看不懂的问题,当然我们也希望其他的开发商为本项目提供技术支持! 先感谢您!


3.项目介绍

CustomJWT 是对于这个项目的自定制而写的,后期会继续开发更新,拓展这个项目

根据 JWT.io 这个网站进行了解以及原理的学习,对于这个项目的JWT 验证,Java实现起来还是较容易实现的,其中使用的部分是 Base64Url 而不是常规的 Base64

编码 Base64Url 使用的编辑如下:

private String encodeBase64Url(byte[] data) {
        String base64url = Base64.getUrlEncoder().withoutPadding().encodeToString(data);  //将输入的内容转换成 Base64Url
        return base64url;             //返回 base64url
    }

创建 JWT,实现 Header 验证:

protected String createJWT() {
        String encodedHeader = encodeBase64Url(header.getBytes());
        String encodedPayload = encodeBase64Url(payload.getBytes());
        String toSign = encodedHeader + "." + encodedPayload;

        byte[] signatureBytes = generateSignature(toSign, secret, algorithm);
        String calculatedSignature = encodeBase64Url(signatureBytes);
        return toSign + "." + calculatedSignature;
    }

验证 JWT 签名部分是否与输出的结果一致:

protected boolean verifyJWT(String jwt) {
        jwt = jwt.trim();

        String[] parts = jwt.split("\\.");
        if (parts.length != 3) {
            return false;
        }

        String encodedHeader = parts[0];
        String encodedPayload = parts[1];
        String signature = parts[2];

        String toVerify = encodedHeader + "." + encodedPayload;
        byte[] calculatedSignatureBytes = generateSignature(toVerify, secret, algorithm);
        String calculatedSignature = encodeBase64Url(calculatedSignatureBytes);

        return calculatedSignature.equals(signature);
    }
 

请求调用🌐

同步请求SSE请求中使用的请求方式如下:

HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(apiUrl))
                .header("Accept", "application/json")
                .header("Content-Type", "application/json;charset=UTF-8")
                .header("Authorization", "Bearer " + token)
                .POST(HttpRequest.BodyPublishers.ofString(jsonRequestBody))
                .build();

使用 POST 方法制作 jsonRequestBody ,如下文所示(同步方法的 Stream 为 false):

String jsonRequestBody = String.format("{\"model\":\"%s\", \"messages\":[{\"role\":\"%s\",\"content\":\"%s\"},{\"role\":\"%s\",\"content\":\"%s\"}], \"stream\":false,\"temperture\":%f,\"top_p\":%f}", Language_Model, system_role, system_content, user_role, message, temp_float, top_p_float);
SSE 流式传输模型(可以正常使用!完美支持)

这里我们将使用 concurrent.Flow 方法来解决SSE流处理的问题:

public class SSESubscriber implements Flow.Subscriber<String> {

        private Flow.Subscription subscription;

        @Override
        public void onSubscribe(Flow.Subscription subscription) {
            this.subscription = subscription;
            subscription.request(1);
        }

        @Override
        public void onNext(String item) {
            if (item.startsWith("data: ")) {
                String jsonData = item.substring("data: ".length());
                //System.out.println("Received SSE item: " + jsonData); //Debug

                if (!jsonData.equals("[DONE]")) {
                    responseDataBody(jsonData.replaceAll("Invalid JSON format: \\[\"DONE\"\\]", ""));
                }
            }
            subscription.request(1);
        }

        @Override
        public void onError(Throwable throwable) {
            System.out.println("Error in SSESubscriber: " + throwable.getMessage());
        }

        @Override
        public void onComplete() {
            //System.out.println("SSESubscriber completed");
        }
    }

并在此处调用并接收 chatglm-4 消息:

try (JsonReader jsonReader = new JsonReader(new StringReader(responseData))) {
            jsonReader.setLenient(true);
            JsonElement jsonElement = JsonParser.parseReader(jsonReader);

            if (jsonElement.isJsonObject()) {
                JsonObject jsonResponse = jsonElement.getAsJsonObject();

                if (jsonResponse.has("choices")) {
                    JsonArray choices = jsonResponse.getAsJsonArray("choices");

                    if (!choices.isEmpty()) {
                        JsonObject choice = choices.get(0).getAsJsonObject();

                        if (choice.has("delta")) {
                            JsonObject delta = choice.getAsJsonObject("delta");

                            if (delta.has("content")) {
                                String content = delta.get("content").getAsString();
                                getMessage = convertUnicodeEmojis(content);
                                getMessage = getMessage.replaceAll("\"", "")
                                        .replaceAll("\\\\n\\\\n", "\n")
                                        .replaceAll("\\\\nn", "\n")
                                        .replaceAll("\\n", "\n")
                                        .replaceAll("\\\\", "")
                                        .replaceAll("\\\\", "");

                                for (char c : getMessage.toCharArray()) {
                                    charQueue.offer(c);
                                }

                                while (!charQueue.isEmpty()) {
                                    queueResult.append(charQueue.poll());
                                }
                            }
                        }
                    }
                }
            } else {
                System.out.println("Invalid JSON format: " + jsonElement);
            }
        } catch (IOException e) {
            System.out.println("Error reading JSON: " + e.getMessage());
        }
异步请求传输模型(AsyncInvokeModel:推荐使用,速度快)

这里采用的是HTTPRequest方法,来接收消息:

String jsonRequestBody = String.format("{\"model\":\"%s\", \"messages\":[{\"role\":\"%s\",\"content\":\"%s\"},{\"role\":\"%s\",\"content\":\"%s\"}],\"temperture\":%f,\"top_p\":%f}",
                Language_Model, system_role, system_content, user_role, message, temp_float, top_p_float);

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(apiUrl))
                .header("Accept", "application/json")
                .header("Content-Type", "application/json;charset=UTF-8")
                .header("Authorization", "Bearer " + token)
                .POST(HttpRequest.BodyPublishers.ofString(jsonRequestBody))
                .build();

整体使用的是异步发送信息,这样的好处是可以减少线程阻塞,这里的codestatus是获取错误消息。当你得到一个request_id 的时候,再进行查询

                    if (response.statusCode() == 200) {      //When the response value is 200, output the corresponding parameters of the interface for an asynchronous request.
                        processResponseData(response.body());
                        return CompletableFuture.completedFuture(response.body());
                    } else {
                        JsonObject errorResponse = JsonParser.parseString(response.body()).getAsJsonObject();
                        if (errorResponse.has("id") && errorResponse.has("task_status")) {
                            int code = errorResponse.get("id").getAsInt();
                            String status = errorResponse.get("task_status").getAsString();
                            throw new RuntimeException("HTTP request failure, Your request id is: " + code + ", Status: " + status);
                        } else {
                            return CompletableFuture.failedFuture(new RuntimeException("HTTP request failure, Code: " + response.statusCode()));
                        }
                    }
                });

当你得到需要的Task_id的时候,进行GET请求查询(部分代码):

                .....略 .sendAsync(HttpRequest.newBuilder()
                        .uri(URI.create(checkUrl + ID))
                        .header("Accept", "application/json")
                        .header("Content-Type", "application/json;charset=UTF-8")
                        .header("Authorization", "Bearer " + token)
                        .GET()
                        .build(), HttpResponse.BodyHandlers.ofString())
                .thenCompose(response -> {
                    if (response.statusCode() == 200) {
                        return CompletableFuture.completedFuture(response.body());
                    } else {
                        return CompletableFuture.failedFuture(new RuntimeException("HTTP request failure, Code: " + response.statusCode()));
                    }
                });

最后通过JSON的提取,提取代码示例为:

try {
            JsonObject jsonResponse = JsonParser.parseString(responseData).getAsJsonObject();

            if (jsonResponse.has("choices")) {
                JsonArray choices = jsonResponse.getAsJsonArray("choices");

                if (!choices.isEmpty()) {
                    JsonObject choice = choices.get(0).getAsJsonObject();

                    if (choice.has("message")) {
                        JsonObject message = choice.getAsJsonObject("message");

                        if (message.has("content")) {
                            String content = message.get("content").getAsString();
                            getMessage = convertUnicodeEmojis(content);
                            getMessage = getMessage.replaceAll("\"", "")
                                    .replaceAll("\\\\n\\\\n", "\n")
                                    .replaceAll("\\\\nn", "\n")
                                    .replaceAll("\\n", "\n")
                                    .replaceAll("\\\\", "")
                                    .replaceAll("\\\\", "");
                        }
                    }
                }
            }
        } catch (JsonSyntaxException e) {
            System.out.println("Error processing task status: " + e.getMessage());
        }
同步请求传输模型(InvokeModel:推荐使用,速度较快)

同步请求还算不错,运行的时候一般情况下都还算快,当然同步的缺点就是请求量过大可能会阻塞线程(单线程

这里直接说明关于处理信息这一块,这一块就是解析 JSON 也没有其他的东西了,示例代码:

try {
            JsonObject jsonResponse = JsonParser.parseString(responseData).getAsJsonObject();

            if (jsonResponse.has("choices")) {
                JsonArray choices = jsonResponse.getAsJsonArray("choices");

                if (!choices.isEmpty()) {
                    JsonObject choice = choices.get(0).getAsJsonObject();

                    if (choice.has("message")) {
                        JsonObject message = choice.getAsJsonObject("message");

                        if (message.has("content")) {
                            String content = message.get("content").getAsString();
                            getMessage = convertUnicodeEmojis(content);
                            getMessage = getMessage.replaceAll("\"", "")
                                    .replaceAll("\\\\n\\\\n", "\n")
                                    .replaceAll("\\\\nn", "\n")
                                    .replaceAll("\\n", "\n")
                                    .replaceAll("\\\\", "")
                                    .replaceAll("\\\\", "");
                        }
                    }
                }
            }
        } catch (JsonSyntaxException e) {
            System.out.println("Error processing task status: " + e.getMessage());
        }

总体下来,介绍本项目三种请求方式应该还是相对简单,如果有任何问题,可以在 Issue 处发起讨论🥳,也希望各路大神的对这个项目的支援!再次感谢🎉!


4.结语

感谢您打开我的项目,这是一个自主开发 ChatGLM Java SDK 的开发项目,为了解决官方的 SDK 存在的问题我也在努力开发和更新这个项目,当然我个人也会继续开发这个项目,我也比较坚持开源的原则,毕竟白嫖不香嘛(doge)。最后也希望越来越多的人一起参与开发🚀 ,最后如果喜欢的朋友,可以打开我的这个 ChatGLM Java SDK 项目 帮我点个 ⭐️ ,谢谢大家看到最后!😆👏


最后的最后感恩 gson 的 jar 包开发人员👩‍💻👨‍💻文章来源地址https://www.toymoban.com/news/detail-828211.html

到了这里,关于ChatGLM Java SDK:智谱 AI 通用语言模型 Zhipu ChatGLM Java SDK的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【chatglm3】(4):如何设计一个知识库问答系统,参考智谱AI的知识库系统,

    https://www.bilibili.com/video/BV16j411E7FX/?vd_source=4b290247452adda4e56d84b659b0c8a2 【chatglm3】(4):如何设计一个知识库问答系统,参考智谱AI的知识库系统,学习设计理念,开源组件 https://open.bigmodel.cn/knowledge 知识配置: 项目地址是: https://github.com/chatchat-space/Langchain-Chatchat gitee搬运的项

    2024年02月05日
    浏览(48)
  • 智谱 GLM-4 大语言模型好用吗?

    我替你尝试了它的基本对话、绘图、阅读长文档、数据分析和高级联网等几方面能力。 最近智谱的 GLM-4 大语言模型发布,成为了热门话题。一篇文章不断出现在我的朋友圈和各种群聊中。 这篇文章是由新智元发布的,介绍了GLM-4的特性。文章兴奋地宣称,现在我们也有了国

    2024年01月20日
    浏览(54)
  • CogVLM:智谱AI 新一代多模态大模型

    自 5 月 18 日发布并开源 VisualGLM-6B 以来,智谱AI清华KEG潜心打磨,致力于开发更加强大的多模态大模型。 基于对视觉和语言信息之间融合的理解,我们提出了一种新的视觉语言基础模型 CogVLM。CogVLM 可以在不牺牲任何 NLP 任务性能的情况下,实现视觉语言特征的深度融合。 我

    2024年01月21日
    浏览(55)
  • 英特尔集成显卡+ChatGLM3大语言模型的企业本地AI知识库部署

    作者: 英特尔创新大使 刘力 英特尔开发者技术推广经理 李翊玮     在当今的企业环境中,信息的快速获取和处理对于企业的成功至关重要。为了满足这一需求,我们可以将RAG技术与企业本地知识库相结合,以提供实时的、自动生成的信息处理和决策支持。这将有助于企业

    2024年04月26日
    浏览(52)
  • 从AI人工智能LLM大型语言模型到通用人工智能AGI “世界模型”的演进路径

    近年来,人工智能技术取得了飞速的发展,各种领域都出现了涉及人工智能的应用。大型语言模型(Large Language Model, LLM)作为其中一种重要的技术手段,已成为当前自然

    2024年02月08日
    浏览(92)
  • 【AI理论学习】语言模型Performer:一种基于Transformer架构的通用注意力框架

    Performer是一种用于高效处理自注意力机制(Self-Attention)的神经网络架构 。自注意力机制在许多自然语言处理和计算机视觉任务中

    2024年02月09日
    浏览(48)
  • LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言

    目录 引言 代码完整地址 入参  出参 Controller Service Service实现类  模型Service  入参转换类 文心一言实现类 讯飞星火实现类  通义千问实现类 智谱清言实现类 本文将介绍如何使用Java语言,结合Spring Boot框架,集成国内热门大模型API,包括文心一言、讯飞星火、通义千问、智

    2024年04月12日
    浏览(49)
  • 智谱AI技术开放日:新一代基座大模型GLM-4及GLMs的发布

    2024年1月16日,智谱AI举行了一次重要的技术开放日,发布了新一代基座大模型GLM-4和定制化的大模型GLMs。此次发布标志着智谱AI在人工智能领域的新一轮突破,进一步提升了大模型的性能,并降低了使用门槛,使得更多的人能够参与到AI的广泛应用中来。 GLM-4模型是智谱AI全自

    2024年01月16日
    浏览(51)
  • 【开源】给ChatGLM写个,Java对接的SDK

    作者:小傅哥 - 百度搜 小傅哥bugstack 博客:bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!😄 大家好,我是技术UP主小傅哥。 清华大学计算机系的超大规模训练模型 ChatGLM-130B 使用效果非常牛,所以我也想把这样的Ai能力接入到自己的应用中或者做一些 IntelliJ I

    2024年02月04日
    浏览(47)
  • 【金猿案例展】智谱AI——基于全闪分布式并行文件存储打造高速大模型训练平台...

    ‍ 焱融科技案例 本项目案例由焱融科技投递并参与“数据猿年度金猿策划活动——2023大数据产业年度创新服务企业榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 · 改变商业 自 ChatGPT 爆火以来,中国的 AI 产业已经进入名副其实的“百模大战”。《中国人工智能

    2024年02月02日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包