AIGC: 关于ChatGPT中基于API实现一个Client客户端

Java版的GPT的Client

  • 可作为其他编程语言的参考
  • 注意: 下面包名中的 xxx 可以换成自己的

1 )核心代码结构设计

  • src
    • main
      • java
        • com.xxx.gpt.client
          • entity
            • ChatCompletion.java
            • ChatCompletionResponse.java
            • ChatChoice.java
          • util
            • Proxys.java
          • ChatApi.java
          • ChatGPTClient.java
    • test
      • java
        • com.xxx.gpt.client.test
          • ChatGPTClientTest.java
  • pom.xml

2 ) pom 文件

  • 在 pom 文件里面,我们引入了我们需要引用的依赖
    • 对于 OpenAI 的API访问,由于它是一个HTTP的接口
    • 我们使用的是 okhttp-see
    • 然后通过 retrofit 进行一个封装
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>gpt-client</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version><scope>compile</scope><optional>true</optional></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.7</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.3.7</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.3.7</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.19</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.33</version></dependency><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp-sse</artifactId><version>3.14.9</version></dependency><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>logging-interceptor</artifactId><version>3.14.9</version></dependency><dependency><groupId>com.squareup.retrofit2</groupId><artifactId>retrofit</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.squareup.retrofit2</groupId><artifactId>converter-jackson</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.squareup.retrofit2</groupId><artifactId>adapter-rxjava2</artifactId><version>2.9.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>com.knuddels</groupId><artifactId>jtokkit</artifactId><version>0.4.0</version></dependency></dependencies>
</project>

3 )entity 目录

  • 在这个包里面,开发了核心的chat completion相关接口
    • 比如对于我们的ChatCompletion请求的一些参数
      • 包括 model,包括需要传入的message和temperature以及top_p, functioncall等等的这些参数
    • 然后对于它的返回值: ChatCompletionResponse 程序里面
      • 包括 id, object, created, model, choice, usage
    • 对于ChatChoice, 里面包含 delta, message 和 finishReason
  • 这几个类和我们前面去访问 OpenAI 它的API文档里面所对应的相关的属性是一致的
    • 这部分照着 API 手册去进行一下相关实体类的开发就可以了

ChatCompletion.java

package com.xxx.gpt.client.entity;import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.xxx.gpt.client.util.TokensUtil;
import lombok.Builder;
import lombok.Data;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;import java.io.Serializable;
import java.util.List;
import java.util.Map;@Data
@Builder
@Slf4j
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ChatCompletion implements Serializable {@NonNull@Builder.Defaultprivate String model = Model.GPT_3_5_TURBO_0613.getName();@NonNullprivate List<Message> messages;/*** 使用什么取样温度,0到2之间。越高越奔放。越低越保守。* <p>* 不要同时改这个和topP*/@Builder.Defaultprivate double temperature = 0.9;/*** 0-1* 建议0.9* 不要同时改这个和temperature*/@JsonProperty("top_p")@Builder.Defaultprivate double topP = 0.9;/*** auto*/String function_call;List<ChatFunction> functions;/*** 结果数。*/@Builder.Defaultprivate Integer n = 1;/*** 是否流式输出.* default:false*/@Builder.Defaultprivate boolean stream = false;/*** 停用词*/private List<String> stop;/*** 3.5 最大支持4096* 4.0 最大32k*/@JsonProperty("max_tokens")private Integer maxTokens;@JsonProperty("presence_penalty")private double presencePenalty;/*** -2.0 ~~ 2.0*/@JsonProperty("frequency_penalty")private double frequencyPenalty;@JsonProperty("logit_bias")private Map logitBias;/*** 用户唯一值,确保接口不被重复调用*/private String user;public int countTokens() {return TokensUtil.tokens(this.model, this.messages);}
}

ChatCompletionResponse.java

package com.xxx.gpt.client.entity;import lombok.Data;
import java.io.Serializable;
import java.util.List;@Data
public class ChatCompletionResponse implements Serializable {private String id;private String object;private long created;private String model;private List<ChatChoice> choices;private Usage usage;
}

ChatChoice.java

package com.xxx.gpt.client.entity;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;import java.io.Serializable;@Data
public class ChatChoice implements Serializable {private long index;/*** 请求参数stream为true返回是delta*/@JsonProperty("delta")private Message delta;@JsonProperty("message")private Message message;@JsonProperty("finish_reason")private String finishReason;
}

3 )util 目录

  • 由于国内的网络没办法直接的去进行访问, 我们添加一个 util/Proxys.java, 基于它去做一个代理
    • 里面我们提供两个方法,都是传入我们代理的IP和代理的端口
    • 然后返回 Proxy的Type是HTTP,这是对于HTTP的 Proxy
    • 再来创建一个socks的 Proxy

Proxys.java

package com.xxx.gpt.client.util;import java.net.InetSocketAddress;
import java.net.Proxy;public class Proxys {public static Proxy http(String ip, int port) {return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port));}public static Proxy socks5(String ip, int port) {return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(ip, port));}
}

4 )创建 ChatApi 接口

  • 在ChatAPI里面,我们就添加我们需要去访问的 Open AI 的接口
  • 接口是post请求,接口的URI是 v1/chat/completions
  • 返回值是我们刚刚创建的实体类 ChatCompletionResponse,参数是 ChatCompleination
  • 这是我们要访问的chatAPI它的核心的接口

ChatApi.java

package com.xxx.gpt.client;import com.xxx.gpt.client.entity.ChatCompletion;
import com.xxx.gpt.client.entity.ChatCompletionResponse;
import io.reactivex.Single;
import retrofit2.http.Body;
import retrofit2.http.POST;public interface ChatApi {String CHAT_GPT_API_HOST = "https://api.openai.com/";@POST("v1/chat/completions")Single<ChatCompletionResponse> chatCompletion(@Body ChatCompletion chatCompletion);
}

5 )添加 ChatGPTClient

  • 在这个类里面定义一些属性: apiKey, apiHost, chatApi, okHttpClient, timeout, proxy

  • 再来添加一个init方法

    • 在拦截器里添加apikey
    • 设置timeout,默认300s
    • 设置代理
    • 通过 retrofit 实例化chatapi,供我们去进行使用
  • 这样就完成了一个ChatGPTClient的一个实例化

  • 实例化完成之后呢,我们添加一个调用的方法 chatCompletion,返回值就是我们请求的response

  • 现在已经完成了java版本的ChatGPT的client

ChatGPTClient.java

