ChatGPT API 的 Java 简单使用

2023-04-04 11:09:46 浏览数 (1)

ChatGPT API 的 Java 简单使用

> 引言:想着openai送的额度不能浪费,就使用OKHTTP框架做了一个简单的控制台对话实现

请求部分

代码语言:javascript复制
/**
     * 发送消息请求
     * @param msgList 消息列表,包含历史对话
     * @param delay 等待回复延迟
     * @return ChatGPT回复消息
     * @throws IOException Json格式化异常, 返回包execute()异常
     */
    private static String sendReq(List<Map<String, String>> msgList, int delay) throws IOException {
        assert Main.CONFIG != null;
        var httpClient = new OkHttpClient.Builder()
                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(Main.CONFIG.getProxyUrl(), Main.CONFIG.getPort())))
                .callTimeout(60, TimeUnit.SECONDS)
                .connectTimeout(delay, TimeUnit.SECONDS)
                .readTimeout(delay, TimeUnit.SECONDS)
                .build();
        var reqBody = Map.of("model", "gpt-3.5-turbo"
                , "messages", msgList
                , "temperature", 0.7);
        var req = new Request.Builder()
                .url(Main.CONFIG.getChatGptApi())
                .addHeader("Content-Type", "application/json")
                .addHeader("Authorization", "Bearer "   Main.CONFIG.getChatGptToken())
                .post(RequestBody.create(FileUtil.OBJECT_MAPPER.writeValueAsString(reqBody).getBytes(StandardCharsets.UTF_8)))
                .build();
        try (var resp = httpClient.newCall(req).execute()) {
            if (resp.isSuccessful()) {
                assert resp.body() != null;
                return resp.body().string();
            } else {
                return null;
            }
        }
    }

根据 官方文档,需要在请求头中加入 Authorization: Bearer OPENAI_API_KEY 来鉴权,其中 OPENAI_API_KEY 需要自己创建,发文时新注册赠送 5$ 4个月。

请求部分参考这部分 官方文档 可以看到方法的入参有一个集合,其中存储历史对话记录

官方提供的返回Json示例如下,我们重点关注 message 部分

代码语言:javascript复制
{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "nnHello there, how may I assist you today?",
    },
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

可以看到,api 采用 role 字段表名消息发送者的身份,一共有三种身份 文档

代码语言:javascript复制
[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."}
]

官方的描述是: The main input is the messages parameter. Messages must be an array of message objects, where each object has a role (either "system", "user", or "assistant") and content (the content of the message). Conversations can be as short as 1 message or fill many pages.

通常使用 System 喂给 ChatGPT 一些背景设定,而后交替使用 userassistant来进行对话。

temperature 的范围在 0 - 2 之间,用于设定生成回复的 "创造力",较高的值生成的内容会更加随机。

对话交互部分

代码语言:javascript复制
/**
     * 负责对话交互部分
     */
    public void chat() {
        try {
            List<Map<String, String>> msgList = new ArrayList<>();
            while (true) {
                Main.LOGGER.info("n你:");
                String input = Main.SCANNER.nextLine();
                if ("exit".equals(input)) {
                    return;
                }
                Main.LOGGER.info("请输入本次回复的等待时间(s):");
                var delay = Integer.parseInt(Main.SCANNER.nextLine());
                msgList.add(Map.of("role", "user", "content", input));
                String resp = sendReq(msgList, delay);
                if (resp == null) {
                    Main.LOGGER.warn("请求错误");
                    return;
                }
                String chatgptReply = resp.substring(resp.indexOf(""message":")   10, resp.indexOf(","finish_reason"));
                Message message = FileUtil.OBJECT_MAPPER.readValue(chatgptReply, Message.class);
                msgList.add(Map.of("role", message.getRole(), "content", message.getContent()));
                Main.LOGGER.info("Chatgpt:");
                Main.LOGGER.info(message.getContent());
            }
        } catch (NumberFormatException e) {
            Main.LOGGER.warn("输入格式有误, 请输入数字");
        } catch (InterruptedIOException e) {
            Main.LOGGER.warn("等待回复超时, 请确认代理状态或增加等待时间");
        } catch (IOException e) {
            Main.LOGGER.warn("回复数据格式化失败");
        }
    }

通过将 问题 和 回复 添加进 msgList 集合,来实现持续对话

GitHub仓库:https://github.com/mashirot/MashiroChat

0 人点赞