超级详细 JAVA 对接 ChatGPT 教程,实现自己的AI对话小助手

维基框架 2024-07-01 09:31:02 阅读 52

1     前言

大家好,由于近期需要对接了ChatGPT API所以特地记录下来,据介绍该模型是和当前官网使用的相同的模型,如果你还没体验过ChatGPT,那么今天就教大家如何打破网络壁垒,打造一个属于自己的智能助手把。本文包括API Key的申请以及网络代理的搭建,那么事不宜迟,我们现在开始。

若有想体验的可联系我获取体验账号。

2     对接流程

2.1  API-Key的获取


首先第一步要获取OpenAI接口的API Key,该Key是你用来调用接口的token,主要用于接口鉴权。获取该key首先要注册OpenAi的账号。

2.1.1      打开platform.openai.com网站,点击view API Key

2.1.2      点击创建key

2.1.3      弹窗显示生成的key,记得把key复制,不然等会就找不到这个key了,只能重新创建

将API Key保存好以备用

2.2  API用量的查看

 这里可以查看API的使用情况,新账号注册默认有5美元的试用额度,之前都是18美元,API成本降了之后试用额度也狠狠地砍了一刀。

2.3  核心代码实现

2.3.1      pom依赖

其中引入包cdkj-core请参考另一开源项目 维基框架

<?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">

<parent>

<artifactId>framewiki-gpt</artifactId>

<groupId>com.framewiki.gpt</groupId>

<version>1.0.0</version>

</parent>

<modelVersion>4.0.0</modelVersion>

<artifactId>gpt-util</artifactId>

<dependencies>

<dependency>

<groupId>com.cdkjframework</groupId>

<artifactId>cdkj-core</artifactId>

</dependency>

<dependency>

<groupId>com.cdkjframework</groupId>

<artifactId>cdkj-util</artifactId>

</dependency>

<dependency>

<groupId>commons-httpclient</groupId>

<artifactId>commons-httpclient</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-validation</artifactId>

</dependency>

</dependencies>

</project>

2.3.2      实体类ChatMessagesDto.java

用于存放发送的消息信息,注解使用了lombok,如果没有使用lombok可以自动生成构造方法以及get和set方法

package com.framewiki.gpt.dto.response;

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto

* @ClassName: ChatMessagesDto

* @Description: java类作用描述

* @Author: xiaLin

* @Date: 2023/6/10 22:30

* @Version: 1.0

*/

@Data

@NoArgsConstructor

@AllArgsConstructor

public class ChatMessagesDto {

/**

* 消息角色

* system

* user

* assistant

*/

private String role;

/**

* 消息内容

*/

private String content;

}

2.3.3      实体类CreateChatCompletionDto.java

package com.framewiki.gpt.dto.request;

import lombok.Data;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto.request

* @ClassName: CreateChatCompletionDto

* @Description: java类作用描述

* @Author: xiaLin

* @Date: 2023/6/21 22:07

* @Version: 1.0

*/

@Data

public class CreateChatCompletionDto {

/**

* 内容

*/

private String content;

/**

* 模型

*/

private String model;

/**

* 用户

*/

private String user;

}

2.3.4      实体类ChatCompletionRequestDto.java

用于发送的请求的参数实体类,参数释义如下:

package com.framewiki.gpt.dto.request;

import com.alibaba.fastjson.annotation.JSONField;

import com.framewiki.gpt.dto.response.ChatMessagesDto;

import lombok.Builder;

import lombok.Data;

import java.math.BigDecimal;

import java.util.List;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto

* @ClassName: ChatCompletionRequestDto

* @Description: 请求实体

* @Author: xiaLin

* @Date: 2023/6/10 22:27

* @Version: 1.0

*/

@Data

@Builder

public class ChatCompletionRequestDto {

/**

* 模型

* gpt-4

* gpt-4-0314

* gpt-4-32k

* gpt-4-32k-0314

* gpt-3.5-turbo

* gpt-3.5-turbo-0301

*/

private String model;

/**

* 温度,参数从0-2,越低表示越精准,越高表示越广发,回答的内容重复率越低

*/

private BigDecimal temperature;

/**

* 消息

*/

private List<ChatMessagesDto> messages;

/**

* 回复条数,一次对话回复的条数

*/

private Integer n;

/**

* 是否流式处理,就像ChatGPT一样的处理方式,会增量的发送信息。

*/

private Boolean stream;

/**

* 状态

*/

private List<String> stop;

/**

* 生成的答案允许的最大token数

*/

@JSONField(name = "max_tokens")

private Integer maxTokens;

/**

* 对话用户

*/

private String user;

}

