From 04124cf978acb79fa0d5f9306782dc3f2ecd1e95 Mon Sep 17 00:00:00 2001 From: Amith Koujalgi Date: Tue, 14 May 2024 10:27:56 +0530 Subject: [PATCH] Updated default request timeout to 10 seconds --- docs/docs/apis-generate/chat.md | 2 +- .../ollama4j/core/OllamaAPI.java | 1067 ++++++++--------- .../models/request/OllamaEndpointCaller.java | 197 ++- 3 files changed, 628 insertions(+), 638 deletions(-) diff --git a/docs/docs/apis-generate/chat.md b/docs/docs/apis-generate/chat.md index 5c4dc20..b4d51b1 100644 --- a/docs/docs/apis-generate/chat.md +++ b/docs/docs/apis-generate/chat.md @@ -112,7 +112,7 @@ You will get a response similar to: ## Use a simple Console Output Stream Handler -``` +```java import io.github.amithkoujalgi.ollama4j.core.impl.ConsoleOutputStreamHandler; public class Main { diff --git a/src/main/java/io/github/amithkoujalgi/ollama4j/core/OllamaAPI.java b/src/main/java/io/github/amithkoujalgi/ollama4j/core/OllamaAPI.java index 25b3a37..1f22210 100644 --- a/src/main/java/io/github/amithkoujalgi/ollama4j/core/OllamaAPI.java +++ b/src/main/java/io/github/amithkoujalgi/ollama4j/core/OllamaAPI.java @@ -9,18 +9,13 @@ import io.github.amithkoujalgi.ollama4j.core.models.chat.OllamaChatResult; import io.github.amithkoujalgi.ollama4j.core.models.embeddings.OllamaEmbeddingResponseModel; import io.github.amithkoujalgi.ollama4j.core.models.embeddings.OllamaEmbeddingsRequestModel; import io.github.amithkoujalgi.ollama4j.core.models.generate.OllamaGenerateRequestModel; -import io.github.amithkoujalgi.ollama4j.core.models.request.CustomModelFileContentsRequest; -import io.github.amithkoujalgi.ollama4j.core.models.request.CustomModelFilePathRequest; -import io.github.amithkoujalgi.ollama4j.core.models.request.ModelRequest; -import io.github.amithkoujalgi.ollama4j.core.models.request.OllamaChatEndpointCaller; -import io.github.amithkoujalgi.ollama4j.core.models.request.OllamaGenerateEndpointCaller; +import io.github.amithkoujalgi.ollama4j.core.models.request.*; import io.github.amithkoujalgi.ollama4j.core.utils.Options; import io.github.amithkoujalgi.ollama4j.core.utils.Utils; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; @@ -33,554 +28,552 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Base64; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -/** The base Ollama API class. */ +/** + * The base Ollama API class. + */ @SuppressWarnings("DuplicatedCode") public class OllamaAPI { - private static final Logger logger = LoggerFactory.getLogger(OllamaAPI.class); - private final String host; - private long requestTimeoutSeconds = 3; - private boolean verbose = true; - private BasicAuth basicAuth; - - /** - * Instantiates the Ollama API. - * - * @param host the host address of Ollama server - */ - public OllamaAPI(String host) { - if (host.endsWith("/")) { - this.host = host.substring(0, host.length() - 1); - } else { - this.host = host; - } - } - - /** - * Set request timeout in seconds. Default is 3 seconds. - * - * @param requestTimeoutSeconds the request timeout in seconds - */ - public void setRequestTimeoutSeconds(long requestTimeoutSeconds) { - this.requestTimeoutSeconds = requestTimeoutSeconds; - } - - /** - * Set/unset logging of responses - * - * @param verbose true/false - */ - public void setVerbose(boolean verbose) { - this.verbose = verbose; - } - - /** - * Set basic authentication for accessing Ollama server that's behind a reverse-proxy/gateway. - * - * @param username the username - * @param password the password - */ - public void setBasicAuth(String username, String password) { - this.basicAuth = new BasicAuth(username, password); - } - - /** - * API to check the reachability of Ollama server. - * - * @return true if the server is reachable, false otherwise. - */ - public boolean ping() { - String url = this.host + "/api/tags"; - HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest httpRequest = null; - try { - httpRequest = - getRequestBuilderDefault(new URI(url)) - .header("Accept", "application/json") - .header("Content-type", "application/json") - .GET() - .build(); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - HttpResponse response = null; - try { - response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - } catch (HttpConnectTimeoutException e) { - return false; - } catch (IOException | InterruptedException e) { - throw new RuntimeException(e); - } - int statusCode = response.statusCode(); - return statusCode == 200; - } - - /** - * List available models from Ollama server. - * - * @return the list - */ - public List listModels() - throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { - String url = this.host + "/api/tags"; - HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest httpRequest = - getRequestBuilderDefault(new URI(url)) - .header("Accept", "application/json") - .header("Content-type", "application/json") - .GET() - .build(); - HttpResponse response = - httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseString = response.body(); - if (statusCode == 200) { - return Utils.getObjectMapper() - .readValue(responseString, ListModelsResponse.class) - .getModels(); - } else { - throw new OllamaBaseException(statusCode + " - " + responseString); - } - } - - /** - * Pull a model on the Ollama server from the list of available models. - * - * @param modelName the name of the model - */ - public void pullModel(String modelName) - throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { - String url = this.host + "/api/pull"; - String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = - getRequestBuilderDefault(new URI(url)) - .POST(HttpRequest.BodyPublishers.ofString(jsonData)) - .header("Accept", "application/json") - .header("Content-type", "application/json") - .build(); - HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = - client.send(request, HttpResponse.BodyHandlers.ofInputStream()); - int statusCode = response.statusCode(); - InputStream responseBodyStream = response.body(); - String responseString = ""; - try (BufferedReader reader = - new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { - String line; - while ((line = reader.readLine()) != null) { - ModelPullResponse modelPullResponse = - Utils.getObjectMapper().readValue(line, ModelPullResponse.class); - if (verbose) { - logger.info(modelPullResponse.getStatus()); - } - } - } - if (statusCode != 200) { - throw new OllamaBaseException(statusCode + " - " + responseString); - } - } - - /** - * Gets model details from the Ollama server. - * - * @param modelName the model - * @return the model details - */ - public ModelDetail getModelDetails(String modelName) - throws IOException, OllamaBaseException, InterruptedException, URISyntaxException { - String url = this.host + "/api/show"; - String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = - getRequestBuilderDefault(new URI(url)) - .header("Accept", "application/json") - .header("Content-type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(jsonData)) - .build(); - HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseBody = response.body(); - if (statusCode == 200) { - return Utils.getObjectMapper().readValue(responseBody, ModelDetail.class); - } else { - throw new OllamaBaseException(statusCode + " - " + responseBody); - } - } - - /** - * Create a custom model from a model file. Read more about custom model file creation here. - * - * @param modelName the name of the custom model to be created. - * @param modelFilePath the path to model file that exists on the Ollama server. - */ - public void createModelWithFilePath(String modelName, String modelFilePath) - throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { - String url = this.host + "/api/create"; - String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString(); - HttpRequest request = - getRequestBuilderDefault(new URI(url)) - .header("Accept", "application/json") - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) - .build(); - HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseString = response.body(); - if (statusCode != 200) { - throw new OllamaBaseException(statusCode + " - " + responseString); - } - // FIXME: Ollama API returns HTTP status code 200 for model creation failure cases. Correct this - // if the issue is fixed in the Ollama API server. - if (responseString.contains("error")) { - throw new OllamaBaseException(responseString); - } - if (verbose) { - logger.info(responseString); - } - } - - /** - * Create a custom model from a model file. Read more about custom model file creation here. - * - * @param modelName the name of the custom model to be created. - * @param modelFileContents the path to model file that exists on the Ollama server. - */ - public void createModelWithModelFileContents(String modelName, String modelFileContents) - throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { - String url = this.host + "/api/create"; - String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString(); - HttpRequest request = - getRequestBuilderDefault(new URI(url)) - .header("Accept", "application/json") - .header("Content-Type", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) - .build(); - HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseString = response.body(); - if (statusCode != 200) { - throw new OllamaBaseException(statusCode + " - " + responseString); - } - if (responseString.contains("error")) { - throw new OllamaBaseException(responseString); - } - if (verbose) { - logger.info(responseString); - } - } - - /** - * Delete a model from Ollama server. - * - * @param modelName the name of the model to be deleted. - * @param ignoreIfNotPresent ignore errors if the specified model is not present on Ollama server. - */ - public void deleteModel(String modelName, boolean ignoreIfNotPresent) - throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { - String url = this.host + "/api/delete"; - String jsonData = new ModelRequest(modelName).toString(); - HttpRequest request = - getRequestBuilderDefault(new URI(url)) - .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) - .header("Accept", "application/json") - .header("Content-type", "application/json") - .build(); - HttpClient client = HttpClient.newHttpClient(); - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseBody = response.body(); - if (statusCode == 404 && responseBody.contains("model") && responseBody.contains("not found")) { - return; - } - if (statusCode != 200) { - throw new OllamaBaseException(statusCode + " - " + responseBody); - } - } - - /** - * Generate embeddings for a given text from a model - * - * @param model name of model to generate embeddings from - * @param prompt text to generate embeddings for - * @return embeddings - */ - public List generateEmbeddings(String model, String prompt) - throws IOException, InterruptedException, OllamaBaseException { - return generateEmbeddings(new OllamaEmbeddingsRequestModel(model, prompt)); - } + private static final Logger logger = LoggerFactory.getLogger(OllamaAPI.class); + private final String host; + private long requestTimeoutSeconds = 10; + private boolean verbose = true; + private BasicAuth basicAuth; /** - * Generate embeddings using a {@link OllamaEmbeddingsRequestModel}. - * - * @param modelRequest request for '/api/embeddings' endpoint - * @return embeddings - */ - public List generateEmbeddings(OllamaEmbeddingsRequestModel modelRequest) throws IOException, InterruptedException, OllamaBaseException{ - URI uri = URI.create(this.host + "/api/embeddings"); - String jsonData = modelRequest.toString(); - HttpClient httpClient = HttpClient.newHttpClient(); - HttpRequest.Builder requestBuilder = - getRequestBuilderDefault(uri) - .header("Accept", "application/json") - .POST(HttpRequest.BodyPublishers.ofString(jsonData)); - HttpRequest request = requestBuilder.build(); - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - String responseBody = response.body(); - if (statusCode == 200) { - OllamaEmbeddingResponseModel embeddingResponse = - Utils.getObjectMapper().readValue(responseBody, OllamaEmbeddingResponseModel.class); - return embeddingResponse.getEmbedding(); - } else { - throw new OllamaBaseException(statusCode + " - " + responseBody); + * Instantiates the Ollama API. + * + * @param host the host address of Ollama server + */ + public OllamaAPI(String host) { + if (host.endsWith("/")) { + this.host = host.substring(0, host.length() - 1); + } else { + this.host = host; + } } - } - /** - * Generate response for a question to a model running on Ollama server. This is a sync/blocking - * call. - * - * @param model the ollama model to ask the question to - * @param prompt the prompt/question text - * @param options the Options object - More - * details on the options - * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. - * @return OllamaResult that includes response text and time taken for response - */ - public OllamaResult generate(String model, String prompt, Options options, OllamaStreamHandler streamHandler) - throws OllamaBaseException, IOException, InterruptedException { - OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt); - ollamaRequestModel.setOptions(options.getOptionsMap()); - return generateSyncForOllamaRequestModel(ollamaRequestModel,streamHandler); - } - - /** - * Convenience method to call Ollama API without streaming responses. - * - * Uses {@link #generate(String, String, Options, OllamaStreamHandler)} - */ - public OllamaResult generate(String model, String prompt, Options options) - throws OllamaBaseException, IOException, InterruptedException { - return generate(model, prompt, options,null); - } - - /** - * Generate response for a question to a model running on Ollama server and get a callback handle - * that can be used to check for status and get the response from the model later. This would be - * an async/non-blocking call. - * - * @param model the ollama model to ask the question to - * @param prompt the prompt/question text - * @return the ollama async result callback handle - */ - public OllamaAsyncResultCallback generateAsync(String model, String prompt) { - OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt); - - URI uri = URI.create(this.host + "/api/generate"); - OllamaAsyncResultCallback ollamaAsyncResultCallback = - new OllamaAsyncResultCallback( - getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); - ollamaAsyncResultCallback.start(); - return ollamaAsyncResultCallback; - } - - /** - * With one or more image files, ask a question to a model running on Ollama server. This is a - * sync/blocking call. - * - * @param model the ollama model to ask the question to - * @param prompt the prompt/question text - * @param imageFiles the list of image files to use for the question - * @param options the Options object - More - * details on the options - * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. - * @return OllamaResult that includes response text and time taken for response - */ - public OllamaResult generateWithImageFiles( - String model, String prompt, List imageFiles, Options options, OllamaStreamHandler streamHandler) - throws OllamaBaseException, IOException, InterruptedException { - List images = new ArrayList<>(); - for (File imageFile : imageFiles) { - images.add(encodeFileToBase64(imageFile)); + /** + * Set request timeout in seconds. Default is 3 seconds. + * + * @param requestTimeoutSeconds the request timeout in seconds + */ + public void setRequestTimeoutSeconds(long requestTimeoutSeconds) { + this.requestTimeoutSeconds = requestTimeoutSeconds; } - OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt, images); - ollamaRequestModel.setOptions(options.getOptionsMap()); - return generateSyncForOllamaRequestModel(ollamaRequestModel,streamHandler); - } - /** - * Convenience method to call Ollama API without streaming responses. - * - * Uses {@link #generateWithImageFiles(String, String, List, Options, OllamaStreamHandler)} - */ - public OllamaResult generateWithImageFiles( - String model, String prompt, List imageFiles, Options options) - throws OllamaBaseException, IOException, InterruptedException{ - return generateWithImageFiles(model, prompt, imageFiles, options, null); -} - - /** - * With one or more image URLs, ask a question to a model running on Ollama server. This is a - * sync/blocking call. - * - * @param model the ollama model to ask the question to - * @param prompt the prompt/question text - * @param imageURLs the list of image URLs to use for the question - * @param options the Options object - More - * details on the options - * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. - * @return OllamaResult that includes response text and time taken for response - */ - public OllamaResult generateWithImageURLs( - String model, String prompt, List imageURLs, Options options, OllamaStreamHandler streamHandler) - throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { - List images = new ArrayList<>(); - for (String imageURL : imageURLs) { - images.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl(imageURL))); + /** + * Set/unset logging of responses + * + * @param verbose true/false + */ + public void setVerbose(boolean verbose) { + this.verbose = verbose; } - OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt, images); - ollamaRequestModel.setOptions(options.getOptionsMap()); - return generateSyncForOllamaRequestModel(ollamaRequestModel,streamHandler); - } - /** - * Convenience method to call Ollama API without streaming responses. - * - * Uses {@link #generateWithImageURLs(String, String, List, Options, OllamaStreamHandler)} - */ - public OllamaResult generateWithImageURLs(String model, String prompt, List imageURLs, - Options options) - throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { - return generateWithImageURLs(model, prompt, imageURLs, options, null); - } + /** + * Set basic authentication for accessing Ollama server that's behind a reverse-proxy/gateway. + * + * @param username the username + * @param password the password + */ + public void setBasicAuth(String username, String password) { + this.basicAuth = new BasicAuth(username, password); + } + + /** + * API to check the reachability of Ollama server. + * + * @return true if the server is reachable, false otherwise. + */ + public boolean ping() { + String url = this.host + "/api/tags"; + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest httpRequest = null; + try { + httpRequest = + getRequestBuilderDefault(new URI(url)) + .header("Accept", "application/json") + .header("Content-type", "application/json") + .GET() + .build(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + HttpResponse response = null; + try { + response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + } catch (HttpConnectTimeoutException e) { + return false; + } catch (IOException | InterruptedException e) { + throw new RuntimeException(e); + } + int statusCode = response.statusCode(); + return statusCode == 200; + } + + /** + * List available models from Ollama server. + * + * @return the list + */ + public List listModels() + throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { + String url = this.host + "/api/tags"; + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest httpRequest = + getRequestBuilderDefault(new URI(url)) + .header("Accept", "application/json") + .header("Content-type", "application/json") + .GET() + .build(); + HttpResponse response = + httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseString = response.body(); + if (statusCode == 200) { + return Utils.getObjectMapper() + .readValue(responseString, ListModelsResponse.class) + .getModels(); + } else { + throw new OllamaBaseException(statusCode + " - " + responseString); + } + } + + /** + * Pull a model on the Ollama server from the list of available models. + * + * @param modelName the name of the model + */ + public void pullModel(String modelName) + throws OllamaBaseException, IOException, URISyntaxException, InterruptedException { + String url = this.host + "/api/pull"; + String jsonData = new ModelRequest(modelName).toString(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .header("Accept", "application/json") + .header("Content-type", "application/json") + .build(); + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = + client.send(request, HttpResponse.BodyHandlers.ofInputStream()); + int statusCode = response.statusCode(); + InputStream responseBodyStream = response.body(); + String responseString = ""; + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + ModelPullResponse modelPullResponse = + Utils.getObjectMapper().readValue(line, ModelPullResponse.class); + if (verbose) { + logger.info(modelPullResponse.getStatus()); + } + } + } + if (statusCode != 200) { + throw new OllamaBaseException(statusCode + " - " + responseString); + } + } + + /** + * Gets model details from the Ollama server. + * + * @param modelName the model + * @return the model details + */ + public ModelDetail getModelDetails(String modelName) + throws IOException, OllamaBaseException, InterruptedException, URISyntaxException { + String url = this.host + "/api/show"; + String jsonData = new ModelRequest(modelName).toString(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .header("Accept", "application/json") + .header("Content-type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonData)) + .build(); + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseBody = response.body(); + if (statusCode == 200) { + return Utils.getObjectMapper().readValue(responseBody, ModelDetail.class); + } else { + throw new OllamaBaseException(statusCode + " - " + responseBody); + } + } + + /** + * Create a custom model from a model file. Read more about custom model file creation here. + * + * @param modelName the name of the custom model to be created. + * @param modelFilePath the path to model file that exists on the Ollama server. + */ + public void createModelWithFilePath(String modelName, String modelFilePath) + throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { + String url = this.host + "/api/create"; + String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) + .build(); + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseString = response.body(); + if (statusCode != 200) { + throw new OllamaBaseException(statusCode + " - " + responseString); + } + // FIXME: Ollama API returns HTTP status code 200 for model creation failure cases. Correct this + // if the issue is fixed in the Ollama API server. + if (responseString.contains("error")) { + throw new OllamaBaseException(responseString); + } + if (verbose) { + logger.info(responseString); + } + } + + /** + * Create a custom model from a model file. Read more about custom model file creation here. + * + * @param modelName the name of the custom model to be created. + * @param modelFileContents the path to model file that exists on the Ollama server. + */ + public void createModelWithModelFileContents(String modelName, String modelFileContents) + throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { + String url = this.host + "/api/create"; + String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .header("Accept", "application/json") + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) + .build(); + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseString = response.body(); + if (statusCode != 200) { + throw new OllamaBaseException(statusCode + " - " + responseString); + } + if (responseString.contains("error")) { + throw new OllamaBaseException(responseString); + } + if (verbose) { + logger.info(responseString); + } + } + + /** + * Delete a model from Ollama server. + * + * @param modelName the name of the model to be deleted. + * @param ignoreIfNotPresent ignore errors if the specified model is not present on Ollama server. + */ + public void deleteModel(String modelName, boolean ignoreIfNotPresent) + throws IOException, InterruptedException, OllamaBaseException, URISyntaxException { + String url = this.host + "/api/delete"; + String jsonData = new ModelRequest(modelName).toString(); + HttpRequest request = + getRequestBuilderDefault(new URI(url)) + .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) + .header("Accept", "application/json") + .header("Content-type", "application/json") + .build(); + HttpClient client = HttpClient.newHttpClient(); + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseBody = response.body(); + if (statusCode == 404 && responseBody.contains("model") && responseBody.contains("not found")) { + return; + } + if (statusCode != 200) { + throw new OllamaBaseException(statusCode + " - " + responseBody); + } + } + + /** + * Generate embeddings for a given text from a model + * + * @param model name of model to generate embeddings from + * @param prompt text to generate embeddings for + * @return embeddings + */ + public List generateEmbeddings(String model, String prompt) + throws IOException, InterruptedException, OllamaBaseException { + return generateEmbeddings(new OllamaEmbeddingsRequestModel(model, prompt)); + } + + /** + * Generate embeddings using a {@link OllamaEmbeddingsRequestModel}. + * + * @param modelRequest request for '/api/embeddings' endpoint + * @return embeddings + */ + public List generateEmbeddings(OllamaEmbeddingsRequestModel modelRequest) throws IOException, InterruptedException, OllamaBaseException { + URI uri = URI.create(this.host + "/api/embeddings"); + String jsonData = modelRequest.toString(); + HttpClient httpClient = HttpClient.newHttpClient(); + HttpRequest.Builder requestBuilder = + getRequestBuilderDefault(uri) + .header("Accept", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonData)); + HttpRequest request = requestBuilder.build(); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + String responseBody = response.body(); + if (statusCode == 200) { + OllamaEmbeddingResponseModel embeddingResponse = + Utils.getObjectMapper().readValue(responseBody, OllamaEmbeddingResponseModel.class); + return embeddingResponse.getEmbedding(); + } else { + throw new OllamaBaseException(statusCode + " - " + responseBody); + } + } + + /** + * Generate response for a question to a model running on Ollama server. This is a sync/blocking + * call. + * + * @param model the ollama model to ask the question to + * @param prompt the prompt/question text + * @param options the Options object - More + * details on the options + * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. + * @return OllamaResult that includes response text and time taken for response + */ + public OllamaResult generate(String model, String prompt, Options options, OllamaStreamHandler streamHandler) + throws OllamaBaseException, IOException, InterruptedException { + OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt); + ollamaRequestModel.setOptions(options.getOptionsMap()); + return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler); + } + + /** + * Convenience method to call Ollama API without streaming responses. + *

