com_cloudurable_jai_examples - RichardHightower/jai GitHub Wiki

com.cloudurable.jai.examples

class diagram

GetTopAINewsArticles

The GetTopAINewsArticles class is a public class that is used to retrieve the top news articles related to artificial intelligence (AI). This class provides a method to fetch AI news articles from a specified source or API. It encapsulates the functionality required to retrieve and process AI news articles, making it easier for software engineers to integrate AI news functionality into their applications.

public static void main(String... args)

public static void main(String... args) {
    try {
        final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
        final var chatRequest = ChatRequest.builder().addMessage(Message.builder().role(Role.SYSTEM).content("All output shall be JSON").build()).addMessage(Message.builder().role(Role.USER).content(QUERIES_INPUT.replace("{USER_QUESTION}", "What is Tesla new AI initiative?")).build()).build();
        final var chat = client.chat(chatRequest);
        if (chat.getResponse().isPresent()) {
            String queriesJson = chat.getResponse().get().getChoices().get(0).getMessage().getContent();
            System.out.println(queriesJson);
            List<String> queries = JsonParserBuilder.builder().build().parse(queriesJson).getObjectNode().getArrayNode("queries").filter(node -> node instanceof StringNode).stream().map(Object::toString).collect(Collectors.toList());
            List<ArrayNode> results = queries.subList(0, 10).stream().map(GetTopAINewsArticles::searchNews).collect(Collectors.toList());
            results.forEach(arrayNode -> {
                arrayNode.forEach(on -> {
                    final var node = on.asCollection().asObject();
                    handleArticle(node);
                });
            });
        } else {
            System.out.println("" + chat.getStatusCode().orElse(666) + "" + chat.getStatusMessage().orElse(""));
        }
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

The main method in the GetTopAINewsArticles class is structured as follows:

  1. The method begins by creating a client object of type OpenAIClient using the OpenAIClient.builder() method and setting the API key from the system environment variable OPENAI_API_KEY.

  2. Next, a ChatRequest object is created using the ChatRequest.builder() method.

  3. Inside the ChatRequest, two messages are added using the addMessage method:

    a. The first message is a system message with the content "All output shall be JSON" and the role set as Role.SYSTEM.

    b. The second message is a user message with the content "What is Tesla new AI initiative?" where {USER_QUESTION} is replaced by the given user question. The role is set as Role.USER.

  4. After creating the chat request, it is passed to the client.chat(chatRequest) method, which returns a ChatCompletion object.

  5. The method checks if the response is present in the ChatCompletion object using the chat.getResponse().isPresent() condition.

  6. If the response is present, the method retrieves the JSON content from the first choice in the response using chat.getResponse().get().getChoices().get(0).getMessage().getContent(). The retrieved JSON content is assigned to the variable queriesJson.

  7. The JSON content is printed to the console using System.out.println(queriesJson).

  8. The JSON content is parsed using a JSON parser from the JsonParserBuilder.builder().build() method.

  9. The parsed JSON object is used to retrieve an array node named "queries" using getObjectNode().getArrayNode("queries").

  10. Next, a sublist of the first 10 items in the "queries" array is created using queries.subList(0, 10).

  11. For each query in the sublist, the method calls the searchNews method from the GetTopAINewsArticles class and stores the results in a List<ArrayNode> called results.

  12. The method then iterates over each ArrayNode in the results list and further iterates over each ObjectNode in the ArrayNode.

  13. For each ObjectNode, the method calls the handleArticle method, passing the node as a parameter.

  14. If the response is not present in the ChatCompletion object, the method prints the status code and status message using chat.getStatusCode().orElse(666) and chat.getStatusMessage().orElse("").

  15. Any exception thrown during the execution of the method is caught, and the stack trace is printed to the console using ex.printStackTrace(). sequence diagram

private static void handleArticle(ObjectNode node)

private static void handleArticle(ObjectNode node) {
    System.out.println("# " + node.getString("title"));
    if (node.get("author") != null) {
        System.out.println("#### author: " + node.getString("author"));
    }
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final var chatRequest = ChatRequest.builder().addMessage(Message.builder().role(Role.SYSTEM).content("All output shall be Markdown").build()).addMessage(Message.builder().role(Role.USER).content("First Summarize this article to less than 500 words while " + "getting all of the main points. Also Extract the author, publication, publication date, and link to the article ||| " + node).build()).addMessage(Message.builder().role(Role.USER).content("Then create 10 high level bullet points from the article").build()).build();
    ClientResponse<ChatRequest, ChatResponse> chat = client.chat(chatRequest);
    if (chat.getResponse().isPresent()) {
        System.out.println(chat.getResponse().get().getChoices().get(0).getMessage().getContent());
    } else {
        System.out.println("" + chat.getStatusCode().orElse(666) + "" + chat.getStatusMessage().orElse(""));
    }
    System.out.println("------");
}

The handleArticle method in the GetTopAINewsArticles class is used to handle a news article object represented by the node parameter. Here is a step-by-step description of what the method does:

  1. Print the title of the article by retrieving the value of the "title" field from the node object and appending it with a heading (#).
  2. Check if the "author" field exists in the node object.
    • If it exists, print the author's name by retrieving the value of the "author" field and appending it with "author:" and a subheading (####).
  3. Build an instance of the OpenAIClient using the OpenAI_API_KEY environment variable to make API requests.
  4. Build a ChatRequest to summarize the article and extract key information.
    • The request includes two Message objects:
      • The first message is from the system's role and sets the requirement for the output format to be Markdown.
      • The second message is from the user's role and provides instructions and the article itself. It concatenates the instructions with the node object.
      • The third message from the user's role instructs to create 10 high-level bullet points from the article.
  5. Send the chatRequest to the OpenAI API and get the response in chat variable.
  6. Check if the response is available (chat.getResponse().isPresent()).
    • If available, print the content of the first choice in the response (chat.getResponse().get().getChoices().get(0).getMessage().getContent()).
    • If not available, print the status code and status message from the chat variable.
  7. Print a delimiter (------) to separate each article in the output. sequence diagram

public static ArrayNode searchNews(final String query, final Instant start, final Instant end, final int pageSize)

public static ArrayNode searchNews(final String query, final Instant start, final Instant end, final int pageSize) {
    System.out.println(query);
    try {
        String url = "https://newsapi.org/v2/everything?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8) + "&apiKey=" + System.getenv("NEWS_API_KEY") + "&language=en" + "&sortBy=relevancy" + "&from=" + dateStr(start) + "&to=" + dateStr(end) + "&pageSize=" + pageSize;
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder().uri(URI.create(url)).GET().setHeader("Content-Type", "application/json").build(), HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 200 && response.statusCode() < 299) {
            return JsonParserBuilder.builder().build().parse(response.body()).atPath("articles").asCollection().asArray();
        } else {
            throw new IllegalStateException(" status code " + response.statusCode() + " " + response.body());
        }
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
}

The searchNews method is defined in the com.cloudurable.jai.examples.GetTopAINewsArticles class. It takes the following parameters:

  • query (type: String): The query string used for searching news articles.
  • start (type: Instant): The start date for the search.
  • end (type: Instant): The end date for the search.
  • pageSize (type: int): The number of results to be returned per page.

The method performs the following steps:

  1. Prints the query parameter to the console.
  2. Constructs the URL for the news API request by appending the encoded query parameter, the API key retrieved from the environment variable NEWS_API_KEY, language, sortBy value as "relevancy", start date converted to a string using the dateStr method, end date converted to a string using the dateStr method, and pageSize value.
  3. Creates a new HttpClient.
  4. Sends an HTTP GET request to the constructed URL with the appropriate headers.
  5. Retrieves the response from the HTTP request.
  6. Checks if the response status code is between 200 and 299 (indicating a successful request).
    • If the status code is within this range, the method uses a JsonParserBuilder to parse the response body and extract the "articles" field as an array node. The method then returns this array node as the result.
    • If the status code is outside this range, the method throws an IllegalStateException with the status code and response body as the error message.
  7. If any exception occurs during the execution of the method, it is caught and rethrown as an IllegalStateException with the original exception as its cause. sequence diagram

Main

The Main class is a public class that serves as the entry point for the application. It contains the main method which is invoked when the program is executed. This class is responsible for initializing and running the application, and may include various methods and variables to support its functionality.

public static void main(final String... args)

public static void main(final String... args) {
    try {
        chatWithFunctions();
        //            listFiles();
        //            final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
        //
        //            uploadFile(new File("prompts.jsonl"));
        //
        //            Thread.sleep(1000);
        //            listFiles();
        //            FileData fileData = client.listFiles().getData().get(0);
        //            getFileDataAsync(fileData.getId());
        //
        //            final String contents = getFileContents(fileData.getId());
        //
        //
        //            client.listFiles().getData().forEach(fileData1 -> deleteFile(fileData1.getId()));
        //            listFiles();
        //            listFilesAsync();
        //            deleteFile("file-oGS5LrLOSrGosbREBfZahbWt");
        //            deleteFileAsync("file-I0sbD442zLMWkGZAlCiLGdHW");
        //            listFiles();
        //listFilesAsync();
        //getFileData("file-HBNdOLJK7rKf9jbP1DsBc7b8");
        //getFileDataAsync("file-HBNdOLJK7rKf9jbP1DsBc7b8");
        //getModelAsync("whisper-1");
        //listModelsAsync();
        //getModel("whisper-1");
        //listModels();
        //           createVariationsImageAsync();
        //           editImageAsync();
        //           callCreateImageAsync();
        //            createVariationsImage();
        //            editImage();
        //            callCreateImage();
        //           callTranslate();
        //            callTranscribe();
        //            callEmbeddingAsyncExample();
        //            callEmbeddingExample();
        //            callEditAsyncExample();
        //            callEditExample();
        //            callCompletionExample();
        //            callChatExample();
        //            callChatExampleAsync();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

The main method in the com.cloudurable.jai.examples.Main class is performing the following steps:

  1. It begins by calling the chatWithFunctions() method to initiate a chat conversation with AI functions.

  2. It then comments out several lines of code that contain other method calls. These methods are related to various functionalities like listing files, uploading files, retrieving file data, getting file contents, deleting files, and listing models. These methods are not executed in the current code.

  3. It catches any exceptions that may occur during the execution of the above steps and prints the stack trace in case of an exception.

Note: The commented-out method calls suggest that this code is likely a placeholder or an example code that demonstrates various functionalities of the com.cloudurable.jai.examples.Main class. sequence diagram

private static void chatWithFunctions() throws ExecutionException, InterruptedException

private static void chatWithFunctions() throws ExecutionException, InterruptedException {
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    FunctionDef getCurrentWeatherFunc = FunctionDef.builder().name("get_current_weather").description("Get the current weather in a given location").setParameters(ObjectParameter.objectParamBuilder().addParameter(Parameter.builder().name("location").description("The city and state, e.g. Austin, TX").build()).addParameter(EnumParameter.enumBuilder().name("unit").enumValues("celsius", "fahrenheit").build()).required("location").build()).build();
    Map<String, java.util.function.Function<ObjectNode, String>> functionMap = new HashMap<>();
    functionMap.put("get_current_weather", objectNode -> {
        final String location = objectNode.getString("location");
        final String unit = Optional.ofNullable(objectNode.get("unit")).map(node -> node.asScalar().stringValue()).orElse("fahrenheit");
        final JsonSerializer json = new JsonSerializer();
        json.startObject();
        json.addAttribute("location", location);
        json.addAttribute("unit", unit);
        switch(location) {
            case "Austin, TX":
                json.addAttribute("temperature", 92);
                json.endObject();
                return json.toString();
            case "Boston, MA":
                json.addAttribute("temperature", 72);
                json.endObject();
                return json.toString();
            default:
                json.addAttribute("temperature", 70);
                json.endObject();
                return json.toString();
        }
    });
    // messages = [{"role": "user", "content": "What's the weather like in Boston?"}]
    ChatRequest.Builder chatBuilder = ChatRequest.builder().model("gpt-3.5-turbo-0613").addMessage(Message.builder().role(Role.USER).content("What's the weather like in Boston in fahrenheit?").build()).addFunction(getCurrentWeatherFunc).functionalCall(ChatRequest.AUTO);
    ChatRequest chatRequest = chatBuilder.build();
    ClientResponse<ChatRequest, ChatResponse> chat = client.chat(chatRequest);
    chat.getResponse().ifPresent(chatResponse -> {
        var responseMessage = chatResponse.getChoices().get(0).getMessage();
        var functionCall = responseMessage.getFunctionCall();
        if (functionCall != null && functionMap.containsKey(functionCall.getName())) {
            String functionResponse = functionMap.get(functionCall.getName()).apply(functionCall.getArguments());
            chatBuilder.addMessage(Message.builder().name(functionCall.getName()).role(Role.FUNCTION).content(functionResponse).build());
            ClientResponse<ChatRequest, ChatResponse> response2 = client.chat(chatBuilder.build());
            response2.getResponse().ifPresent(new Consumer<ChatResponse>() {

                @Override
                public void accept(ChatResponse chatResponse) {
                    System.out.println(chatResponse.getChoices().get(0).getMessage().getContent());
                }
            });
            if (response2.getStatusMessage().isPresent()) {
                System.out.println(response2.getStatusMessage().orElse(""));
            }
        }
    });
    System.out.println(chat.getStatusCode().orElse(666));
    System.out.println(chat.getStatusMessage().orElse(""));
    chat.getException().ifPresent(e -> e.printStackTrace());
}

The chatWithFunctions method defined in the com.cloudurable.jai.examples.Main class performs the following steps:

Step 1: Create the OpenAIClient

It creates an instance of the OpenAIClient using the OPENAI_API_KEY environment variable as the API key.

Step 2: Define the getCurrentWeatherFunc function

It defines a function called get_current_weather that retrieves the current weather for a given location. The function takes two parameters: location (the city and state) and unit (the unit of temperature, either celsius or fahrenheit).

Step 3: Create a function map

It creates a HashMap called functionMap to store the functions. The get_current_weather function is added to this map.

Step 4: Handle the user input message

It creates a ChatRequest.Builder object and sets the model to gpt-3.5-turbo-0613. It adds a user message asking for the weather in Boston in fahrenheit. It also adds the getCurrentWeatherFunc function to the request.

Step 5: Make a chat request

It builds the ChatRequest object from the chatBuilder and makes a chat request using the client.chat() method. The response is stored in the chat variable.

Step 6: Process the chat response

If the chat response contains a valid response, it retrieves the first choice message from the response. If the message contains a function call, it checks if the function map contains the function name. If the function is found in the map, the function is executed with the arguments provided in the function call. The function response is then added as a message to the chatBuilder.

Step 7: Make a second chat request

The chatBuilder is modified to include the function response message. Another chat request is made using the client.chat() method with the modified chat builder.

Step 8: Process the second chat response

If the second chat response contains a valid response, it retrieves the first choice message from the response and prints its content. It also prints the status message if it is present.

Step 9: Print the status code and message

The status code and message of the initial chat request are printed. If there was an exception during the chat request, it is also printed. sequence diagram

private static void createVariationsImageAsync() throws ExecutionException, InterruptedException

private static void createVariationsImageAsync() throws ExecutionException, InterruptedException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final CreateImageVariationRequest request = CreateImageVariationRequest.builder().imageFile(new File("super_hero.png")).n(5).responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<CreateImageVariationRequest, ImageResponse> response = client.createImageVariationAsync(request).get();
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method createVariationsImageAsync() in the class com.cloudurable.jai.examples.Main performs the following steps:

  1. Create an instance of the OpenAIClient by calling the builder() method and setting the API key from the environment variable OPENAI_API_KEY.
  2. Create a CreateImageVariationRequest object by calling the builder() method and passing in the parameters:
    • imageFile: A File object representing the image file "super_hero.png".
    • n: The number of image variations to create, set to 5.
    • responseFormat: The format of the response, set to ImageResponseFormat.URL.
  3. Call the createImageVariationAsync() method on the client object, passing in the request object. This method returns a ClientResponse object.
  4. Call the get() method on the ClientResponse object to get the result. This method will block until the result is available.
  5. If the response contains a successful result, call the getResponse() method to get the ImageResponse object. If it exists, print the string representation of the response using System.out.println().
  6. If the response contains a successful result, call the getResponse() method to get the ImageResponse object. If it exists, print the value of the created property using System.out.println().
  7. If an exception occurred during the request, call the getException() method on the ClientResponse object to get the Throwable object and print the stack trace using Throwable::printStackTrace.
  8. If the request resulted in a non-successful status code, call the getStatusMessage() method on the ClientResponse object to get the error message, and call getStatusCode() to get the status code. If both values are present, print the error message and status code using System.out.printf().

Note: The method throws ExecutionException and InterruptedException, so it should be called from a try-catch block or propagate the exceptions to be handled by the caller. sequence diagram

private static void editImageAsync() throws IOException, ExecutionException, InterruptedException

private static void editImageAsync() throws IOException, ExecutionException, InterruptedException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final EditImageRequest request = EditImageRequest.builder().imageFile(new File("super_hero.png")).n(5).prompt("make the super hero have a cape and larger muscles").responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<EditImageRequest, ImageResponse> response = client.editImageAsync(request).get();
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method editImageAsync is defined as a private static method in the class com.cloudurable.jai.examples.Main. It throws IOException, ExecutionException, and InterruptedException.

  1. It starts by creating an instance of the OpenAIClient using the builder pattern. The OpenAI API key is retrieved from the system environment variable "OPENAI_API_KEY".
  2. Then, an EditImageRequest object is constructed using the builder pattern. The request specifies an image file named "super_hero.png", sets the number of edits to 5, sets the prompt as "make the super hero have a cape and larger muscles", and requests the response format to be a URL.
  3. The editImageAsync method of the client is invoked asynchronously with the constructed request.
  4. The result of the asynchronous call is obtained by calling the get() method on the returned CompletableFuture<ClientResponse<EditImageRequest, ImageResponse>> object.
  5. The obtained response object is checked for an available response by calling the getResponse() method and then printed using System.out.println() if present.
  6. The method also prints the created field of the response object if available.
  7. If there is an exception during the asynchronous call, it is printed by calling printStackTrace() on the exception object.
  8. Any status message and status code of the response are printed if available by calling printf() on System.out.

Overall, the editImageAsync method makes an asynchronous call to the OpenAI API's editImageAsync method, passing the constructed EditImageRequest object, and handles the response and exceptions accordingly. sequence diagram

private static void callCreateImageAsync() throws ExecutionException, InterruptedException

private static void callCreateImageAsync() throws ExecutionException, InterruptedException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final CreateImageRequest request = CreateImageRequest.builder().prompt("super hero").responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<CreateImageRequest, ImageResponse> response = client.createImageAsync(request).get();
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The callCreateImageAsync method is defined in the com.cloudurable.jai.examples.Main class.

Here is a step-by-step description of what this method is doing:

  1. Create an instance of the OpenAIClient class by calling the builder() method and setting the API key using setApiKey() method with the value from the OPENAI_API_KEY environment variable.
  2. Create a CreateImageRequest object by calling the builder() method and setting the properties. In this case, the prompt is set to "super hero" and the response format is set to ImageResponseFormat.URL.
  3. Call the createImageAsync method on the client object, passing the request object as an argument. This method returns a ClientResponse object.
  4. Call the get() method on the ClientResponse object to wait for the response and retrieve it.
  5. Check if the response is available by calling the getResponse() method on the ClientResponse object. If it is present, print the response using the toString() method.
  6. Check if the response is available and retrieve the created property by calling the getCreated() method on the response object. If it is present, print the created value.
  7. Check if an exception occurred by calling the getException() method on the ClientResponse object. If an exception is present, print the stack trace.
  8. Check if the status message is available by calling the getStatusMessage() method on the ClientResponse object. If the status message is present, print it along with the status code using the printf() method.

This method makes an asynchronous request to the OpenAI API to create an image based on the specified prompt. It then retrieves the response, prints it to the console, and handles any exceptions or error messages that may occur. sequence diagram

private static void createVariationsImage() throws IOException

private static void createVariationsImage() throws IOException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final CreateImageVariationRequest request = CreateImageVariationRequest.builder().imageFile(new File("super_hero.png")).n(5).responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<CreateImageVariationRequest, ImageResponse> response = client.createImageVariation(request);
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method createVariationsImage() performs the following steps:

  1. It creates an instance of the OpenAIClient by using the OpenAIClient.builder() method and setting the API key obtained from the OPENAI_API_KEY environment variable.
  2. It creates a CreateImageVariationRequest object by using the CreateImageVariationRequest.builder() method.
    • It specifies the image file to be used for creating image variations by calling the imageFile method and passing the file path as a File object.
    • It specifies the number of variations to create by calling the n method and passing the desired number.
    • It specifies the response format for the image variations by calling the responseFormat method and passing ImageResponseFormat.URL as the format.
  3. It calls the createImageVariation method on the OpenAIClient instance and passes the CreateImageVariationRequest object as a parameter.
    • The method returns a ClientResponse object that contains the response and status of the request.
  4. It checks if the response contains a non-null image response by calling the getResponse method on the ClientResponse object and using the ifPresent method to execute the provided lambda expression only if the response is present.
    • It prints the string representation of the response by calling the toString method on the response object and passing it to the println method of System.out.
  5. It checks if the response contains the information about when the image variations were created by calling the getCreated method on the response object and using the ifPresent method to execute the provided lambda expression only if the created information is present.
    • It prints the created information by calling the println method of System.out and passing the created information as an argument.
  6. It checks if the response contains an exception by calling the getException method on the ClientResponse object and using the ifPresent method to execute the provided lambda expression only if an exception is present.
    • It prints the stack trace of the exception by calling the printStackTrace method on the exception object.
  7. It checks if the response contains a status message by calling the getStatusMessage method on the ClientResponse object and using the ifPresent method to execute the provided lambda expression only if a status message is present.
    • It prints the status message, along with the status code if present, by calling the printf method of System.out and passing the status message and status code as arguments. sequence diagram

private static void editImage() throws IOException

private static void editImage() throws IOException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final EditImageRequest request = EditImageRequest.builder().imageFile(new File("super_hero.png")).n(5).prompt("make the super hero have a cape and larger muscles").responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<EditImageRequest, ImageResponse> response = client.editImage(request);
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The editImage method is performing the following steps:

  1. Creating an instance of the OpenAIClient class by using the OpenAIClient.builder() method and setting the API key from the environment variables using setApiKey(System.getenv("OPENAI_API_KEY")).
  2. Creating an instance of the EditImageRequest class by using the EditImageRequest.builder() method.
    • Setting the image file to be edited by passing the new File("super_hero.png") as the imageFile parameter.
    • Specifying the number of edits to be made by setting n to 5.
    • Providing a prompt for the edits as "make the super hero have a cape and larger muscles".
    • Specifying the response format as ImageResponseFormat.URL.
  3. Making a request to edit the image by calling the client.editImage() method and passing the request object as the parameter. This returns a ClientResponse<EditImageRequest, ImageResponse> object.
  4. Checking if the response contains a valid ImageResponse object by calling response.getResponse().ifPresent().
    • If a valid ImageResponse object is present, it is printed to the console by calling System.out.println(r.toString()).
  5. Checking if the response contains the creation timestamp by calling response.getResponse().ifPresent() again.
    • If the timestamp is present, it is printed to the console by calling System.out.println(r.getCreated()).
  6. Checking if an exception occurred during the request by calling response.getException().ifPresent().
    • If an exception occurred, its stack trace is printed to the console by calling Throwable::printStackTrace.
  7. Checking if the response contains a status message by calling response.getStatusMessage().ifPresent().
    • If a status message is present, it is printed to the console along with the status code by calling System.out.printf("status message %s %d\n", error, response.getStatusCode().orElse(0)). sequence diagram

private static void callCreateImage() throws IOException

private static void callCreateImage() throws IOException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final CreateImageRequest request = CreateImageRequest.builder().prompt("super hero").responseFormat(ImageResponseFormat.URL).build();
    final ClientResponse<CreateImageRequest, ImageResponse> response = client.createImage(request);
    response.getResponse().ifPresent(r -> System.out.println(r.toString()));
    response.getResponse().ifPresent(r -> System.out.println(r.getCreated()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method callCreateImage() in the class com.cloudurable.jai.examples.Main performs the following steps:

  1. Creates an instance of the OpenAIClient class with the API key obtained from the OPENAI_API_KEY environment variable.

  2. Defines a CreateImageRequest object with a prompt of "super hero" and the image response format as ImageResponseFormat.URL.

  3. Calls the createImage() method on the client instance, passing in the CreateImageRequest object. This method returns a ClientResponse object.

  4. Retrieves the response from the ClientResponse object using the getResponse() method. If a response is present, it prints the response as a string using System.out.println(r.toString()).

  5. Retrieves the 'created' field from the response using the getCreated() method and prints it using System.out.println(r.getCreated()).

  6. Retrieves any exception that occurred during the API call using the getException() method. If an exception is present, it prints the stack trace using Throwable.printStackTrace().

  7. Retrieves the status message of the response using the getStatusMessage() method. If a status message is present, it formats and prints the message along with the status code using System.out.printf("status message %s %d", error, response.getStatusCode().orElse(0)). sequence diagram

private static void callTranslate() throws IOException

private static void callTranslate() throws IOException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final TranslateRequest request = TranslateRequest.builder().model("whisper-1").prompt("translate from Spanish to English").file(new File("spanish.m4a")).responseFormat(AudioResponseFormat.VTT).build();
    final ClientResponse<TranslateRequest, AudioResponse> response = client.translate(request);
    response.getResponse().ifPresent(r -> System.out.println(r.getText()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method callTranslate() in the class com.cloudurable.jai.examples.Main is performing the following steps:

  1. Create an instance of the OpenAIClient class by calling the builder() method and setting the API key from the environment variable OPENAI_API_KEY.
  2. Build a TranslateRequest object by calling the builder() method and setting the following properties:
    • model - Specifies the translation model (in this case, "whisper-1").
    • prompt - Specifies the text to be translated (in this case, "translate from Spanish to English").
    • file - Specifies the input audio file to be translated (in this case, "spanish.m4a").
    • responseFormat - Specifies the desired output format for the translation (in this case, AudioResponseFormat.VTT).
  3. Call the translate() method on the OpenAIClient instance, passing in the TranslateRequest object.
  4. The translate() method returns a ClientResponse object, which contains the response from the API.
  5. Check if the response has a valid response using the getResponse() method. If a response is present, print the translated text using System.out.println().
  6. Check if the response has an exception using the getException() method. If an exception is present, print the stack trace using Throwable::printStackTrace.
  7. Check if the response has a status message using the getStatusMessage() method. If a status message is present, print it along with the status code using System.out.printf(). sequence diagram

private static void callTranscribe() throws IOException

private static void callTranscribe() throws IOException {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    File file = new File("test.m4a");
    byte[] bytes = Files.readAllBytes(file.toPath());
    // Create the chat request
    final TranscriptionRequest request = TranscriptionRequest.builder().model("whisper-1").prompt("Write up notes").language("en").file(bytes).build();
    // Call Open AI API with chat message
    final ClientResponse<TranscriptionRequest, AudioResponse> response = client.transcribe(request);
    response.getResponse().ifPresent(r -> System.out.println(r.getBody()));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The callTranscribe method is performing the following steps:

  1. Create an instance of the OpenAIClient class using the builder() method and setting the API key from the environment variable.
  2. Create a File object to represent the "test.m4a" file.
  3. Read all the bytes from the file using the Files.readAllBytes() method.
  4. Create a TranscriptionRequest object using the builder() method, providing the model ("whisper-1"), prompt ("Write up notes"), language ("en"), and the bytes of the file.
  5. Call the transcribe method of the OpenAIClient object, passing in the TranscriptionRequest.
  6. Get the response from the API call using the getResponse() method of the ClientResponse object. If present, print the body of the response.
  7. If an exception occurred during the API call, print the stack trace using the printStackTrace() method of the exception object.
  8. Get the status message from the API call using the getStatusMessage() method of the ClientResponse object. If present, print the status message along with the status code (or 0 if not present). sequence diagram

private static void callEmbeddingAsyncExample() throws Exception

private static void callEmbeddingAsyncExample() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the request
    final com.cloudurable.jai.model.text.embedding.EmbeddingRequest request = com.cloudurable.jai.model.text.embedding.EmbeddingRequest.builder().model("text-embedding-ada-002").input("What is AI?").build();
    // Call Open AI API with chat message
    //
    client.embeddingAsync(request).exceptionally(e -> {
        e.printStackTrace();
        latch.countDown();
        return null;
    }).thenAccept(response -> {
        response.getResponse().ifPresent(response1 -> response1.getData().forEach(System.out::println));
        response.getException().ifPresent(Throwable::printStackTrace);
        response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
        latch.countDown();
    });
    latch.await(10, TimeUnit.SECONDS);
}

The callEmbeddingAsyncExample method in the com.cloudurable.jai.examples.Main class performs the following steps:

  1. Initialize a CountDownLatch with a count of 1. This latch is used to synchronize the completion of the asynchronous operation.
  2. Create an instance of the OpenAIClient by calling the builder() method and setting the API key using the setApiKey() method. The API key is retrieved from the environment variable OPEN_AI_KEY.
  3. Create an instance of the com.cloudurable.jai.model.text.embedding.EmbeddingRequest class by calling the builder() method and setting the model and input parameters. In this example, the model is set as "text-embedding-ada-002" and the input is set as "What is AI?".
  4. Invoke the embeddingAsync() method of the OpenAIClient instance, passing the previously created EmbeddingRequest object. This method returns a CompletableFuture which represents the asynchronous operation.
  5. Chain exception handling to the CompletableFuture using the exceptionally() method. This will be called if an exception occurs during the asynchronous operation. The exception is printed and the latch count is decremented.
  6. Chain the result processing logic to the CompletableFuture using the thenAccept() method. This will be called when the asynchronous operation completes successfully. It prints the response data (if available), prints any exception (if present), prints the status message (if available), and then decrements the latch count.
  7. Call the await() method on the latch to block the current thread until the latch count reaches zero or the specified timeout of 10 seconds elapses. This ensures that the program waits for the completion of the asynchronous operation before proceeding further. sequence diagram

private static void callEmbeddingExample()

private static void callEmbeddingExample() {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final com.cloudurable.jai.model.text.embedding.EmbeddingRequest request = com.cloudurable.jai.model.text.embedding.EmbeddingRequest.builder().model("text-embedding-ada-002").input("What is AI?").build();
    // Call Open AI API with chat message
    final ClientResponse<com.cloudurable.jai.model.text.embedding.EmbeddingRequest, EmbeddingResponse> response = client.embedding(request);
    response.getResponse().ifPresent(completionResponse -> completionResponse.getData().forEach(System.out::println));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The callEmbeddingExample() method is defined in the com.cloudurable.jai.examples.Main class. Here is a step-by-step description of what it does:

  1. Create the client: A new instance of the OpenAIClient class is created using its builder. The client is configured with an API key retrieved from the environment variable "OPEN_AI_KEY".

  2. Create the chat request: A new instance of the com.cloudurable.jai.model.text.embedding.EmbeddingRequest class is created using its builder. The request is configured with the model "text-embedding-ada-002" and the input text "What is AI?".

  3. Call Open AI API with chat message: The client.embedding(request) method is called, passing in the chat request. This method makes a request to the Open AI API with the chat message and returns a ClientResponse object.

  4. Process the response: The getResponse() method is called on the ClientResponse object to retrieve the response data. If the response is present, the getData() method is called to get the data associated with the completion response. The data is then printed to the console using System.out.println().

  5. Handle exceptions: The getException() method is called on the ClientResponse object to check if any exception occurred during the API call. If an exception is present, the printStackTrace() method is called on the exception to print the stack trace.

  6. Handle status messages: The getStatusMessage() method is called on the ClientResponse object to get the status message. If a status message is present, it is printed to the console using System.out.printf() along with the corresponding status code obtained from getStatusCode().

This method essentially creates a client, makes a chat request to the Open AI API, processes the response (if any), handles exceptions, and prints status messages (if any) to the console. sequence diagram

private static void callCompletionExample()

private static void callCompletionExample() {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final CompletionRequest request = CompletionRequest.builder().model("text-davinci-003").maxTokens(500).prompt("What is AI?").completionCount(3).build();
    // Call Open AI API with chat message
    final ClientResponse<CompletionRequest, CompletionResponse> response = client.completion(request);
    response.getResponse().ifPresent(completionResponse -> completionResponse.getChoices().forEach(System.out::println));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method callCompletionExample in the Main class is performing the following steps:

  1. Create an instance of the OpenAIClient class using the builder pattern and setting the API key from the "OPEN_AI_KEY" environment variable. This client will be used to interact with the Open AI API.

  2. Create a CompletionRequest object using the builder pattern. This request includes the following parameters:

    • model: Specifies the model to use for the completion. In this case, the model is set to "text-davinci-003".
    • maxTokens: Sets the maximum limit on the number of tokens generated by the completion. In this case, the limit is set to 500 tokens.
    • prompt: Provides a prompt or starting point for the completion. In this case, the prompt is set to "What is AI?".
    • completionCount: Specifies the number of completions to be generated. In this case, 3 completions will be generated.
  3. Call the Open AI API using the client.completion(request) method. This method sends the CompletionRequest object to the API and returns a ClientResponse object.

  4. Check the response from the API using the getResponse, getException, and getStatusMessage methods of the ClientResponse object.

    • If the response is successful, the completionResponse object is obtained from the response and each choice in completionResponse.getChoices() is printed.
    • If there is an exception, the printStackTrace method is called on the exception.
    • If there is a status message, it's printed along with the response status code.

This method essentially creates a chat conversation with the Open AI API by providing a prompt and generating multiple completions based on the given parameters. sequence diagram

private static void callEditExample()

private static void callEditExample() {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final EditRequest request = EditRequest.builder().model("text-davinci-edit-001").input("Where is u going?").instruction("Fix grammar").completionCount(3).build();
    // Call Open AI API with chat message
    final ClientResponse<EditRequest, EditResponse> response = client.edit(request);
    response.getResponse().ifPresent(completionResponse -> completionResponse.getChoices().forEach(System.out::println));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The callEditExample method in the Main class is performing the following steps:

  1. Create an instance of the OpenAIClient by calling the builder() method and setting the API key using setApiKey(System.getenv("OPEN_AI_KEY")).
  2. Create an instance of the EditRequest by calling the builder() method and setting the following properties:
    • model - Set to "text-davinci-edit-001" specifying the model to be used for the edit task.
    • input - Set to "Where is u going?" specifying the input text to be edited.
    • instruction - Set to "Fix grammar" providing the instruction for the editing task.
    • completionCount - Set to 3 indicating the number of completions to be generated.
  3. Call the client.edit(request) method of the OpenAIClient instance, passing the created EditRequest object.
  4. Get the response from the API call by assigning the result to a ClientResponse<EditRequest, EditResponse> object.
  5. If the response contains a valid EditResponse, iterate over the choices in the response and print each choice using forEach(System.out::println).
  6. If the response contains an exception, print the stack trace using response.getException().ifPresent(Throwable::printStackTrace).
  7. If the response contains a status message, print the message and the status code using response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d\n", error, response.getStatusCode().orElse(0))). sequence diagram

private static void callEditAsyncExample() throws Exception

private static void callEditAsyncExample() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final EditRequest request = EditRequest.builder().model("text-davinci-edit-001").input("Where is u going?").instruction("Fix grammar").completionCount(3).build();
    // Call Open AI API with chat message
    //
    client.editAsync(request).exceptionally(e -> {
        e.printStackTrace();
        latch.countDown();
        return null;
    }).thenAccept(response -> {
        response.getResponse().ifPresent(response1 -> response1.getChoices().forEach(System.out::println));
        response.getException().ifPresent(Throwable::printStackTrace);
        response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
        latch.countDown();
    });
    latch.await(10, TimeUnit.SECONDS);
}

Method Call: callEditAsyncExample

This method performs an asynchronous call to the Open AI API to edit a given text.

private static void callEditAsyncExample() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final EditRequest request = EditRequest.builder().model("text-davinci-edit-001").input("Where is u going?").instruction("Fix grammar").completionCount(3).build();
    // Call Open AI API with chat message
    //
    client.editAsync(request).exceptionally(e -> {
        e.printStackTrace();
        latch.countDown();
        return null;
    }).thenAccept(response -> {
        response.getResponse().ifPresent(response1 -> response1.getChoices().forEach(System.out::println));
        response.getException().ifPresent(Throwable::printStackTrace);
        response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d\n", error, response.getStatusCode().orElse(0)));
        latch.countDown();
    });
    latch.await(10, TimeUnit.SECONDS);
}

Steps:

  1. Create a new CountDownLatch with an initial count of 1 to synchronize the API call.
  2. Create a new instance of OpenAIClient using the provided API key from the system environment variables.
  3. Create a new EditRequest object with the following parameters:
    • model - The Open AI model to be used for editing the text.
    • input - The text to be edited.
    • instruction - The instructions for editing the text.
    • completionCount - The number of alternative completions to generate.
  4. Call editAsync method on the OpenAIClient instance, passing the EditRequest object. This returns a CompletableFuture for handling the asynchronous response.
  5. Handle any exceptions that occur during the API call by printing the stack trace and counting down the latch.
  6. Handle the response from the API call by using the thenAccept method on the CompletableFuture. This callback is executed when the API call completes successfully.
    • If a response is received, iterate through the choices in the response and print them.
    • If an exception occurs, print the stack trace.
    • If a status message is present, print it along with the status code (if available).
    • Count down the latch to unlock the synchronization.
  7. Use the latch.await method to wait for the latch to count down to zero, allowing the API call to complete within a specified time limit (10 seconds in this case). sequence diagram

private static void callChatExampleAsync() throws Exception

private static void callChatExampleAsync() throws Exception {
    final CountDownLatch latch = new CountDownLatch(1);
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final ChatRequest chatRequest = ChatRequest.builder().model("gpt-3.5-turbo").addMessage(Message.builder().content("What is AI?").role(Role.USER).build()).build();
    // Call Open AI API with chat message
    client.chatAsync(chatRequest).exceptionally(e -> {
        e.printStackTrace();
        latch.countDown();
        return null;
    }).thenAccept(response -> {
        response.getResponse().ifPresent(chatResponse -> chatResponse.getChoices().forEach(System.out::println));
        response.getException().ifPresent(Throwable::printStackTrace);
        response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
        latch.countDown();
    });
    latch.await(10, TimeUnit.SECONDS);
}

The method callChatExampleAsync is performing the following steps:

  1. It creates a CountDownLatch object named latch with an initial count of 1.

  2. It creates an instance of the OpenAIClient class using the builder pattern. The API key is obtained from the environment variable OPEN_AI_KEY.

  3. It creates a ChatRequest object using the builder pattern. The model used for the chat is "gpt-3.5-turbo". A single message is added to the chat, with the content "What is AI?" and the role being set as USER.

  4. It asynchronously calls the Open AI API using the chatAsync method of the OpenAIClient. If any exception occurs during the API call, it is handled by an exception handler provided as a lambda function. This lambda function prints the stack trace of the exception, decrements the count of the latch, and returns null.

  5. If the API call is successful, the response is passed to a lambda function provided as an argument to the thenAccept method. This lambda function handles the response by:

    • If the response contains chat messages, it prints each choice on a separate line.
    • If the response contains an exception, it prints the stack trace of the exception.
    • If the response contains a status message, it prints the message along with the status code (if available).
  6. After handling the response, the count of the latch is decremented.

  7. The method waits for a maximum of 10 seconds for the latch count to reach zero using the await method of the CountDownLatch class. This ensures that the method does not return until the asynchronous chat operation is completed.

Note: This method assumes that the OpenAIClient class and the required dependencies are properly imported and available for use. sequence diagram

private static void callChatExample() throws Exception

private static void callChatExample() throws Exception {
    // Create the client
    final OpenAIClient client = OpenAIClient.builder().setApiKey(System.getenv("OPEN_AI_KEY")).build();
    // Create the chat request
    final ChatRequest chatRequest = ChatRequest.builder().model("gpt-3.5-turbo").addMessage(Message.builder().content("What is AI?").role(Role.USER).build()).completionCount(5).build();
    // Call Open AI API with chat message
    final ClientResponse<ChatRequest, ChatResponse> response = client.chat(chatRequest);
    response.getResponse().ifPresent(chatResponse -> chatResponse.getChoices().forEach(System.out::println));
    response.getException().ifPresent(Throwable::printStackTrace);
    response.getStatusMessage().ifPresent(error -> System.out.printf("status message %s %d \n", error, response.getStatusCode().orElse(0)));
}

The method callChatExample() is defined in the class com.cloudurable.jai.examples.Main, and it performs the following steps:

  1. Create an instance of the OpenAIClient class, using the builder() method.
  2. Set the API key for the client by retrieving it from the system environment variable "OPEN_AI_KEY".
  3. Build the client using the build() method.
  4. Create a ChatRequest object using the builder() method.
  5. Set the model to "gpt-3.5-turbo" using the model() method.
  6. Add a Message to the chat request, with the content "What is AI?", a role of "USER", and build it using the addMessage() method.
  7. Set the completion count to 5 using the completionCount() method.
  8. Build the chat request using the build() method.
  9. Call the chat method of the Open AI API by passing the chat request to the client.chat() method.
  10. Store the response from the API call in a ClientResponse object, which is a generic type containing the ChatRequest and ChatResponse.
  11. If the response contains a ChatResponse object, iterate over the choices and print them using System.out.println().
  12. If an exception occurred during the API call, print the stack trace using Throwable::printStackTrace.
  13. If the response status has a message, print it along with the status code (or 0 if it's not present). The message is printed using System.out.printf(). sequence diagram

WhoWonUFC290Async

WhoWonUFC290Async The WhoWonUFC290Async class is a public class in Java that is used to determine the winner of UFC 290 asynchronously. It provides methods and functionalities to retrieve and process the data related to the UFC 290 event, allowing users to determine the winner of the said event. This class is designed to handle asynchronous operations, ensuring efficient and non-blocking execution of the code.

public static CompletableFuture jsonGPT(String input, String system)

public static CompletableFuture<String> jsonGPT(String input, String system) {
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final var chatRequest = ChatRequest.builder().addMessage(Message.builder().role(Role.SYSTEM).content(system).build()).addMessage(Message.builder().role(Role.USER).content(input).build()).build();
    return client.chatAsync(chatRequest).thenApply(chat -> {
        if (chat.getResponse().isPresent()) {
            return chat.getResponse().get().getChoices().get(0).getMessage().getContent();
        } else {
            System.out.println(chat.getStatusCode().orElse(666) + " " + chat.getStatusMessage().orElse(""));
            throw new IllegalStateException();
        }
    });
}

The jsonGPT method in the com.cloudurable.jai.examples.WhoWonUFC290Async class is a static method that takes two parameters: input and system. It returns a CompletableFuture<String>, which means the result of the method will be available asynchronously.

Here is a step-by-step description of what the jsonGPT method does based on its body:

  1. It starts by creating an instance of the OpenAIClient class using the builder pattern. The builder is configured by setting the apiKey property to the value of the OPENAI_API_KEY environment variable.

  2. Next, it creates a ChatRequest instance using the input and system parameters. The ChatRequest is built using the builder pattern and consists of two messages: one from the system and one from the user.

  3. The method then asynchronously performs a chat using the OpenAI client and the chat request. This is done by invoking the chatAsync method on the client instance and passing the chat request as a parameter. The method returns a CompletableFuture<ChatComplete>, where ChatComplete represents the result of the chat.

  4. Once the chat is complete, the method uses the thenApply method of the CompletableFuture to process the result. Inside the thenApply function, it checks if the chat response is present.

  5. If the chat response is present, it retrieves the content of the first choice from the response's choices list. This content represents the message generated by the AI model.

  6. If the chat response is not present, it means there was an error during the chat. In this case, it prints the status code and status message of the chat, if available, and throws an IllegalStateException.

  7. Finally, the method returns the content of the first choice as a String.

Note that the method assumes the availability of the OpenAI_API_KEY environment variable and uses it to configure the OpenAI client. If this environment variable is not set, it may cause an exception to be thrown. sequence diagram

public static CompletableFuture<List<float[]>> embeddingsAsync(List input)

public static CompletableFuture<List<float[]>> embeddingsAsync(List<String> input) {
    System.out.println("INPUT " + input);
    if (input == null || input.size() == 0) {
        return CompletableFuture.completedFuture(Collections.singletonList(new float[0]));
    }
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    return client.embeddingAsync(EmbeddingRequest.builder().model("text-embedding-ada-002").input(input).build()).thenApply(embedding -> {
        if (embedding.getResponse().isPresent()) {
            return embedding.getResponse().get().getData().stream().map(Embedding::getEmbedding).collect(Collectors.toList());
        } else {
            System.out.println(embedding.getStatusCode().orElse(666) + " " + embedding.getStatusMessage().orElse(""));
            throw new IllegalStateException(embedding.getStatusCode().orElse(666) + " " + embedding.getStatusMessage().orElse(""));
        }
    });
}

Method: embeddingsAsync

This method is defined in the com.cloudurable.jai.examples.WhoWonUFC290Async class.

Method Signature:

public static CompletableFuture<List<float[]>> embeddingsAsync(List<String> input)

Parameters:

  • input : A List of Strings

Returns:

  • A CompletableFuture that returns a List of float arrays

Description:

  1. Check if input is null or empty.
  • If input is null or empty, return a completed CompletableFuture with a singleton list containing an empty float array.
  1. Create an instance of OpenAIClient with the API key obtained from the OPENAI_API_KEY environment variable.

  2. Call the embeddingAsync method of the OpenAIClient object, passing an EmbeddingRequest object as a parameter. The EmbeddingRequest is constructed with the following properties:

  • model: The model used for the text embedding, set to "text-embedding-ada-002".
  • input: The input list of Strings.
  1. The embeddingAsync method returns a CompletableFuture with a result of type EmbeddingResponse. Use the thenApply method to process the result of the CompletableFuture.

  2. Inside the thenApply method, check if the embedding response is present.

  • If the response is present, extract the data from the response and map it to a list of embeddings. Return this list.

  • If the response is not present, print the status code and status message obtained from the EmbeddingResponse object, and throw an IllegalStateException with the same status code and message.

Note: The method's behavior, as described above, is based on the given code snippet. sequence diagram

public static float dot(float[] v1, float[] v2)

public static float dot(float[] v1, float[] v2) {
    assert v1.length == v2.length;
    float result = 0;
    for (int i = 0; i < v1.length; i++) {
        result += v1[i] * v2[i];
    }
    return result;
}

Method Name: dot

Class: com.cloudurable.jai.examples.WhoWonUFC290Async

Description: This method calculates the dot product of two float arrays, v1 and v2. The dot product is the sum of the element-wise multiplication of corresponding elements in both arrays.

Method Signature: public static float dot(float[] v1, float[] v2)

Parameters:

  • v1: The first float array.
  • v2: The second float array.

Returns:

  • The dot product of v1 and v2, represented as a float.

Steps:

  1. Check if the lengths of v1 and v2 are equal. If they are not equal, throw an AssertionError.
  2. Initialize a float variable "result" to zero. This variable will store the dot product of v1 and v2.
  3. Iterate over the elements of v1 and v2 from index 0 to v1.length - 1.
    • Multiply the i-th element of v1 with the i-th element of v2.
    • Add the result of the multiplication to the "result" variable.
  4. After the loop, return the calculated "result" as the dot product of v1 and v2. sequence diagram

public static CompletableFuture searchNews(final String query)

public static CompletableFuture<ArrayNode> searchNews(final String query) {
    System.out.println("searchNews " + query);
    final var end = Instant.now();
    final var start = end.minus(java.time.Duration.ofDays(5));
    return searchNewsFunc(query, start, end, 5);
}

The searchNews method, defined in the WhoWonUFC290Async class in the com.cloudurable.jai.examples package, performs the following steps based on its body:

  1. Prints a debug message indicating that the searchNews method has been called, along with the provided query.

  2. Retrieves the current timestamp using the Instant.now() method and assigns it to the end variable.

  3. Calculates a start timestamp by subtracting 5 days from the end timestamp using the minus method with the Duration.ofDays(5) argument. Assigns the resulting timestamp to the start variable.

  4. Calls the searchNewsFunc method with the query, start, end, and 5 arguments. This method is not included in the provided code, so its functionality is unclear. However, based on the name, it is likely responsible for executing a search query for news related to the provided query within the specified time frame.

  5. Returns a CompletableFuture object that represents the asynchronous result of the searchNewsFunc method call. The CompletableFuture encapsulates an ArrayNode object, which is presumably the result of the news search operation. sequence diagram

public static CompletableFuture searchNewsFunc(final String query, final Instant start, final Instant end, final int pageSize)

public static CompletableFuture<ArrayNode> searchNewsFunc(final String query, final Instant start, final Instant end, final int pageSize) {
    System.out.println(query);
    try {
        String url = "https://newsapi.org/v2/everything?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8) + "&apiKey=" + System.getenv("NEWS_API_KEY") + "&language=en" + "&sortBy=relevancy" + "&from=" + dateStr(start) + "&to=" + dateStr(end) + "&pageSize=" + pageSize;
        HttpClient httpClient = HttpClient.newHttpClient();
        return httpClient.sendAsync(HttpRequest.newBuilder().uri(URI.create(url)).GET().setHeader("Content-Type", "application/json").build(), HttpResponse.BodyHandlers.ofString()).thenApply(response -> {
            if (response.statusCode() >= 200 && response.statusCode() < 299) {
                return JsonParserBuilder.builder().build().parse(response.body()).atPath("articles").asCollection().asArray();
            } else {
                throw new IllegalStateException(" status code " + response.statusCode() + " " + response.body());
            }
        });
    } catch (Exception ex) {
        return CompletableFuture.failedFuture(ex);
    }
}

The searchNewsFunc method in the WhoWonUFC290Async class is used to perform a news search based on a given query, start and end dates, and page size. The method returns a CompletableFuture that will eventually contain an ArrayNode representing the search results.

Here is a step-by-step description of what the method does:

  1. Accepts four parameters: query (the search query), start (the start date for the search), end (the end date for the search), and pageSize (the number of results per page).

  2. Prints the value of the query parameter to the console.

  3. Constructs a URL string using the provided arguments and the News API URL structure.

  4. Creates a new instance of HttpClient.

  5. Sends an asynchronous HTTP GET request to the constructed URL using sendAsync method of the HttpClient. The request includes a custom header specifying the request's content type as application/json.

  6. Uses HttpResponse.BodyHandlers.ofString() to handle the response body as a String.

  7. The sendAsync method returns a CompletableFuture<HttpResponse>. This CompletableFuture is then passed to the thenApply method, where further processing of the response is done.

  8. Checks if the response status code is in the range 200-299, indicating a successful request.

  9. If the response status code is in the successful range, the response body is parsed as a JSON string using JsonParserBuilder from the Jackson library, extracting the "articles" field as an array.

  10. If the response status code is not in the successful range, an IllegalStateException is thrown with a message containing the status code and response body.

  11. If any exception occurs during the execution of the method, a failed CompletableFuture is returned with the exception as the result.

  12. The completed or failed CompletableFuture is then returned as the result of the method call. sequence diagram

public static void main(String... args)

public static void main(String... args) {
    try {
        long startTime = System.currentTimeMillis();
        final CountDownLatch countDownLatch = new CountDownLatch(2);
        // Generating a hypothetical answer and its embedding
        final var hypotheticalAnswerEmbeddingFuture = hypotheticalAnswer().thenCompose(WhoWonUFC290Async::embeddingsAsync).thenApply(floats -> {
            countDownLatch.countDown();
            return floats;
        });
        // Generate a list of queries and use them to look up articles.
        final var queriesFuture = jsonGPT(QUERIES_INPUT.replace("{USER_QUESTION}", USER_QUESTION)).thenApply(queriesJson -> JsonParserBuilder.builder().build().parse(queriesJson).getObjectNode().getArrayNode("queries").filter(node -> node instanceof StringNode).stream().map(Object::toString).collect(Collectors.toList())).thenCompose(WhoWonUFC290Async::getArticles).thenApply(objectNodes -> {
            countDownLatch.countDown();
            return objectNodes;
        });
        if (!countDownLatch.await(30, TimeUnit.SECONDS))
            throw new TimeoutException("Timed out waiting for hypotheticalAnswerEmbedding and " + " articles ");
        final var articles = queriesFuture.get();
        final var hypotheticalAnswerEmbedding = hypotheticalAnswerEmbeddingFuture.get();
        // Extracting article content and generating embeddings for each article
        final var articleContent = articles.stream().map(article -> String.format("%s %s %s", article.getString("title"), article.getString("description"), article.getString("content").substring(0, 100))).collect(Collectors.toList());
        final var articleEmbeddings = embeddingsAsync(articleContent).get();
        // Calculating cosine similarities between the hypothetical answer embedding and article embeddings
        final var cosineSimilarities = articleEmbeddings.stream().map(articleEmbedding -> dot(hypotheticalAnswerEmbedding, articleEmbedding)).collect(Collectors.toList());
        // Creating a set of scored articles based on cosine similarities
        final var articleSet = IntStream.range(0, Math.min(cosineSimilarities.size(), articleContent.size())).mapToObj(i -> new ScoredArticle(articles.get(i), cosineSimilarities.get(i))).collect(Collectors.toSet());
        final var sortedArticles = new ArrayList<>(articleSet);
        sortedArticles.sort((o1, o2) -> Float.compare(o2.getScore(), o1.getScore()));
        // Printing the top 5 scored articles
        sortedArticles.subList(0, 5).forEach(System.out::println);
        // Formatting the top results as JSON strings
        final var formattedTopResults = String.join(",\n", sortedArticles.stream().map(ScoredArticle::getContent).map(article -> String.format(Json.niceJson("{'title':'%s', 'url':'%s'," + " 'description':'%s', 'content':'%s'}\n"), article.getString("title"), article.getString("url"), article.getString("description"), getArticleContent(article))).collect(Collectors.toList()).subList(0, 10));
        System.out.println(formattedTopResults);
        // Generating the final answer with the formatted top results
        final var finalAnswer = jsonGPT(ANSWER_INPUT.replace("{USER_QUESTION}", USER_QUESTION).replace("{formatted_top_results}", formattedTopResults), "Output format is markdown").get();
        System.out.println(finalAnswer);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

The main method in the class com.cloudurable.jai.examples.WhoWonUFC290Async performs the following steps:

  1. Initializes a variable startTime to record the start time of the method's execution.
  2. Creates a CountDownLatch with an initial count of 2. This is used to synchronize the completion of two asynchronous operations.
  3. Starts an asynchronous operation to generate a hypothetical answer and its embedding using the hypotheticalAnswer method. The result is then passed to the embeddingsAsync method. The thenApply method is used to decrement the count of the CountDownLatch and return the result.
  4. Starts an asynchronous operation to generate a list of queries by replacing a placeholder in the QUERIES_INPUT string with a user question. The result is then parsed as JSON and filtered to get a list of queries. These queries are then passed to the getArticles method. The thenApply method is used to decrement the count of the CountDownLatch and return the result.
  5. Checks if the CountDownLatch reaches zero within 30 seconds. If not, a TimeoutException is thrown.
  6. Obtains the results of the two asynchronous operations: the list of articles and the embedding of the hypothetical answer.
  7. Extracts the content of each article and generates embeddings for them.
  8. Calculates the cosine similarities between the hypothetical answer embedding and the article embeddings.
  9. Creates a set of scored articles based on the cosine similarities.
  10. Sorts the scored articles based on their scores in descending order.
  11. Prints the top 5 scored articles to the console.
  12. Formats the top results as JSON strings.
  13. Generates the final answer by replacing placeholders in the ANSWER_INPUT string and obtaining the result from the jsonGPT method.
  14. Prints the final answer to the console.
  15. Calculates the execution time by subtracting the startTime from the current time.
  16. Prints the execution time to the console.
  17. Catches and prints any exceptions that occur during the execution of the method. sequence diagram

WeatherFunctionCallExample

The WeatherFunctionCallExample class is a public class used in software engineering. It represents an example of a function call related to weather. This class can be utilized to demonstrate the implementation and usage of a function that retrieves weather information.

public static void main(final String... args)

public static void main(final String... args) {
    try {
        final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
        new WeatherFunctionCallExample(client).runConversation();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

The main method in the WeatherFunctionCallExample class is used to invoke the WeatherFunctionCallExample's runConversation method. Here is a step-by-step description of what the method does:

  1. It is a public static method, which means it can be called without creating an instance of the class.

  2. It takes command-line arguments as String varargs (String... args).

  3. It starts by attempting to build an instance of OpenAIClient using the OPENAI_API_KEY environment variable as the API key.

  4. The OpenAIClient.builder() method is called to create a builder instance.

  5. The setApiKey(System.getenv("OPENAI_API_KEY")) method is called on the builder to set the API key using the OPENAI_API_KEY environment variable.

  6. The build() method is called on the builder to build the OpenAIClient instance.

  7. The WeatherFunctionCallExample constructor is called with the OpenAIClient instance as an argument to create a new instance of WeatherFunctionCallExample.

  8. The runConversation() method is called on the newly created WeatherFunctionCallExample instance to start the conversation.

  9. If any exception occurs during this process, it is caught and its stack trace is printed to the console.

That's the step-by-step description of what the main method in WeatherFunctionCallExample is doing based on its body. sequence diagram

public void runConversation()

public void runConversation() {
    // Call the ChatGPT chat with the user query.
    final var message = Message.builder().role(Role.USER).content("What's the weather like in Austin, TX in fahrenheit? What state is Austin? Is there anything special about austin").build();
    // And include the set of functions defined in the functions parameter.
    final var getCurrentWeatherFunc = getFunctionDefinition();
    final var chatBuilder = ChatRequest.builder().model("gpt-3.5-turbo-0613").addMessage(// user query
    message).addFunction(//function definitions
    getCurrentWeatherFunc).functionalCall(ChatRequest.AUTO);
    final var chatRequest = chatBuilder.build();
    final var chatResponse = client.chat(chatRequest);
    chatResponse.getResponse().ifPresent(response -> handleFunctionCallback(chatBuilder, response));
    System.out.println(chatResponse.getStatusCode().orElse(666));
    System.out.println(chatResponse.getStatusMessage().orElse(""));
    chatResponse.getException().ifPresent(e -> e.printStackTrace());
}

The runConversation method, defined in the WeatherFunctionCallExample class, performs the following steps:

  1. A Message object is created with the user role and query content. The query asks about the weather in Austin, TX in Fahrenheit, what state Austin is located in, and if there's anything special about Austin.

  2. The getFunctionDefinition method is called to obtain a function definition. The result is assigned to the getCurrentWeatherFunc variable.

  3. A ChatRequest builder is created with the model set to "gpt-3.5-turbo-0613". The previously created Message object is added as a user query using the addMessage method, and the getCurrentWeatherFunc function definition is added using the addFunction method. The functionalCall method is called with the ChatRequest.AUTO parameter.

  4. The chatBuilder instance is built into a ChatRequest using the build method and assigned to the chatRequest variable.

  5. The chat method is called on the client object with the chatRequest as the parameter. The response from the chat API is assigned to the chatResponse variable.

  6. If the response from the chat API contains a response message, the handleFunctionCallback method is called with the chatBuilder and the response message as arguments.

  7. The status code of the chatResponse is printed to the console. If the status code is not present, the value 666 is printed.

  8. The status message of the chatResponse is printed to the console. If the status message is not present, an empty string is printed.

  9. If an exception occurred during the chat API call, the exception stack trace is printed to the console. sequence diagram

private void handleFunctionCallback(final ChatRequest.Builder chatBuilder, final ChatResponse chatResponse)

private void handleFunctionCallback(final ChatRequest.Builder chatBuilder, final ChatResponse chatResponse) {
    var responseMessage = chatResponse.getChoices().get(0).getMessage();
    var functionCall = responseMessage.getFunctionCall();
    var functionResponse = getFunctionResponse(functionCall);
    chatBuilder.addMessage(Message.builder().name(functionCall.getName()).role(Role.FUNCTION).content(functionResponse).build());
    var response = client.chat(chatBuilder.build());
    response.getResponse().ifPresent(chatResponse1 -> System.out.println(chatResponse1.getChoices().get(0).getMessage().getContent()));
    if (response.getStatusMessage().isPresent()) {
        System.out.println(response.getStatusMessage().orElse(""));
    }
}

The handleFunctionCallback method is defined in the WeatherFunctionCallExample class. Here is a step-by-step description of what this method does:

  1. It takes two parameters: chatBuilder, which is an instance of ChatRequest.Builder, and chatResponse, which is an instance of ChatResponse.

  2. It retrieves the first choice message from chatResponse using getChoices().get(0), and then gets the message content from it using getMessage().

  3. It retrieves the function call from the message content using getFunctionCall().

  4. It calls the getFunctionResponse method (not shown in the given code snippet) to retrieve the function response based on the function call obtained in the previous step.

  5. It builds a new Message using Message.builder() with the function call name, role as Role.FUNCTION, and the obtained function response as the content. The built message is added to chatBuilder using chatBuilder.addMessage().

  6. It calls the chat method of a client object (not shown in the given code snippet) with chatBuilder.build() as the argument. The returned response is stored in a variable named response.

  7. It checks if the response has a non-empty getResponse() using response.getResponse().ifPresent(). If it does, it retrieves the first choice message from the response using chatResponse1.getChoices().get(0) and gets the content from it using getMessage().getContent(). The content is then printed to the console using System.out.println().

  8. It checks if the response has a status message using response.getStatusMessage().isPresent(). If it does, it retrieves the status message using response.getStatusMessage().orElse(""). The status message is then printed to the console using System.out.println().

Note: The specific implementation details of the getFunctionResponse method and the client object are not provided in the given code snippet and are not described in this step-by-step explanation. sequence diagram

WhoWonUFC290

The WhoWonUFC290 class is a public class that is used to determine the winner of UFC 290. It is designed specifically for the purpose of determining the winner of this specific UFC event.

public static String jsonGPT(String input)

public static String jsonGPT(String input) {
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final var chatRequest = ChatRequest.builder().addMessage(Message.builder().role(Role.SYSTEM).content("All output shall be JSON").build()).addMessage(Message.builder().role(Role.USER).content(input).build()).build();
    final var chat = client.chat(chatRequest);
    if (chat.getResponse().isPresent()) {
        return chat.getResponse().get().getChoices().get(0).getMessage().getContent();
    } else {
        System.out.println("" + chat.getStatusCode().orElse(666) + "" + chat.getStatusMessage().orElse(""));
        throw new IllegalStateException();
    }
}

Method: jsonGPT

Description:

This method takes a String input and makes a chat request to the OpenAI API using the OpenAIClient. It sends a chat request with a system message and a user message. The system message is fixed as "All output shall be JSON". The user message is the input passed to the method.

The chat request is sent to the OpenAI API, and the response is received. If a response is present, the method retrieves the content of the first choice in the response and returns it as a String. If no response is present, it prints the status code and status message returned by the chat request and throws an IllegalStateException.

Parameters:

  • input: String - The user input for the chat request.

Return Type:

  • String - The content of the first choice in the chat response.

Exceptions:

  • IllegalStateException - Thrown if the chat response does not contain a valid response.

Example Usage:

String input = "Who will win in UFC 290?";
String result = jsonGPT(input);
System.out.println(result);

Output:

The predicted winner in UFC 290 is ...

sequence diagram

public static List<float[]> embeddings(List input)

public static List<float[]> embeddings(List<String> input) {
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    var embedding = client.embedding(EmbeddingRequest.builder().model("text-embedding-ada-002").input(input).build());
    if (embedding.getResponse().isPresent()) {
        return embedding.getResponse().get().getData().stream().map(Embedding::getEmbedding).collect(Collectors.toList());
    } else {
        System.out.println("" + embedding.getStatusCode().orElse(666) + "" + embedding.getStatusMessage().orElse(""));
        throw new IllegalStateException();
    }
}

The method embeddings is defined in the class com.cloudurable.jai.examples.WhoWonUFC290. Here is a step-by-step description of what this method does:

  1. It takes a list of strings as input.
  2. It creates an instance of the OpenAIClient class, using the OpenAIClient.builder() method and setting the API key from the OPENAI_API_KEY system environment variable.
  3. It creates an EmbeddingRequest object, using the EmbeddingRequest.builder() method, and setting the model to "text-embedding-ada-002" and the input to the provided list of strings.
  4. It makes a request to the OpenAI service to generate embeddings for the input strings, using the client.embedding() method and passing the EmbeddingRequest object as a parameter.
  5. It checks if the response from the OpenAI service is present. If it is present, it retrieves the data from the response and extracts the embeddings from each element in the data. It returns a list of these embeddings.
  6. If the response is not present, it prints the status code and status message from the embedding object using embedding.getStatusCode().orElse(666) and embedding.getStatusMessage().orElse(""). It then throws an IllegalStateException.

Note: It's important to ensure that the necessary dependencies are imported, such as the com.cloudurable.jai.examples.WhoWonUFC290 class and the OpenAIClient and EmbeddingRequest classes. sequence diagram

public static void main(String... args)

public static void main(String... args) {
    try {
        long startTime = System.currentTimeMillis();
        // Generating queries based on user question
        String queriesJson = jsonGPT(QUERIES_INPUT.replace("{USER_QUESTION}", USER_QUESTION));
        List<String> queries = JsonParserBuilder.builder().build().parse(queriesJson).getObjectNode().getArrayNode("queries").filter(node -> node instanceof StringNode).stream().map(Object::toString).collect(Collectors.toList());
        queries.forEach(System.out::println);
        // Generating a hypothetical answer and its embedding
        var hypotheticalAnswer = hypotheticalAnswer();
        System.out.println(hypotheticalAnswer);
        var hypotheticalAnswerEmbedding = embeddings(hypotheticalAnswer);
        // Searching news articles based on the queries
        List<ArrayNode> results = queries.stream().map(WhoWonUFC290::searchNews).collect(Collectors.toList());
        // Extracting relevant information from the articles
        List<ObjectNode> articles = results.stream().map(arrayNode -> arrayNode.map(on -> on.asCollection().asObject())).flatMap(List::stream).collect(Collectors.toList());
        // Extracting article content and generating embeddings for each article
        List<String> articleContent = articles.stream().map(article -> String.format("%s %s %s", article.getString("title"), article.getString("description"), article.getString("content").substring(0, 100))).collect(Collectors.toList());
        List<float[]> articleEmbeddings = embeddings(articleContent);
        // Calculating cosine similarities between the hypothetical answer embedding and article embeddings
        List<Float> cosineSimilarities = articleEmbeddings.stream().map(articleEmbedding -> dot(hypotheticalAnswerEmbedding, articleEmbedding)).collect(Collectors.toList());
        // Creating a set of scored articles based on cosine similarities
        Set<ScoredArticle> articleSet = IntStream.range(0, Math.min(cosineSimilarities.size(), articleContent.size())).mapToObj(i -> new ScoredArticle(articles.get(i), cosineSimilarities.get(i))).collect(Collectors.toSet());
        // Sorting the articles based on their scores
        List<ScoredArticle> sortedArticles = new ArrayList<>(articleSet);
        Collections.sort(sortedArticles, (o1, o2) -> Float.compare(o2.getScore(), o1.getScore()));
        // Printing the top 5 scored articles
        sortedArticles.subList(0, 5).forEach(s -> System.out.println(s));
        // Formatting the top results as JSON strings
        String formattedTopResults = String.join(",\n", sortedArticles.stream().map(sa -> sa.getContent()).map(article -> String.format(Json.niceJson("{'title':'%s', 'url':'%s', 'description':'%s', 'content':'%s'}\n"), article.getString("title"), article.getString("url"), article.getString("description"), getArticleContent(article))).collect(Collectors.toList()).subList(0, 10));
        // Generating the final answer with the formatted top results
        String finalAnswer = jsonGPT(ANSWER_INPUT.replace("{USER_QUESTION}", USER_QUESTION).replace("{formatted_top_results}", formattedTopResults));
        System.out.println(finalAnswer);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

The main method defined in the com.cloudurable.jai.examples.WhoWonUFC290 class performs the following steps:

  1. It starts by capturing the start time using System.currentTimeMillis().

  2. It generates queries based on a user question by replacing {USER_QUESTION} with the actual user question in the QUERIES_INPUT String. The resulting queries are stored in a JSON object called queriesJson.

  3. It parses the queriesJson using a JsonParserBuilder and extracts the array of queries from it. It filters out non-string nodes and converts each query to a string. Finally, it prints each query.

  4. It generates a hypothetical answer using the hypotheticalAnswer() method and prints it.

  5. It generates the embedding for the hypothetical answer using the embeddings() method.

  6. It searches for news articles based on the queries using the searchNews() method, which returns a list of ArrayNode objects.

  7. It extracts relevant information from the articles, such as the title, description, and the first 100 characters of the content. This information is stored in a list called articleContent.

  8. It generates embeddings for each article in the articleContent list using the embeddings() method.

  9. It calculates the cosine similarity between the hypothetical answer embedding and each article embedding. The cosine similarities are stored in a list called cosineSimilarities.

  10. It creates a set of scored articles by associating each article with its respective cosine similarity. These scored articles are stored as instances of ScoredArticle.

  11. It sorts the scored articles based on their scores in descending order using a custom Comparator.

  12. It prints the top 5 scored articles.

  13. It formats the top results as JSON strings by extracting the necessary fields from each article and generating a formatted JSON string. The formatted top results are stored in the formattedTopResults string.

  14. It generates the final answer using the ANSWER_INPUT string, which is similar to the QUERIES_INPUT string but also includes the formattedTopResults in place of {formatted_top_results}.

  15. It captures the end time using System.currentTimeMillis() and calculates the elapsed time by subtracting the start time from the end time.

  16. Finally, it handles any exceptions that occur during the execution of the method by printing the stack trace. sequence diagram

public static float dot(float[] v1, float[] v2)

public static float dot(float[] v1, float[] v2) {
    assert v1.length == v2.length;
    float result = 0;
    for (int i = 0; i < v1.length; i++) {
        result += v1[i] * v2[i];
    }
    return result;
}

This method, dot, is a static method defined in the com.cloudurable.jai.examples.WhoWonUFC290 class. It takes in two float arrays, v1 and v2. Here is a step-by-step description of what the method does:

  1. The method starts with an assertion to check if the lengths of v1 and v2 are equal. This ensures that both arrays have the same number of elements. If the lengths are not equal, an AssertionError is thrown.

  2. Next, a float variable called result is initialized to 0. This variable will store the final dot product of v1 and v2.

  3. A for loop is used to iterate over the elements of v1 and v2. The loop starts with i initialized to 0 and continues as long as i is less than the length of v1. In each iteration, the current element of v1 and v2 at index i are multiplied and added to the result variable.

  4. After the loop finishes, the final dot product (result) is returned.

To summarize, this dot method calculates the dot product of two float arrays, v1 and v2, by multiplying the corresponding elements of the arrays and summing them up. It assumes both arrays have the same length and throws an exception if this condition is not met. sequence diagram

private static void handleArticle(ObjectNode node)

private static void handleArticle(ObjectNode node) {
    System.out.println("# " + node.getString("title"));
    if (node.get("author") != null) {
        System.out.println("#### author: " + node.getString("author"));
    }
    final var client = OpenAIClient.builder().setApiKey(System.getenv("OPENAI_API_KEY")).build();
    final var chatRequest = ChatRequest.builder().addMessage(Message.builder().role(Role.SYSTEM).content("All output shall be Markdown").build()).addMessage(Message.builder().role(Role.USER).content("First Summarize this article to less than 500 words while " + "getting all of the main points. Also Extract the author, publication, publication date, and link to the article ||| " + node).build()).addMessage(Message.builder().role(Role.USER).content("Then create 10 high level bullet points from the article").build()).build();
    ClientResponse<ChatRequest, ChatResponse> chat = client.chat(chatRequest);
    if (chat.getResponse().isPresent()) {
        System.out.println(chat.getResponse().get().getChoices().get(0).getMessage().getContent());
    } else {
        System.out.println("" + chat.getStatusCode().orElse(666) + "" + chat.getStatusMessage().orElse(""));
    }
    System.out.println("------");
}

The handleArticle method in the class com.cloudurable.jai.examples.WhoWonUFC290 performs the following steps:

  1. Print the title of the article, prepended with a "#" symbol.
  2. Check if the "author" field exists in the node object. If it does, print the author's name, prepended with "#### author: ".
  3. Create an instance of the OpenAIClient class, passing the API key obtained from the OPENAI_API_KEY environment variable.
  4. Construct a ChatRequest object with the following messages:
    • The first message is a system message, indicating that all output should be in Markdown format.
    • The second message is a user message, consisting of a string that includes instructions to summarize the article to less than 500 words and extract various information (author, publication, publication date, and link) from the node object.
    • The third message is a user message, requesting the creation of 10 high-level bullet points from the article.
  5. Use the client to execute the chat request and store the response in a ClientResponse object.
  6. If the response is present, print the content of the first choice in the response (which contains the summarized article and bullet points).
  7. If the response is not present, print a string that includes the status code and status message of the client response.
  8. Print a line of dashes ("------") to separate multiple invocations of the handleArticle method. sequence diagram

public static ArrayNode searchNews(final String query, final Instant start, final Instant end, final int pageSize)

public static ArrayNode searchNews(final String query, final Instant start, final Instant end, final int pageSize) {
    System.out.println(query);
    try {
        String url = "https://newsapi.org/v2/everything?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8) + "&apiKey=" + System.getenv("NEWS_API_KEY") + "&language=en" + "&sortBy=relevancy" + "&from=" + dateStr(start) + "&to=" + dateStr(end) + "&pageSize=" + pageSize;
        HttpClient httpClient = HttpClient.newHttpClient();
        HttpResponse<String> response = httpClient.send(HttpRequest.newBuilder().uri(URI.create(url)).GET().setHeader("Content-Type", "application/json").build(), HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 200 && response.statusCode() < 299) {
            return JsonParserBuilder.builder().build().parse(response.body()).atPath("articles").asCollection().asArray();
        } else {
            throw new IllegalStateException(" status code " + response.statusCode() + " " + response.body());
        }
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
}

The searchNews method is a public static method defined in the class com.cloudurable.jai.examples.WhoWonUFC290. This method retrieves news articles based on a given query, start date, end date, and page size.

Here is a step-by-step description of what the method does:

  1. The method takes four parameters: query (a string representing the search query), start (an Instant representing the start date), end (an Instant representing the end date), and pageSize (an integer representing the number of articles to retrieve per page).

  2. The method first prints out the value of the query parameter using System.out.println(), which is most likely for logging or debugging purposes.

  3. The method then constructs a URL string using the provided parameters. The URL is created using the newsapi.org API and includes the search query, API key, language (English), sorting method (relevancy), start date, end date, and page size.

  4. A new instance of the HttpClient class is created using the newHttpClient() method.

  5. The URL is used to create a new HttpRequest object with the appropriate HTTP method (GET) and headers (Content-Type: application/json).

  6. The send() method of the HttpClient is called passing the HttpRequest object and the HttpResponse.BodyHandlers.ofString() object as arguments. This sends the request to the API and returns the response as a HttpResponse<String> object.

  7. The method checks if the response status code is between 200 and 299 (indicating a successful response). If it is, the method parses the response body as a JSON string and retrieves the "articles" field using JsonParserBuilder and returns it as an ArrayNode.

  8. If the response status code is not in the range of 200-299, an IllegalStateException is thrown with a message that includes the response status code and body.

  9. If any exception occurs during the execution of the method, it is caught in a catch block and re-thrown as a new IllegalStateException with the original exception as the cause.

sequence diagram

⚠️ **GitHub.com Fallback** ⚠️