All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nkjmlab.util.openai.chat.ChatCompletion Maven / Gradle / Ivy

package org.nkjmlab.util.openai.chat;

import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.Properties;

import org.nkjmlab.util.java.function.Try;
import org.nkjmlab.util.openai.OpenAi4jException;
import org.nkjmlab.util.openai.chat.model.ChatRequest;
import org.nkjmlab.util.openai.chat.model.ChatRequest.ChatMessage;
import org.nkjmlab.util.openai.chat.model.ChatRequest.ChatMessage.Role;
import org.nkjmlab.util.openai.chat.model.ChatResponse;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * API Reference - OpenAI
 * API
 *
 * @author nkjm
 */
public class ChatCompletion {

  private final String authHeader;
  private final URI apiUrl;
  private final HttpClient httpClient;
  private final ObjectMapper objectMapper;

  public static void main(String[] args) {
    ChatResponse res =
        ChatCompletion.builder()
            .build()
            .createCompletion("What do you think would be good for dinner tonight?");
    System.out.println(res);
  }

  private ChatCompletion(Builder builder) {
    this.authHeader = "Bearer " + builder.apiKey;
    this.apiUrl = builder.apiUrl;

    this.httpClient =
        HttpClient.newBuilder()
            .connectTimeout(Duration.of(builder.timeout, ChronoUnit.MILLIS))
            .build();

    this.objectMapper = builder.objectMapper;
  }

  public ChatResponse createCompletion(String text) throws OpenAi4jException {
    return createCompletion(
        ChatRequest.builder().messages(ChatMessage.of(Role.USER, text)).build());
  }

  public ChatResponse createCompletion(ChatRequest chatRequest) throws OpenAi4jException {
    try {
      HttpRequest req = createHttpRequest(chatRequest);
      HttpResponse res = httpClient.send(req, BodyHandlers.ofByteArray());
      ChatResponse chatResponse = objectMapper.readValue(res.body(), ChatResponse.class);

      return chatResponse;
    } catch (Exception e) {
      throw new OpenAi4jException("error occurs when it calls completion api", e);
    }
  }

  private HttpRequest createHttpRequest(ChatRequest chatRequest) throws JsonProcessingException {
    return HttpRequest.newBuilder()
        .uri(apiUrl)
        .header("Authorization", authHeader)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofByteArray(objectMapper.writeValueAsBytes(chatRequest)))
        .build();
  }

  public static Builder builder() {
    return new Builder();
  }

  public static class Builder {

    private String apiKey;
    private long timeout = 2 * 60 * 1000L;
    private URI apiUrl = toURI("https://api.openai.com/v1/chat/completions");
    private ObjectMapper objectMapper =
        new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            .setSerializationInclusion(JsonInclude.Include.NON_NULL);

    public Builder apiKeyFromSystemEnv() {
      String key = System.getenv("OPENAI4J_SECRET_TOKEN");
      if (key != null && key.toString().length() > 0) {
        apiKey(key.toString());
        return this;
      }
      throw new RuntimeException("System env OPENAI4J_SECRET_TOKEN is not found or not valid.");
    }

    public Builder apiKeyFromProperties(String resourceName) {
      try (InputStream is = ChatCompletion.class.getResourceAsStream(resourceName)) {
        Properties props = new Properties();
        props.load(is);
        Object key = props.get("secretKey");
        if (key != null && key.toString().length() > 0) {
          apiKey(key.toString());
          return this;
        }
        throw new RuntimeException("/openai4j.properties is invalid.");
      } catch (Exception e) {
        throw Try.rethrow(e);
      }
    }

    public Builder apiKey(String apiKey) {
      this.apiKey = apiKey;
      return this;
    }

    public Builder timeout(long timeout) {
      this.timeout = timeout;
      return this;
    }

    public Builder apiUrl(String apiUrl) {

      this.apiUrl = toURI(apiUrl);
      return this;
    }

    public Builder mapper(ObjectMapper mapper) {
      this.objectMapper = mapper;
      return this;
    }

    public ChatCompletion build() {
      return new ChatCompletion(this);
    }

    private static URI toURI(String uri) {
      try {
        return new URI(uri);
      } catch (URISyntaxException e) {
        throw new OpenAi4jException(uri + " is invalid", e);
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy