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

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

超级详细 JAVA 对接 ChatGPT 教程,实现自己的AI对话小助手_第1张图片

2.1.2      点击创建key

超级详细 JAVA 对接 ChatGPT 教程,实现自己的AI对话小助手_第2张图片

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

超级详细 JAVA 对接 ChatGPT 教程,实现自己的AI对话小助手_第3张图片

将API Key保存好以备用

2.2  API用量的查看

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

超级详细 JAVA 对接 ChatGPT 教程,实现自己的AI对话小助手_第4张图片

2.3  核心代码实现

2.3.1      pom依赖

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



    
        framewiki-gpt
        com.framewiki.gpt
        1.0.0
    
    4.0.0

    gpt-util

    
        
            com.cdkjframework
            cdkj-core
        
        
            com.cdkjframework
            cdkj-util
        
        
            commons-httpclient
            commons-httpclient
        
        
            org.springframework.boot
            spring-boot-starter-validation
        
    

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 messages;

  /**
   * 回复条数,一次对话回复的条数
   */
  private Integer n;

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

  /**
   * 状态
   */
  private List 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 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 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 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://.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  .ai.com;

        ssl_certificate      /usr/local/cert/.ai.com.pem;
        ssl_certificate_key  /usr/local/cert/.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

你可能感兴趣的:(java,chatgpt,人工智能)