前言
随着ChatGPT的热度日渐增长,我也开始玩起了AI对话,但是为了不想每次使用chatgpt都需要科学上网等一系列麻烦的操作,所以我打算自己写一个Java对接chatgpt的微服务项目,接入的是chatgpt的3.5模型,但是由于chatgpt国内的限制,又为了防止自己科学上网的不稳定,所以选择对接的是一个别人创建的一个OpenAI的代理服务地址 api.openai-proxy.com
代理地址的详细信息可以访问OpenAI API 代理 (openai-proxy.com)
一、前置工作
虽然可以通过代理地址访问chatgpt,但是我们还是需要一个ApiKey,那么怎么获得ApiKey呢
可以查看这两篇文章
ChatGPT保姆级注册教学 - 掘金 (juejin.cn)
如何获取chatGPT的Api-Key - 掘金 (juejin.cn)
记得需要先科学上网,或者可以购买一个香港服务器进行代理。
二、代码实现
配置文件和依赖
配置文件
open:
ai:
url: https://api.openai-proxy.com/
## API-Key
token: xxx
session:
time: 4
token:
num: 1000
部分依赖
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
2.1、工具包(常量类和gpt工具类)
常量
public class Constant {
public static String CREATE_CHAT_COMPLETION = "v1/chat/completions";
public static String API_KEY_PREFIX = "Bearer ";
}
chatgpt工具类
@Slf4j
@Component
public class OpenAiApi {
@Value("${open.ai.url}")
private String url;
@Value("${open.ai.token}")
private String token;
@Value("${token.num}")
private int tokenNum;
/**
* gpt请求参数实体封装
*
* @param list 列表
* @param userId 用户id
* @return {@link String}
*/
public String ChatCompletionRequestBuilder(List<ChatMessage> list, String userId){
//封装gpt请求参数实体类
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model("gpt-3.5-turbo")
.messages(list)
.user(userId)
.max_tokens(tokenNum)
.temperature(1.0)
.build();
return JSONObject.toJSONString(chatCompletionRequest);
}
}
2.2、实体类(chatgpt的实体类和用户上下文以及对话的实体类)
实体类可以从保姆级JAVA对接ChatGPT教程,实现自己的AI对话助手 - 掘金 (juejin.cn)这篇文章查看,根据自己需要的实体类获取。
2.3、service层的实现
关于mapper等mp的基础操作在这里就不做过多展示,我是把数据存放在数据库中,可以根据自己的需求改造。
@Override
public ChatMessage postChatCompletion(String content, String userId) {
//封装发送的消息存到list中
final List<ChatMessage> list = userContextMapper.selectMessageForUser(userId);
ChatMessage systemMessage = new ChatMessage(ChatMessageRole.USER.value(), content);
//消息添加至上下文
list.add(systemMessage);
//获取gpt返回的内容
String json = openAiApi.post(Constant.CREATE_CHAT_COMPLETION, list, userId);
JSONObject jsonObject = JSONObject.parseObject(json);
List<ChatCompletionChoice> choices = jsonObject.getJSONArray("choices").toJavaList(ChatCompletionChoice.class);
//把内容封装到ChatMessage对象中
ChatMessage context = new ChatMessage(choices.get(0).getMessage().getRole(), choices.get(0).getMessage().getContent());
list.add(context);
return context;
}
2.4、hutool工具库调用(向gpt的api发送请求)
/**
* gpt请求发送
*
* @param path 路径
* @param list 列表
* @param userId 用户id
* @return {@link String}
*/
public String post(String path, List<ChatMessage> list, String userId) {
try {
String body = HttpRequest.post(url + path)
.header("Authorization", API_KEY_PREFIX+token)
.header("Content-Type", "application/json")
.timeout(10000)
.setReadTimeout(10000)
.body(ChatCompletionRequestBuilder(list, userId))
.execute()
.body();
if(!StringUtils.isNotBlank(body)){
throw new ChatException("返回异常");
}
log.info(body);
return body;
}catch (HttpException | ConversionException httpException){
log.info(httpException.getMessage());
}
return null;
}
总结
这篇文章是我chat服务的一个初始版,没有完成新会话和会话持久化等功能,完整代码在GitHub。
项目具体使用了SpringCloud、springsecurity、redis、minio等框架,完成了chatgpt对话上下文,使用hutool工具库进行请求,可以创建新对话或长时间后延续上次对话。
如果对我这个项目感兴趣或者想参与贡献的欢迎大家,觉得有用的记得给我的GitHub项目点个star
GitHub项目地址fsj0591/ChatBucket (github.com)