package com.xxx.gpt.client;import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import com.alibaba.fastjson.JSON;
import com.xxx.gpt.client.entity.BaseResponse;
import com.xxx.gpt.client.entity.ChatCompletion;
import com.xxx.gpt.client.entity.ChatCompletionResponse;
import com.xxx.gpt.client.entity.Message;
import io.reactivex.Single;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.jackson.JacksonConverterFactory;import java.net.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Slf4j
@Getter
@Setter
@Builder
public class ChatGPTClient {private String apiKey;private List<String> apiKeyList;@Builder.Defaultprivate String apiHost = ChatApi.CHAT_GPT_API_HOST;private ChatApi apiClient;private OkHttpClient okHttpClient;/*** 超时 默认300*/@Builder.Defaultprivate long timeout = 300;/*** okhttp 代理*/@Builder.Defaultprivate Proxy proxy = Proxy.NO_PROXY;public ChatGPTClient init() {OkHttpClient.Builder client = new OkHttpClient.Builder();client.addInterceptor(chain -> {Request original = chain.request();String key = apiKey;if (apiKeyList != null && !apiKeyList.isEmpty()) {key = RandomUtil.randomEle(apiKeyList);}Request request = original.newBuilder().header(Header.AUTHORIZATION.getValue(), "Bearer " + key).header(Header.CONTENT_TYPE.getValue(), ContentType.JSON.getValue()).method(original.method(), original.body()).build();return chain.proceed(request);}).addInterceptor(chain -> {Request original = chain.request();Response response = chain.proceed(original);if (!response.isSuccessful()) {String errorMsg = response.body().string();log.error("请求异常:{}", errorMsg);BaseResponse baseResponse = JSON.parseObject(errorMsg, BaseResponse.class);if (Objects.nonNull(baseResponse.getError())) {log.error(baseResponse.getError().getMessage());throw new RuntimeException(baseResponse.getError().getMessage());}throw new RuntimeException(errorMsg);}return response;});client.connectTimeout(timeout, TimeUnit.SECONDS);client.writeTimeout(timeout, TimeUnit.SECONDS);client.readTimeout(timeout, TimeUnit.SECONDS);if (Objects.nonNull(proxy)) {client.proxy(proxy);}OkHttpClient httpClient = client.build();this.okHttpClient = httpClient;this.apiClient = new Retrofit.Builder().baseUrl(this.apiHost).client(okHttpClient).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).addConverterFactory(JacksonConverterFactory.create()).build().create(ChatApi.class);return this;}public ChatCompletionResponse chatCompletion(ChatCompletion chatCompletion) {Single<ChatCompletionResponse> chatCompletionResponse =this.apiClient.chatCompletion(chatCompletion);return chatCompletionResponse.blockingGet();}public String chat(String message) {ChatCompletion chatCompletion = ChatCompletion.builder().messages(Arrays.asList(Message.of(message))).build();ChatCompletionResponse response = this.chatCompletion(chatCompletion);return response.getChoices().get(0).getMessage().getContent();}
}

6 )添加测试类

  • 需要先对我们的client去进行实例化
  • 首先添加一下代理
  • 再来添加一个测试的方法

ChatGPTClientTest.java

package com.xxx.gpt.client.test;import com.xxx.gpt.client.ChatGPTClient;
import com.xxx.gpt.client.entity.ChatCompletion;
import com.xxx.gpt.client.entity.ChatCompletionResponse;
import com.xxx.gpt.client.entity.Message;
import com.xxx.gpt.client.entity.Model;
import com.xxx.gpt.client.util.Proxys;
import org.junit.Before;
import org.junit.Test;import java.net.Proxy;
import java.util.Arrays;public class ChatGPTClientTest {private ChatGPTClient chatGPTClient;@Beforepublic void before() {Proxy proxy = Proxys.socks5("127.0.0.1", 7890);chatGPTClient = ChatGPTClient.builder().apiKey("sk-6kchn0DjDasdsdfdqOJqkc3aIso5ct").timeout(900).proxy(proxy).apiHost("https://api.openai.com/").build().init();}@Testpublic void chat() {Message system = Message.ofSystem("你是一个作家,学习过很多古诗");Message message = Message.of("写一首关于青春的七言绝句");ChatCompletion chatCompletion = ChatCompletion.builder().model(Model.GPT_3_5_TURBO.getName()).messages(Arrays.asList(system, message)).maxTokens(3000).temperature(0.9).build();ChatCompletionResponse response = chatGPTClient.chatCompletion(chatCompletion);Message res = response.getChoices().get(0).getMessage();System.out.println(res.getContent());}// @Testpublic void tokens() {Message system = Message.ofSystem("你是一个作家,学习过很多古诗");Message message = Message.of("写一首关于青春的七言绝句");ChatCompletion chatCompletion1 = ChatCompletion.builder().model(Model.GPT_3_5_TURBO.getName()).messages(Arrays.asList(system, message)).maxTokens(3000).temperature(0.9).build();ChatCompletion chatCompletion2 = ChatCompletion.builder().model(Model.TEXT_DAVINCI_003.getName()).messages(Arrays.asList(system, message)).maxTokens(3000).temperature(0.9).build();System.out.println(chatCompletion1.countTokens());System.out.println(chatCompletion2.countTokens());}
}
  • 根据前面我们看到的API的文档,构建 Prompt(message)
  • 我们构造一个system角色的一个message
    • 告诉GPT: 你是一个作家, 写过很多诗,然后默认我们再以用户的角色去实例化一个message
    • 让GPT帮我们去写一首关于青春的七言绝句
  • 接下来构造我们的request参数
    • 设置 model,message,maxTokens,temperature
    • 之后执行 build()
  • 这里完成了让GPT根据 Prompt 创作了一首诗歌
  • 以上是 Java 版本的GPT相关核心代码(网上搜集)
  • 可以作为转换成其他编程语言实现的参考

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

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