2.3.5      实体类ChatCompletionResponseDto.java

用于接收请求返回的信息以及执行结果

package com.framewiki.gpt.dto.response;

import lombok.Data;

import java.util.List;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto

* @ClassName: ChatCompletionResponseDto

* @Description: 响应

* @Author: xiaLin

* @Date: 2023/6/16 23:18

* @Version: 1.0

*/

@Data

public class ChatCompletionResponseDto {

/**

* ID

*/

private String id;

/**

* 返回的内容

*/

private String object;

/**

* 模型

*/

private String model;

/**

* 创建时间

*/

private long created;

/**

* 用户

*/

private String user;

/**

* 选择

*/

private List<ChatCompletionChoiceDto> choices;

/**

* 用量

*/

private ChatCompletionUsageDto usage;

}

2.3.6      实体类ChatCompletionUsageDto.java

package com.framewiki.gpt.dto.response;

import com.alibaba.fastjson.annotation.JSONField;

import lombok.Data;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto

* @ClassName: ChatCompletionUsageDto

* @Description: 用量信息

* @Author: xiaLin

* @Date: 2023/6/16 22:44

* @Version: 1.0

*/

@Data

public class ChatCompletionUsageDto {

/**

* 输入 token 数量

*/

@JSONField(name = "prompt_tokens")

private int promptTokens;

/**

* 完成 token数量

*/

@JSONField(name = "completion_tokens")

private int completionTokens;

/**

* token 总数

*/

@JSONField(name = "total_tokens")

private int totalTokens;

}

2.3.7      实体类ChatCompletionChoiceDto.java

用于接收ChatGPT返回的数据

package com.framewiki.gpt.dto.response;

import lombok.Data;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.dto

* @ClassName: ChatCompletionChoiceDto

* @Description: java类作用描述

* @Author: xiaLin

* @Date: 2023/6/16 22:44

* @Version: 1.0

*/

@Data

public class ChatCompletionChoiceDto {

/**

* 搜索

*/

private Integer index;

/**

* 消息

*/

private ChatMessagesDto message;

/**

* 完成的原因

*/

private String finishReason;

}

2.3.8      接口调用核心类ChatServiceImpl.java

使用HttpURLConnection用于进行api接口的调用,支持post和get方法请求。

url为配置文件open.ai.url的值,表示调用api的地址:https://api.openai.com/ ,token为获取的api-key。

执行post或者get方法时增加头部信息headers.put("Authorization", "Bearer " + token); 用于通过接口鉴权。

package com.framewiki.gpt.service.impl;

import com.cdkjframework.constant.EncodingConsts;

import com.cdkjframework.constant.IntegerConsts;

import com.cdkjframework.entity.http.HttpRequestEntity;

import com.cdkjframework.enums.HttpMethodEnums;

import com.cdkjframework.util.log.LogUtils;

import com.cdkjframework.util.network.http.HttpRequestUtils;

import com.cdkjframework.util.tool.StringUtils;

import com.framewiki.gpt.config.ChatConfig;

import com.framewiki.gpt.config.ChatConfiguration;

import com.framewiki.gpt.dto.request.ChatCompletionRequestDto;

import com.framewiki.gpt.dto.request.CreateChatCompletionDto;

import com.framewiki.gpt.dto.response.ChatCompletionResponseDto;

import com.framewiki.gpt.dto.response.ChatMessagesDto;

import com.framewiki.gpt.service.ChatService;

import lombok.RequiredArgsConstructor;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.service.impl

* @ClassName: ChatServiceImpl

* @Description: java类作用描述

* @Author: xiaLin

* @Date: 2023/6/16 22:58

* @Version: 1.0

*/

@Service

@RequiredArgsConstructor