+ * Uses {@link #generate(String, String, Options, OllamaStreamHandler)} + */ + public OllamaResult generate(String model, String prompt, Options options) + throws OllamaBaseException, IOException, InterruptedException { + return generate(model, prompt, options, null); + } + + /** + * Generate response for a question to a model running on Ollama server and get a callback handle + * that can be used to check for status and get the response from the model later. This would be + * an async/non-blocking call. + * + * @param model the ollama model to ask the question to + * @param prompt the prompt/question text + * @return the ollama async result callback handle + */ + public OllamaAsyncResultCallback generateAsync(String model, String prompt) { + OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt); + + URI uri = URI.create(this.host + "/api/generate"); + OllamaAsyncResultCallback ollamaAsyncResultCallback = + new OllamaAsyncResultCallback( + getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds); + ollamaAsyncResultCallback.start(); + return ollamaAsyncResultCallback; + } + + /** + * With one or more image files, ask a question to a model running on Ollama server. This is a + * sync/blocking call. + * + * @param model the ollama model to ask the question to + * @param prompt the prompt/question text + * @param imageFiles the list of image files to use for the question + * @param options the Options object - More + * details on the options + * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. + * @return OllamaResult that includes response text and time taken for response + */ + public OllamaResult generateWithImageFiles( + String model, String prompt, List imageFiles, Options options, OllamaStreamHandler streamHandler) + throws OllamaBaseException, IOException, InterruptedException { + List images = new ArrayList<>(); + for (File imageFile : imageFiles) { + images.add(encodeFileToBase64(imageFile)); + } + OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt, images); + ollamaRequestModel.setOptions(options.getOptionsMap()); + return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler); + } + + /** + * Convenience method to call Ollama API without streaming responses. + *

+ * Uses {@link #generateWithImageFiles(String, String, List, Options, OllamaStreamHandler)} + */ + public OllamaResult generateWithImageFiles( + String model, String prompt, List imageFiles, Options options) + throws OllamaBaseException, IOException, InterruptedException { + return generateWithImageFiles(model, prompt, imageFiles, options, null); + } + + /** + * With one or more image URLs, ask a question to a model running on Ollama server. This is a + * sync/blocking call. + * + * @param model the ollama model to ask the question to + * @param prompt the prompt/question text + * @param imageURLs the list of image URLs to use for the question + * @param options the Options object - More + * details on the options + * @param streamHandler optional callback consumer that will be applied every time a streamed response is received. If not set, the stream parameter of the request is set to false. + * @return OllamaResult that includes response text and time taken for response + */ + public OllamaResult generateWithImageURLs( + String model, String prompt, List imageURLs, Options options, OllamaStreamHandler streamHandler) + throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { + List images = new ArrayList<>(); + for (String imageURL : imageURLs) { + images.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl(imageURL))); + } + OllamaGenerateRequestModel ollamaRequestModel = new OllamaGenerateRequestModel(model, prompt, images); + ollamaRequestModel.setOptions(options.getOptionsMap()); + return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler); + } + + /** + * Convenience method to call Ollama API without streaming responses. + *

+ * Uses {@link #generateWithImageURLs(String, String, List, Options, OllamaStreamHandler)} + */ + public OllamaResult generateWithImageURLs(String model, String prompt, List imageURLs, + Options options) + throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { + return generateWithImageURLs(model, prompt, imageURLs, options, null); + } - - /** - * Ask a question to a model based on a given message stack (i.e. a chat history). Creates a synchronous call to the api - * 'api/chat'. - * - * @param model the ollama model to ask the question to - * @param messages chat history / message stack to send to the model - * @return {@link OllamaChatResult} containing the api response and the message history including the newly aqcuired assistant response. - * @throws OllamaBaseException any response code than 200 has been returned - * @throws IOException in case the responseStream can not be read + /** + * Ask a question to a model based on a given message stack (i.e. a chat history). Creates a synchronous call to the api + * 'api/chat'. + * + * @param model the ollama model to ask the question to + * @param messages chat history / message stack to send to the model + * @return {@link OllamaChatResult} containing the api response and the message history including the newly aqcuired assistant response. + * @throws OllamaBaseException any response code than 200 has been returned + * @throws IOException in case the responseStream can not be read * @throws InterruptedException in case the server is not reachable or network issues happen - */ - public OllamaChatResult chat(String model, List messages) throws OllamaBaseException, IOException, InterruptedException{ - OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(model); - return chat(builder.withMessages(messages).build()); - } - - /** - * Ask a question to a model using an {@link OllamaChatRequestModel}. This can be constructed using an {@link OllamaChatRequestBuilder}. - * - * Hint: the OllamaChatRequestModel#getStream() property is not implemented. - * - * @param request request object to be sent to the server - * @return - * @throws OllamaBaseException any response code than 200 has been returned - * @throws IOException in case the responseStream can not be read - * @throws InterruptedException in case the server is not reachable or network issues happen - */ - public OllamaChatResult chat(OllamaChatRequestModel request) throws OllamaBaseException, IOException, InterruptedException{ - return chat(request,null); - } - - /** - * Ask a question to a model using an {@link OllamaChatRequestModel}. This can be constructed using an {@link OllamaChatRequestBuilder}. - * - * Hint: the OllamaChatRequestModel#getStream() property is not implemented. - * - * @param request request object to be sent to the server - * @param streamHandler callback handler to handle the last message from stream (caution: all previous messages from stream will be concatenated) - * @return - * @throws OllamaBaseException any response code than 200 has been returned - * @throws IOException in case the responseStream can not be read - * @throws InterruptedException in case the server is not reachable or network issues happen - */ - public OllamaChatResult chat(OllamaChatRequestModel request, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException{ - OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); - OllamaResult result; - if(streamHandler != null){ - request.setStream(true); - result = requestCaller.call(request, streamHandler); + */ + public OllamaChatResult chat(String model, List messages) throws OllamaBaseException, IOException, InterruptedException { + OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(model); + return chat(builder.withMessages(messages).build()); } - else { - result = requestCaller.callSync(request); + + /** + * Ask a question to a model using an {@link OllamaChatRequestModel}. This can be constructed using an {@link OllamaChatRequestBuilder}. + *

+ * Hint: the OllamaChatRequestModel#getStream() property is not implemented. + * + * @param request request object to be sent to the server + * @return + * @throws OllamaBaseException any response code than 200 has been returned + * @throws IOException in case the responseStream can not be read + * @throws InterruptedException in case the server is not reachable or network issues happen + */ + public OllamaChatResult chat(OllamaChatRequestModel request) throws OllamaBaseException, IOException, InterruptedException { + return chat(request, null); } - return new OllamaChatResult(result.getResponse(), result.getResponseTime(), result.getHttpStatusCode(), request.getMessages()); - } - // technical private methods // - - private static String encodeFileToBase64(File file) throws IOException { - return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath())); - } - - private static String encodeByteArrayToBase64(byte[] bytes) { - return Base64.getEncoder().encodeToString(bytes); - } - - private OllamaResult generateSyncForOllamaRequestModel( - OllamaGenerateRequestModel ollamaRequestModel, OllamaStreamHandler streamHandler) - throws OllamaBaseException, IOException, InterruptedException { - OllamaGenerateEndpointCaller requestCaller = - new OllamaGenerateEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); - OllamaResult result; - if (streamHandler != null) { - ollamaRequestModel.setStream(true); - result = requestCaller.call(ollamaRequestModel, streamHandler); - } else { - result = requestCaller.callSync(ollamaRequestModel); + /** + * Ask a question to a model using an {@link OllamaChatRequestModel}. This can be constructed using an {@link OllamaChatRequestBuilder}. + *

+ * Hint: the OllamaChatRequestModel#getStream() property is not implemented. + * + * @param request request object to be sent to the server + * @param streamHandler callback handler to handle the last message from stream (caution: all previous messages from stream will be concatenated) + * @return + * @throws OllamaBaseException any response code than 200 has been returned + * @throws IOException in case the responseStream can not be read + * @throws InterruptedException in case the server is not reachable or network issues happen + */ + public OllamaChatResult chat(OllamaChatRequestModel request, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException { + OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); + OllamaResult result; + if (streamHandler != null) { + request.setStream(true); + result = requestCaller.call(request, streamHandler); + } else { + result = requestCaller.callSync(request); + } + return new OllamaChatResult(result.getResponse(), result.getResponseTime(), result.getHttpStatusCode(), request.getMessages()); } - return result; - } - /** - * Get default request builder. - * - * @param uri URI to get a HttpRequest.Builder - * @return HttpRequest.Builder - */ - private HttpRequest.Builder getRequestBuilderDefault(URI uri) { - HttpRequest.Builder requestBuilder = - HttpRequest.newBuilder(uri) - .header("Content-Type", "application/json") - .timeout(Duration.ofSeconds(requestTimeoutSeconds)); - if (isBasicAuthCredentialsSet()) { - requestBuilder.header("Authorization", getBasicAuthHeaderValue()); + // technical private methods // + + private static String encodeFileToBase64(File file) throws IOException { + return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath())); } - return requestBuilder; - } - /** - * Get basic authentication header value. - * - * @return basic authentication header value (encoded credentials) - */ - private String getBasicAuthHeaderValue() { - String credentialsToEncode = basicAuth.getUsername() + ":" + basicAuth.getPassword(); - return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes()); - } + private static String encodeByteArrayToBase64(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } - /** - * Check if Basic Auth credentials set. - * - * @return true when Basic Auth credentials set - */ - private boolean isBasicAuthCredentialsSet() { - return basicAuth != null; - } + private OllamaResult generateSyncForOllamaRequestModel( + OllamaGenerateRequestModel ollamaRequestModel, OllamaStreamHandler streamHandler) + throws OllamaBaseException, IOException, InterruptedException { + OllamaGenerateEndpointCaller requestCaller = + new OllamaGenerateEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose); + OllamaResult result; + if (streamHandler != null) { + ollamaRequestModel.setStream(true); + result = requestCaller.call(ollamaRequestModel, streamHandler); + } else { + result = requestCaller.callSync(ollamaRequestModel); + } + return result; + } + + /** + * Get default request builder. + * + * @param uri URI to get a HttpRequest.Builder + * @return HttpRequest.Builder + */ + private HttpRequest.Builder getRequestBuilderDefault(URI uri) { + HttpRequest.Builder requestBuilder = + HttpRequest.newBuilder(uri) + .header("Content-Type", "application/json") + .timeout(Duration.ofSeconds(requestTimeoutSeconds)); + if (isBasicAuthCredentialsSet()) { + requestBuilder.header("Authorization", getBasicAuthHeaderValue()); + } + return requestBuilder; + } + + /** + * Get basic authentication header value. + * + * @return basic authentication header value (encoded credentials) + */ + private String getBasicAuthHeaderValue() { + String credentialsToEncode = basicAuth.getUsername() + ":" + basicAuth.getPassword(); + return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes()); + } + + /** + * Check if Basic Auth credentials set. + * + * @return true when Basic Auth credentials set + */ + private boolean isBasicAuthCredentialsSet() { + return basicAuth != null; + } } diff --git a/src/main/java/io/github/amithkoujalgi/ollama4j/core/models/request/OllamaEndpointCaller.java b/src/main/java/io/github/amithkoujalgi/ollama4j/core/models/request/OllamaEndpointCaller.java index ad8d5bb..350200a 100644 --- a/src/main/java/io/github/amithkoujalgi/ollama4j/core/models/request/OllamaEndpointCaller.java +++ b/src/main/java/io/github/amithkoujalgi/ollama4j/core/models/request/OllamaEndpointCaller.java @@ -1,5 +1,15 @@ package io.github.amithkoujalgi.ollama4j.core.models.request; +import io.github.amithkoujalgi.ollama4j.core.OllamaAPI; +import io.github.amithkoujalgi.ollama4j.core.exceptions.OllamaBaseException; +import io.github.amithkoujalgi.ollama4j.core.models.BasicAuth; +import io.github.amithkoujalgi.ollama4j.core.models.OllamaErrorResponseModel; +import io.github.amithkoujalgi.ollama4j.core.models.OllamaResult; +import io.github.amithkoujalgi.ollama4j.core.utils.OllamaRequestBody; +import io.github.amithkoujalgi.ollama4j.core.utils.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -12,22 +22,11 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.Base64; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.github.amithkoujalgi.ollama4j.core.OllamaAPI; -import io.github.amithkoujalgi.ollama4j.core.exceptions.OllamaBaseException; -import io.github.amithkoujalgi.ollama4j.core.models.BasicAuth; -import io.github.amithkoujalgi.ollama4j.core.models.OllamaErrorResponseModel; -import io.github.amithkoujalgi.ollama4j.core.models.OllamaResult; -import io.github.amithkoujalgi.ollama4j.core.utils.OllamaRequestBody; -import io.github.amithkoujalgi.ollama4j.core.utils.Utils; - /** * Abstract helperclass to call the ollama api server. */ public abstract class OllamaEndpointCaller { - + private static final Logger LOG = LoggerFactory.getLogger(OllamaAPI.class); private String host; @@ -49,107 +48,105 @@ public abstract class OllamaEndpointCaller { /** * Calls the api server on the given host and endpoint suffix asynchronously, aka waiting for the response. - * + * * @param body POST body payload * @return result answer given by the assistant - * @throws OllamaBaseException any response code than 200 has been returned - * @throws IOException in case the responseStream can not be read + * @throws OllamaBaseException any response code than 200 has been returned + * @throws IOException in case the responseStream can not be read * @throws InterruptedException in case the server is not reachable or network issues happen */ - public OllamaResult callSync(OllamaRequestBody body) throws OllamaBaseException, IOException, InterruptedException{ - + public OllamaResult callSync(OllamaRequestBody body) throws OllamaBaseException, IOException, InterruptedException { // Create Request - long startTime = System.currentTimeMillis(); - HttpClient httpClient = HttpClient.newHttpClient(); - URI uri = URI.create(this.host + getEndpointSuffix()); - HttpRequest.Builder requestBuilder = - getRequestBuilderDefault(uri) - .POST( - body.getBodyPublisher()); - HttpRequest request = requestBuilder.build(); - if (this.verbose) LOG.info("Asking model: " + body.toString()); - HttpResponse response = - httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); - - + long startTime = System.currentTimeMillis(); + HttpClient httpClient = HttpClient.newHttpClient(); + URI uri = URI.create(this.host + getEndpointSuffix()); + HttpRequest.Builder requestBuilder = + getRequestBuilderDefault(uri) + .POST( + body.getBodyPublisher()); + HttpRequest request = requestBuilder.build(); + if (this.verbose) LOG.info("Asking model: " + body.toString()); + HttpResponse response = + httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream()); + int statusCode = response.statusCode(); - InputStream responseBodyStream = response.body(); - StringBuilder responseBuffer = new StringBuilder(); - try (BufferedReader reader = - new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { - String line; - while ((line = reader.readLine()) != null) { - if (statusCode == 404) { - LOG.warn("Status code: 404 (Not Found)"); - OllamaErrorResponseModel ollamaResponseModel = - Utils.getObjectMapper().readValue(line, OllamaErrorResponseModel.class); - responseBuffer.append(ollamaResponseModel.getError()); - } else if (statusCode == 401) { - LOG.warn("Status code: 401 (Unauthorized)"); - OllamaErrorResponseModel ollamaResponseModel = - Utils.getObjectMapper() - .readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponseModel.class); - responseBuffer.append(ollamaResponseModel.getError()); - } else if (statusCode == 400) { - LOG.warn("Status code: 400 (Bad Request)"); - OllamaErrorResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, - OllamaErrorResponseModel.class); - responseBuffer.append(ollamaResponseModel.getError()); - } else { - boolean finished = parseResponseAndAddToBuffer(line,responseBuffer); - if (finished) { - break; + InputStream responseBodyStream = response.body(); + StringBuilder responseBuffer = new StringBuilder(); + try (BufferedReader reader = + new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + if (statusCode == 404) { + LOG.warn("Status code: 404 (Not Found)"); + OllamaErrorResponseModel ollamaResponseModel = + Utils.getObjectMapper().readValue(line, OllamaErrorResponseModel.class); + responseBuffer.append(ollamaResponseModel.getError()); + } else if (statusCode == 401) { + LOG.warn("Status code: 401 (Unauthorized)"); + OllamaErrorResponseModel ollamaResponseModel = + Utils.getObjectMapper() + .readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponseModel.class); + responseBuffer.append(ollamaResponseModel.getError()); + } else if (statusCode == 400) { + LOG.warn("Status code: 400 (Bad Request)"); + OllamaErrorResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, + OllamaErrorResponseModel.class); + responseBuffer.append(ollamaResponseModel.getError()); + } else { + boolean finished = parseResponseAndAddToBuffer(line, responseBuffer); + if (finished) { + break; + } + } } } - } - } - if (statusCode != 200) { - LOG.error("Status code " + statusCode); - throw new OllamaBaseException(responseBuffer.toString()); - } else { - long endTime = System.currentTimeMillis(); - OllamaResult ollamaResult = - new OllamaResult(responseBuffer.toString().trim(), endTime - startTime, statusCode); - if (verbose) LOG.info("Model response: " + ollamaResult); - return ollamaResult; + if (statusCode != 200) { + LOG.error("Status code " + statusCode); + throw new OllamaBaseException(responseBuffer.toString()); + } else { + long endTime = System.currentTimeMillis(); + OllamaResult ollamaResult = + new OllamaResult(responseBuffer.toString().trim(), endTime - startTime, statusCode); + if (verbose) LOG.info("Model response: " + ollamaResult); + return ollamaResult; + } } - } /** - * Get default request builder. - * - * @param uri URI to get a HttpRequest.Builder - * @return HttpRequest.Builder - */ - private HttpRequest.Builder getRequestBuilderDefault(URI uri) { - HttpRequest.Builder requestBuilder = - HttpRequest.newBuilder(uri) - .header("Content-Type", "application/json") - .timeout(Duration.ofSeconds(this.requestTimeoutSeconds)); - if (isBasicAuthCredentialsSet()) { - requestBuilder.header("Authorization", getBasicAuthHeaderValue()); + * Get default request builder. + * + * @param uri URI to get a HttpRequest.Builder + * @return HttpRequest.Builder + */ + private HttpRequest.Builder getRequestBuilderDefault(URI uri) { + HttpRequest.Builder requestBuilder = + HttpRequest.newBuilder(uri) + .header("Content-Type", "application/json") + .timeout(Duration.ofSeconds(this.requestTimeoutSeconds)); + if (isBasicAuthCredentialsSet()) { + requestBuilder.header("Authorization", getBasicAuthHeaderValue()); + } + return requestBuilder; } - return requestBuilder; - } - /** - * Get basic authentication header value. - * - * @return basic authentication header value (encoded credentials) - */ - private String getBasicAuthHeaderValue() { - String credentialsToEncode = this.basicAuth.getUsername() + ":" + this.basicAuth.getPassword(); - return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes()); - } + /** + * Get basic authentication header value. + * + * @return basic authentication header value (encoded credentials) + */ + private String getBasicAuthHeaderValue() { + String credentialsToEncode = this.basicAuth.getUsername() + ":" + this.basicAuth.getPassword(); + return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes()); + } + + /** + * Check if Basic Auth credentials set. + * + * @return true when Basic Auth credentials set + */ + private boolean isBasicAuthCredentialsSet() { + return this.basicAuth != null; + } - /** - * Check if Basic Auth credentials set. - * - * @return true when Basic Auth credentials set - */ - private boolean isBasicAuthCredentialsSet() { - return this.basicAuth != null; - } - }