相关文章

我有才知识付费小程序免费搭建:轻松拥有知识付费平台

用户管理 提供会员特权和积分奖励&#xff0c;提高用户忠诚度和购买力。 用户通过在平台上进行消费、签到、参与活动等方式获取积分&#xff0c;用于兑换丰厚奖品或提升会员等级。增强用户的参与感与忠诚度&#xff0c;提高用户粘性&#xff0c;并刺激用户的购买力。 为用户打…

7z命令压缩文件夹,并忽略其中某些文件夹

-xr指令表示忽略 对于.vs这样的文件夹&#xff0c;需要用双引号括起来 类似的&#xff0c;可以使用通配符忽略文件 .\7z.exe a -t7z D:\Document\Code\apps.7z D:\Document\Code\apps -xr!".vs" -xr!bin -xr!obj

编码生成规则Long increment(K key, long delta)

前端不传数据&#xff0c;像一些 需要 从后台查出来的编码的生成规则&#xff1b; 采用方法为&#xff1a;Long increment(K key, long delta) redisTemplate.opsForValue()中的方法都定义在ValueOperations<K, V> 中&#xff0c;该接口中一共有17个方法&#xff1a; …

Arduino学习笔记2023年11月30日

目录 1 编程软件下载2 代码结构3 IO引脚控制3.1 引脚初始化3.2 引脚使用数字量输出数字量输入模拟量输出模拟量输入 4 串口串口初始化串口输出串口输入 5 外部中断6 函数6.1 映射区间函数6.2 延时函数 总结 1 编程软件下载 官网链接&#xff1a;https://www.arduino.cc/ 下载链…

SpringBoot 配置文件使用@ @取值

目录 一、背景 二、遇到的问题 三、解决办法 一、背景 &#xff08;1&#xff09;我在项目中引入了如下依赖&#xff0c;目的是开启SpringBoot为我们提供的监控(Actuator)功能。 <!-- 引入SpringBoot 监控功能 --> <dependency><groupId>org.springframew…

PWM控制器电路D9741,定时闩锁、短路保护电路,输出基准电压(2.5V) 采用SOP16封装形式

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点&#xff1a;● 高精度基准电路 ● 定时闩锁、短路保护电路 ● 低电压输入时误操作保护电路 ● 输出基准电…

Linux服务器部署XXL-JOB

参考文档及下载地址&#xff1a;分布式任务调度平台XXL-JOB 1 从git拉取XXL-JOB代码 我们的大部分变动&#xff0c;是发生在xxl-job-admin&#xff0c;最终将这个模块打包成jar包部署在linux服务器上。 2 执行数据库脚本 doc\db\tables_xxl_job.sql 3 修改pom文件&#xff0c…

golang常用库之-操作sqlite数据库

文章目录 一、sqlite使用sqlite3命令行工具创建数据库&#xff0c;查询数据 二、关于mattn/go-sqlite3三、mattn/go-sqlite3使用四、go 使用sqlite常见问题总结window下编译报错&#xff1a;Binary was compiled with CGO_ENABLED0, go-sqlite3 requirewindow下编译报错&#x…

线程池原理初探

1.引言 合理利用线程池能够带来三个好处。第一&#xff1a;降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二&#xff1a;提高响应速度。当任务到达时&#xff0c;任务可以不需要的等到线程创建就能立即执行。第三&#xff1a;提高线程的可管理性。…

逗号表达式