public class ChatServiceImpl implements ChatService {

/**

* 日志

*/

private LogUtils logUtils = LogUtils.getLogger(ChatServiceImpl.class);

/**

* 配置信息

*/

private final ChatConfiguration configuration;

/**

* 地址

*/

private final ChatConfig chatConfig;

/**

* 创建对话

*

* @param content 消息内容

*/

@Override

public ChatCompletionResponseDto createChatCompletion(CreateChatCompletionDto content) {

if (StringUtils.isNullAndSpaceOrEmpty(content.getModel())) {

content.setModel(model);

}

List<ChatMessagesDto> messages = new ArrayList<>();

ChatMessagesDto systemMessage = new ChatMessagesDto(role, content.getContent());

messages.add(systemMessage);

ChatCompletionRequestDto chatCompletionRequest = ChatCompletionRequestDto.builder()

.model(content.getModel())

.messages(messages)

.user(content.getUser())

.maxTokens(IntegerConsts.ONE_HUNDRED * IntegerConsts.FIVE)

.temperature(BigDecimal.ONE)

.build();

HttpRequestEntity request = new HttpRequestEntity();

request.setRequestAddress(chatConfig.getCreateChatCompletion());

request.setMethod(HttpMethodEnums.POST);

request.setData(chatCompletionRequest);

request.setCharset(EncodingConsts.UTF8);

// 请求头

Map<String, String> headerMap = new HashMap<>(IntegerConsts.ONE);

headerMap.put(AUTHORIZATION, BEARER + configuration.getOpenaiApiKey());

request.setHeaderMap(headerMap);

ChatCompletionResponseDto response = null;

try {

response = HttpRequestUtils.httpRequest(request, ChatCompletionResponseDto.class);

response.setUser(content.getUser());

} catch (Exception e) {

logUtils.error(e);

}

// 返回结果

return response;

}

}

2.3.9      定义接口常量配置类ChatConfig.class

用于维护支持的api接口列表

package com.framewiki.gpt.config;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Configuration;

import org.springframework.stereotype.Component;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.config

* @ClassName: GptConfig

* @Description: GPT配置

* @Author: xiaLin

* @Date: 2023/6/10 18:16

* @Version: 1.0

*/

@Component

@Configuration

public class ChatConfig {

/**

* 环境

*/

@Value("${spring.profiles.active}")

private String active;

/**

* 默认环境

*/

private final String defaultActive = "prod";

/**

* 地址

*/

private final String OPEN_AI_URI = "https://api.openai.com/v1/";

/**

* 测试地址

*/

private final String TEST_OPEN_AI_URI = "https://vpn.itizzy.com/v1/";

/**

* 请求机构

* 列出模型

* 检索模型

*/

private final String MODEL_LIST = "models";

/**

* 聊天完成

*/

private final String CREATE_CHAT_COMPLETION = "chat/completions";

/**

* 创建对话

*/

private final String CREATE_COMPLETION = "completions";

/**

* ;

* 聊天完成地址

*

* @return

*/

public String getCreateChatCompletion() {

StringBuffer address = new StringBuffer(getAddress());

address.append(CREATE_CHAT_COMPLETION);

// 返回结果

return address.toString();

}

/**

* 获取地址

*/

private String getAddress() {

if (active.startsWith(defaultActive)) {

return OPEN_AI_URI;

} else {

return TEST_OPEN_AI_URI;

}

}

}

2.3.10 接口调用OpenAi配置信息类ChatConfiguration.class

package com.framewiki.gpt.config;

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.context.annotation.Configuration;

/**

* @ProjectName: framewiki-gpt

* @Package: com.framewiki.gpt.config

* @ClassName: ChatConfiguration

* @Description: java类作用描述

* @Author: xiaLin

* @Date: 2023/6/10 19:35

* @Version: 1.0

*/

@Data

@Configuration

@ConfigurationProperties(prefix = "open.ai.gpt")

public class ChatConfiguration {

/**

* openai Api密钥

*/

private String openaiApiKey;

/**

* 机构ID

*/

private String organizationId;

/**

* appKey

*/

private String appKey;

}

3     常见问题

3.1  OpenAi接口调用不通

因为https://api.openai.com/ 地址也被限制了,但是接口没有对地区做校验,因此可以自己搭建一个代理。

我采用的是亚马逊云代理的模式(新账号可申请1H1G、8G硬盘的云服务器),具体代理配置流程如下:

下载及安装nginx就不在此详说了。

部署nginx并修改/nginx/nginx.conf文件,配置接口代理路径如下

server {

listen 443 ssl;

server_name vpn.ai.com;

ssl_certificate /usr/local/cert/vpn.ai.com.pem;

ssl_certificate_key /usr/local/cert/vpn.ai.com.key;

ssl_session_cache shared:SSL:1m;

ssl_session_timeout 5m;

ssl_ciphers HIGH:!aNULL:!MD5;

ssl_prefer_server_ciphers on;

location / {

proxy_pass https://chat.openai.com/;

proxy_ssl_server_name on;

proxy_ssl_session_reuse off;

}

}

}

3.2  接口返回401

检查请求方法是否增加token字段以及key是否正确

4     总结

至此JAVA对OpenAI对接就已经完成了,并且也支持连续对话,大家可以在此基础上不断地完善和桥接到web服务,定制自己的ChatGPT助手了。我自己也搭建了个平台,不断地在完善中,想要体验的可以用微信登录体验。

项目开源地址:https://gitee.com/cdkjframework/chatgpt-server



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。