exp1, exp2, exp3, …expN 逗号表达式&#xff0c;就是用逗号隔开的多个表达式。逗号表达式&#xff0c;从左向右依次执行。整个表达式的结果是最后一个表达式的结果。 代码示例&#xff1a; #include <stdio.h>int main() {int a 5;int b 3;int c (a > b, a b …

re:Invent 云端历程:我与 2023 亚马逊云科技 re:Invent 大会

每年的11月&#xff0c;科技界的精英们汇聚在拉斯维加斯&#xff0c;参与亚马逊云科技 re:Invent 大会&#xff0c;这个一年一度的科技盛宴。我也是其中的一员&#xff0c;深深感受到这场盛会给我带来的启发和收获。 1. 我和 re:Invent 大会的故事 参加 re:Invent 大会是一次…

哈希表【1】

文章目录 &#x1f914;0.哈希表&#x1f33c;1. 两数之和&#x1f33b;1. 题目&#x1f337;2. 算法原理&#x1f33a;3. 代码实现 &#x1f348;面试题 01.02. 判定是否互为字符重排&#x1f34c;1. 题目&#x1f34f;2. 算法原理&#x1f353;3. 代码实现 &#x1f914;0.哈…

Cmake时遇到Could Not find CURL问题

操作系统&#xff1a;Ubuntu 20.04 cmake编译的时候&#xff0c;出现下述错误Could Not find CURL。 结合上述错误&#xff0c;又去看了CMakelist文件&#xff0c;看到CURL的最小版本需要7.28.0。 首先确认一下自己的curl是否安装&#xff0c;版本号是多少&#xff0c;结果如下…

已知线段的两端点a、b,求线段外一点到线段的距离

公式推导过程已经不存在 仅剩下代码 贴出来&#xff0c;方便使用 // 计算点p到直线a,b的距离&#xff0c;OpenCVstatic float distancePointToLineCV(const cv::Point2f& p, const cv::Point2f& a, const cv::Point2f& b){float v1 std::fabs((b.y - a.y) * p.x…

Pytest接口自动化测试框架搭建模板

auto_api_test 开发环境: Pycharm 开发语言&版本: python3.7.8 测试框架: Pytest、测试报告: Allure 项目源码Git地址 项目目录结构 api – 模仿PO模式, 抽象出页面类, 页面类内包含页面所包含所有接口, 并封装成方法可供其他模块直接调用config – 配置文件目录data…

学习设计模式的网站

Refactoring and Design Patternshttps://refactoring.guru/

vue.js怎么保证计算精度

为什么js计算会丢失精度&#xff1f; JavaScript 中的精度丢失问题通常出现在处理浮点数时。 这是因为 JavaScript 使用双精度浮点数格式&#xff08;64位&#xff09;&#xff0c;无法精确表示所有的小数。举例来说&#xff0c;尝试计算 0.1 0.2 会得到一个近似值 0.300000…

华为云RDS通用型(x86) vs 鲲鹏(ARM)架构的性能对比

概述 之前&#xff0c;我们对比了阿里云RDS的经济版&#xff08;ARM&#xff09;与x86版的性价比&#xff0c;这次我们来看看华为云的RDS MySQL的“通用型”(x86)与“鲲鹏通用增强型”(ARM)版本的情况如何。 这里依旧选择了用户较为常用的4c16g的规格进行测试&#xff0c;测试…

【Rust与AI】概览和方向

本系列主要介绍Rust与AI的那些天作之合&#xff08;开源项目&#xff09;&#xff0c;我们会以开源项目代码阅读的方式推进&#xff0c;以Rust为主&#xff0c;同时科普AI相关知识&#xff0c;目的是让更多非算法、非Rust的程序员进一步学习Rust和AI相关知识。当然&#xff0c;…

【Python】 pip 常用命令及相关作用和使用场景

pip是Python的包管理工具&#xff0c;它允许开发者安装、升级和管理Python软件包。以下是一些常用的pip命令&#xff1a; 1. **列出已安装的包**&#xff1a; pip list 或者 pip freeze 2. **安装包**&#xff1a; pip install [package-name]…