Compare commits

...

10 Commits

Author SHA1 Message Date
amithkoujalgi
b57fc1f818 [maven-release-plugin] prepare release v1.0.33 2023-12-30 06:54:48 +00:00
Amith Koujalgi
01c5a8f07f updated readme 2023-12-30 12:23:42 +05:30
amithkoujalgi
243b8a3747 [maven-release-plugin] prepare for next development iteration 2023-12-29 04:56:21 +00:00
amithkoujalgi
987fce7f07 [maven-release-plugin] prepare release v1.0.32 2023-12-29 04:56:20 +00:00
Amith Koujalgi
657593be09 Updated all APIs to use getRequestBuilderDefault() method 2023-12-29 10:25:18 +05:30
amithkoujalgi
0afba7e3e3 [maven-release-plugin] prepare for next development iteration 2023-12-29 04:03:48 +00:00
amithkoujalgi
ac00bb9029 [maven-release-plugin] prepare release v1.0.31 2023-12-29 04:03:46 +00:00
Amith Koujalgi
67cb444d82 Merge pull request #14 from omcodedthis/patch-3
Updated documentation
2023-12-29 09:32:46 +05:30
amithkoujalgi
1914a29163 [maven-release-plugin] prepare for next development iteration 2023-12-29 03:57:59 +00:00
oM
00bb4e92dc Updated documentation 2023-12-29 11:43:27 +08:00
8 changed files with 207 additions and 143 deletions

View File

@@ -2,8 +2,33 @@
<img src='https://raw.githubusercontent.com/amithkoujalgi/ollama4j/65a9d526150da8fcd98e2af6a164f055572bf722/ollama4j.jpeg' width='100' alt="ollama4j-icon"> <img src='https://raw.githubusercontent.com/amithkoujalgi/ollama4j/65a9d526150da8fcd98e2af6a164f055572bf722/ollama4j.jpeg' width='100' alt="ollama4j-icon">
A Java library (wrapper/binding) A Java library (wrapper/binding) for [Ollama](https://ollama.ai/) server.
for [Ollama](https://github.com/jmorganca/ollama/blob/main/docs/api.md) APIs.
Find more details on the [website](https://amithkoujalgi.github.io/ollama4j/).
![GitHub stars](https://img.shields.io/github/stars/amithkoujalgi/ollama4j)
![GitHub forks](https://img.shields.io/github/forks/amithkoujalgi/ollama4j)
![GitHub watchers](https://img.shields.io/github/watchers/amithkoujalgi/ollama4j)
![GitHub repo size](https://img.shields.io/github/repo-size/amithkoujalgi/ollama4j)
![GitHub language count](https://img.shields.io/github/languages/count/amithkoujalgi/ollama4j)
![GitHub top language](https://img.shields.io/github/languages/top/amithkoujalgi/ollama4j)
![GitHub last commit](https://img.shields.io/github/last-commit/amithkoujalgi/ollama4j?color=green)
![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Famithkoujalgi%2Follama4j&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)
![Build Status](https://github.com/amithkoujalgi/ollama4j/actions/workflows/maven-publish.yml/badge.svg)
## Table of Contents
- [How does it work?](#how-does-it-work)
- [Requirements](#requirements)
- [Installation](#installation)
- [API Spec](#api-spec)
- [Demo APIs](#try-out-the-apis-with-ollama-server)
- [Development](#development)
- [Contributions](#get-involved)
- [References](#references)
#### How does it work?
```mermaid ```mermaid
flowchart LR flowchart LR
@@ -17,39 +42,19 @@ for [Ollama](https://github.com/jmorganca/ollama/blob/main/docs/api.md) APIs.
end end
``` ```
![Build Status](https://github.com/amithkoujalgi/ollama4j/actions/workflows/maven-publish.yml/badge.svg)
![GitHub stars](https://img.shields.io/github/stars/amithkoujalgi/ollama4j?style=social)
![GitHub forks](https://img.shields.io/github/forks/amithkoujalgi/ollama4j?style=social)
![GitHub watchers](https://img.shields.io/github/watchers/amithkoujalgi/ollama4j?style=social)
![GitHub repo size](https://img.shields.io/github/repo-size/amithkoujalgi/ollama4j?style=plastic)
![GitHub language count](https://img.shields.io/github/languages/count/amithkoujalgi/ollama4j?style=plastic)
![GitHub top language](https://img.shields.io/github/languages/top/amithkoujalgi/ollama4j?style=plastic)
![GitHub last commit](https://img.shields.io/github/last-commit/amithkoujalgi/ollama4j?color=red&style=plastic)
![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Famithkoujalgi%2Follama4j&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)
## Table of Contents
- [Requirements](#requirements)
- [Installation](#installation)
- [API Spec](#api-spec)
- [Demo APIs](#try-out-the-apis-with-ollama-server)
- [Development](#development)
- [Contributions](#get-involved)
#### Requirements #### Requirements
![Java](https://img.shields.io/badge/Java-11_+-green.svg?style=for-the-badge&labelColor=gray) ![Java](https://img.shields.io/badge/Java-11_+-green.svg?style=just-the-message&labelColor=gray)
[![][ollama-shield]][ollama] Or [![][ollama-docker-shield]][ollama-docker] [![][ollama-shield]][ollama] **Or** [![][ollama-docker-shield]][ollama-docker]
[ollama]: https://ollama.ai/ [ollama]: https://ollama.ai/
[ollama-shield]: https://img.shields.io/badge/Ollama-Local_Installation-blue.svg?style=for-the-badge&labelColor=gray [ollama-shield]: https://img.shields.io/badge/Ollama-Local_Installation-blue.svg?style=just-the-message&labelColor=gray
[ollama-docker]: https://hub.docker.com/r/ollama/ollama [ollama-docker]: https://hub.docker.com/r/ollama/ollama
[ollama-docker-shield]: https://img.shields.io/badge/Ollama-Docker-blue.svg?style=for-the-badge&labelColor=gray [ollama-docker-shield]: https://img.shields.io/badge/Ollama-Docker-blue.svg?style=just-the-message&labelColor=gray
#### Installation #### Installation
@@ -64,17 +69,19 @@ In your Maven project, add this dependency:
</dependency> </dependency>
``` ```
Latest release: ![Maven Central](https://img.shields.io/maven-central/v/io.github.amithkoujalgi/ollama4j) Latest release:
![Maven Central](https://img.shields.io/maven-central/v/io.github.amithkoujalgi/ollama4j)
[![][lib-shield]][lib] [![][lib-shield]][lib]
[lib]: https://central.sonatype.com/artifact/io.github.amithkoujalgi/ollama4j [lib]: https://central.sonatype.com/artifact/io.github.amithkoujalgi/ollama4j
[lib-shield]: https://img.shields.io/badge/ollama4j-get_latest_version-blue.svg?style=for-the-badge&labelColor=gray [lib-shield]: https://img.shields.io/badge/ollama4j-get_latest_version-blue.svg?style=just-the-message&labelColor=gray
#### API Spec #### API Spec
Find the full `Javadoc` (API specifications) [here](https://amithkoujalgi.github.io/ollama4j/). Find the full API specifications on the [website](https://amithkoujalgi.github.io/ollama4j/).
#### Development #### Development
@@ -115,6 +122,7 @@ Actions CI workflow.
- [x] Use lombok - [x] Use lombok
- [x] Update request body creation with Java objects - [x] Update request body creation with Java objects
- [ ] Async APIs for images - [ ] Async APIs for images
- [ ] Add custom headers to requests
- [ ] Add additional params for `ask` APIs such as: - [ ] Add additional params for `ask` APIs such as:
- `options`: additional model parameters for the Modelfile such as `temperature` - `options`: additional model parameters for the Modelfile such as `temperature`
- `system`: system prompt to (overrides what is defined in the Modelfile) - `system`: system prompt to (overrides what is defined in the Modelfile)
@@ -136,3 +144,7 @@ of contribution is much appreciated.
The nomenclature and the icon have been adopted from the incredible [Ollama](https://ollama.ai/) The nomenclature and the icon have been adopted from the incredible [Ollama](https://ollama.ai/)
project. project.
### References
- [Ollama REST APIs](https://github.com/jmorganca/ollama/blob/main/docs/api.md)

View File

@@ -0,0 +1,24 @@
---
sidebar_position: 2
---
# Set Basic Authentication
This API lets you set the basic authentication for the Ollama client. This would help in scenarios where
Ollama server would be setup behind a gateway/reverse proxy with basic auth.
After configuring basic authentication, all subsequent requests will include the Basic Auth header.
```java
public class Main {
public static void main(String[] args) {
String host = "http://localhost:11434/";
OllamaAPI ollamaAPI = new OllamaAPI(host);
ollamaAPI.setBasicAuth("username", "password");
}
}
```

View File

@@ -4,7 +4,7 @@
<groupId>io.github.amithkoujalgi</groupId> <groupId>io.github.amithkoujalgi</groupId>
<artifactId>ollama4j</artifactId> <artifactId>ollama4j</artifactId>
<version>1.0.30</version> <version>1.0.33</version>
<name>Ollama4j</name> <name>Ollama4j</name>
<description>Java library for interacting with Ollama API.</description> <description>Java library for interacting with Ollama API.</description>
@@ -39,7 +39,7 @@
<connection>scm:git:git@github.com:amithkoujalgi/ollama4j.git</connection> <connection>scm:git:git@github.com:amithkoujalgi/ollama4j.git</connection>
<developerConnection>scm:git:https://github.com/amithkoujalgi/ollama4j.git</developerConnection> <developerConnection>scm:git:https://github.com/amithkoujalgi/ollama4j.git</developerConnection>
<url>https://github.com/amithkoujalgi/ollama4j</url> <url>https://github.com/amithkoujalgi/ollama4j</url>
<tag>v1.0.30</tag> <tag>v1.0.33</tag>
</scm> </scm>
<build> <build>

View File

@@ -37,8 +37,7 @@ public class OllamaAPI {
private final String host; private final String host;
private long requestTimeoutSeconds = 3; private long requestTimeoutSeconds = 3;
private boolean verbose = true; private boolean verbose = true;
private String username; private BasicAuth basicAuth;
private String password;
/** /**
* Instantiates the Ollama API. * Instantiates the Ollama API.
@@ -53,6 +52,11 @@ public class OllamaAPI {
} }
} }
/**
* Set request timeout in seconds. Default is 3 seconds.
*
* @param requestTimeoutSeconds the request timeout in seconds
*/
public void setRequestTimeoutSeconds(long requestTimeoutSeconds) { public void setRequestTimeoutSeconds(long requestTimeoutSeconds) {
this.requestTimeoutSeconds = requestTimeoutSeconds; this.requestTimeoutSeconds = requestTimeoutSeconds;
} }
@@ -67,11 +71,13 @@ public class OllamaAPI {
} }
/** /**
* 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) { public void setBasicAuth(String username, String password) {
this.username = username; this.basicAuth = new BasicAuth(username, password);
this.password = password;
} }
/** /**
@@ -85,11 +91,9 @@ public class OllamaAPI {
HttpRequest httpRequest = null; HttpRequest httpRequest = null;
try { try {
httpRequest = httpRequest =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(new URI(url))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-type", "application/json") .header("Content-type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.GET() .GET()
.build(); .build();
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
@@ -117,11 +121,9 @@ public class OllamaAPI {
String url = this.host + "/api/tags"; String url = this.host + "/api/tags";
HttpClient httpClient = HttpClient.newHttpClient(); HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest httpRequest = HttpRequest httpRequest =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(new URI(url))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-type", "application/json") .header("Content-type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.GET() .GET()
.build(); .build();
HttpResponse<String> response = HttpResponse<String> response =
@@ -148,12 +150,10 @@ public class OllamaAPI {
String url = this.host + "/api/pull"; String url = this.host + "/api/pull";
String jsonData = new ModelRequest(modelName).toString(); String jsonData = new ModelRequest(modelName).toString();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(new URI(url))
.POST(HttpRequest.BodyPublishers.ofString(jsonData)) .POST(HttpRequest.BodyPublishers.ofString(jsonData))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-type", "application/json") .header("Content-type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpResponse<InputStream> response = HttpResponse<InputStream> response =
@@ -184,15 +184,13 @@ public class OllamaAPI {
* @return the model details * @return the model details
*/ */
public ModelDetail getModelDetails(String modelName) public ModelDetail getModelDetails(String modelName)
throws IOException, OllamaBaseException, InterruptedException { throws IOException, OllamaBaseException, InterruptedException, URISyntaxException {
String url = this.host + "/api/show"; String url = this.host + "/api/show";
String jsonData = new ModelRequest(modelName).toString(); String jsonData = new ModelRequest(modelName).toString();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(URI.create(url))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-type", "application/json") .header("Content-type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.POST(HttpRequest.BodyPublishers.ofString(jsonData)) .POST(HttpRequest.BodyPublishers.ofString(jsonData))
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
@@ -214,15 +212,13 @@ public class OllamaAPI {
* @param modelFilePath the path to model file that exists on the Ollama server. * @param modelFilePath the path to model file that exists on the Ollama server.
*/ */
public void createModelWithFilePath(String modelName, String modelFilePath) public void createModelWithFilePath(String modelName, String modelFilePath)
throws IOException, InterruptedException, OllamaBaseException { throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
String url = this.host + "/api/create"; String url = this.host + "/api/create";
String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString(); String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(URI.create(url))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
@@ -250,15 +246,13 @@ public class OllamaAPI {
* @param modelFileContents the path to model file that exists on the Ollama server. * @param modelFileContents the path to model file that exists on the Ollama server.
*/ */
public void createModelWithModelFileContents(String modelName, String modelFileContents) public void createModelWithModelFileContents(String modelName, String modelFileContents)
throws IOException, InterruptedException, OllamaBaseException { throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
String url = this.host + "/api/create"; String url = this.host + "/api/create";
String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString(); String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(URI.create(url))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
@@ -280,20 +274,17 @@ public class OllamaAPI {
* Delete a model from Ollama server. * Delete a model from Ollama server.
* *
* @param modelName the name of the model to be deleted. * @param modelName the name of the model to be deleted.
* @param ignoreIfNotPresent - ignore errors if the specified model is not present on Ollama * @param ignoreIfNotPresent ignore errors if the specified model is not present on Ollama server.
* server.
*/ */
public void deleteModel(String modelName, boolean ignoreIfNotPresent) public void deleteModel(String modelName, boolean ignoreIfNotPresent)
throws IOException, InterruptedException, OllamaBaseException { throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
String url = this.host + "/api/delete"; String url = this.host + "/api/delete";
String jsonData = new ModelRequest(modelName).toString(); String jsonData = new ModelRequest(modelName).toString();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder() getRequestBuilderDefault(new URI(url))
.uri(URI.create(url))
.method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)) .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
.header("Accept", "application/json") .header("Accept", "application/json")
.header("Content-type", "application/json") .header("Content-type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
.build(); .build();
HttpClient client = HttpClient.newHttpClient(); HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
@@ -319,7 +310,8 @@ public class OllamaAPI {
URI uri = URI.create(this.host + "/api/embeddings"); URI uri = URI.create(this.host + "/api/embeddings");
String jsonData = new ModelEmbeddingsRequest(model, prompt).toString(); String jsonData = new ModelEmbeddingsRequest(model, prompt).toString();
HttpClient httpClient = HttpClient.newHttpClient(); HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri) HttpRequest.Builder requestBuilder =
getRequestBuilderDefault(uri)
.header("Accept", "application/json") .header("Accept", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(jsonData)); .POST(HttpRequest.BodyPublishers.ofString(jsonData));
HttpRequest request = requestBuilder.build(); HttpRequest request = requestBuilder.build();
@@ -339,12 +331,12 @@ public class OllamaAPI {
* Ask a question to a model running on Ollama server. This is a sync/blocking call. * 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 model the ollama model to ask the question to
* @param promptText the prompt/question text * @param prompt the prompt/question text
* @return OllamaResult - that includes response text and time taken for response * @return OllamaResult that includes response text and time taken for response
*/ */
public OllamaResult ask(String model, String promptText) public OllamaResult ask(String model, String prompt)
throws OllamaBaseException, IOException, InterruptedException { throws OllamaBaseException, IOException, InterruptedException {
OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, promptText); OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, prompt);
return askSync(ollamaRequestModel); return askSync(ollamaRequestModel);
} }
@@ -354,15 +346,16 @@ public class OllamaAPI {
* async/non-blocking call. * async/non-blocking call.
* *
* @param model the ollama model to ask the question to * @param model the ollama model to ask the question to
* @param promptText the prompt/question text * @param prompt the prompt/question text
* @return the ollama async result callback handle * @return the ollama async result callback handle
*/ */
public OllamaAsyncResultCallback askAsync(String model, String promptText) { public OllamaAsyncResultCallback askAsync(String model, String prompt) {
OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, promptText); OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, prompt);
HttpClient httpClient = HttpClient.newHttpClient();
URI uri = URI.create(this.host + "/api/generate"); URI uri = URI.create(this.host + "/api/generate");
OllamaAsyncResultCallback ollamaAsyncResultCallback = OllamaAsyncResultCallback ollamaAsyncResultCallback =
new OllamaAsyncResultCallback(httpClient, uri, ollamaRequestModel, requestTimeoutSeconds); new OllamaAsyncResultCallback(
getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds);
ollamaAsyncResultCallback.start(); ollamaAsyncResultCallback.start();
return ollamaAsyncResultCallback; return ollamaAsyncResultCallback;
} }
@@ -372,17 +365,17 @@ public class OllamaAPI {
* sync/blocking call. * sync/blocking call.
* *
* @param model the ollama model to ask the question to * @param model the ollama model to ask the question to
* @param promptText the prompt/question text * @param prompt the prompt/question text
* @param imageFiles the list of image files to use for the question * @param imageFiles the list of image files to use for the question
* @return OllamaResult - that includes response text and time taken for response * @return OllamaResult that includes response text and time taken for response
*/ */
public OllamaResult askWithImageFiles(String model, String promptText, List<File> imageFiles) public OllamaResult askWithImageFiles(String model, String prompt, List<File> imageFiles)
throws OllamaBaseException, IOException, InterruptedException { throws OllamaBaseException, IOException, InterruptedException {
List<String> images = new ArrayList<>(); List<String> images = new ArrayList<>();
for (File imageFile : imageFiles) { for (File imageFile : imageFiles) {
images.add(encodeFileToBase64(imageFile)); images.add(encodeFileToBase64(imageFile));
} }
OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, promptText, images); OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, prompt, images);
return askSync(ollamaRequestModel); return askSync(ollamaRequestModel);
} }
@@ -391,17 +384,17 @@ public class OllamaAPI {
* sync/blocking call. * sync/blocking call.
* *
* @param model the ollama model to ask the question to * @param model the ollama model to ask the question to
* @param promptText the prompt/question text * @param prompt the prompt/question text
* @param imageURLs the list of image URLs to use for the question * @param imageURLs the list of image URLs to use for the question
* @return OllamaResult - that includes response text and time taken for response * @return OllamaResult that includes response text and time taken for response
*/ */
public OllamaResult askWithImageURLs(String model, String promptText, List<String> imageURLs) public OllamaResult askWithImageURLs(String model, String prompt, List<String> imageURLs)
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException { throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
List<String> images = new ArrayList<>(); List<String> images = new ArrayList<>();
for (String imageURL : imageURLs) { for (String imageURL : imageURLs) {
images.add(encodeByteArrayToBase64(loadImageBytesFromUrl(imageURL))); images.add(encodeByteArrayToBase64(loadImageBytesFromUrl(imageURL)));
} }
OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, promptText, images); OllamaRequestModel ollamaRequestModel = new OllamaRequestModel(model, prompt, images);
return askSync(ollamaRequestModel); return askSync(ollamaRequestModel);
} }
@@ -432,7 +425,8 @@ public class OllamaAPI {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
HttpClient httpClient = HttpClient.newHttpClient(); HttpClient httpClient = HttpClient.newHttpClient();
URI uri = URI.create(this.host + "/api/generate"); URI uri = URI.create(this.host + "/api/generate");
HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri) HttpRequest.Builder requestBuilder =
getRequestBuilderDefault(uri)
.POST( .POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
Utils.getObjectMapper().writeValueAsString(ollamaRequestModel))); Utils.getObjectMapper().writeValueAsString(ollamaRequestModel)));
@@ -455,9 +449,10 @@ public class OllamaAPI {
} else if (statusCode == 401) { } else if (statusCode == 401) {
logger.warn("Status code: 401 (Unauthorized)"); logger.warn("Status code: 401 (Unauthorized)");
OllamaErrorResponseModel ollamaResponseModel = OllamaErrorResponseModel ollamaResponseModel =
Utils.getObjectMapper().readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponseModel.class); Utils.getObjectMapper()
.readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponseModel.class);
responseBuffer.append(ollamaResponseModel.getError()); responseBuffer.append(ollamaResponseModel.getError());
}else { } else {
OllamaResponseModel ollamaResponseModel = OllamaResponseModel ollamaResponseModel =
Utils.getObjectMapper().readValue(line, OllamaResponseModel.class); Utils.getObjectMapper().readValue(line, OllamaResponseModel.class);
if (!ollamaResponseModel.isDone()) { if (!ollamaResponseModel.isDone()) {
@@ -467,7 +462,7 @@ public class OllamaAPI {
} }
} }
if (statusCode != 200) { if (statusCode != 200) {
logger.error("Status code " + statusCode + " instead 200"); logger.error("Status code " + statusCode);
throw new OllamaBaseException(responseBuffer.toString()); throw new OllamaBaseException(responseBuffer.toString());
} else { } else {
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
@@ -476,35 +471,38 @@ public class OllamaAPI {
} }
/** /**
* Get default request builder.
* *
* @param uri URI to get a HttpRequest.Builder
* @return HttpRequest.Builder
*/ */
private HttpRequest.Builder getRequestBuilderDefault(URI uri) { private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
HttpRequest.Builder requestBuilder = HttpRequest.Builder requestBuilder =
HttpRequest.newBuilder(uri) HttpRequest.newBuilder(uri)
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.timeout(Duration.ofSeconds(requestTimeoutSeconds)); .timeout(Duration.ofSeconds(requestTimeoutSeconds));
if (basicAuthCredentialsSet()) { if (isBasicAuthCredentialsSet()) {
requestBuilder.header("Authorization", getBasicAuthHeaderValue()); requestBuilder.header("Authorization", getBasicAuthHeaderValue());
} }
return requestBuilder; return requestBuilder;
} }
/** /**
* Get basic authentication header value.
*
* @return basic authentication header value (encoded credentials) * @return basic authentication header value (encoded credentials)
*/ */
private String getBasicAuthHeaderValue() { private String getBasicAuthHeaderValue() {
String credentialsToEncode = username + ":" + password; String credentialsToEncode = basicAuth.getUsername() + ":" + basicAuth.getPassword();
return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes()); return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes());
} }
/** /**
* Check if Basic Auth credentials set.
*
* @return true when Basic Auth credentials set * @return true when Basic Auth credentials set
*/ */
private boolean basicAuthCredentialsSet() { private boolean isBasicAuthCredentialsSet() {
if (username != null && password != null) { return basicAuth != null;
return true;
} else {
return false;
}
} }
} }

View File

@@ -0,0 +1,13 @@
package io.github.amithkoujalgi.ollama4j.core.models;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BasicAuth {
private String username;
private String password;
}

View File

@@ -6,7 +6,6 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
@@ -14,30 +13,44 @@ import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Queue; import java.util.Queue;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@Data
@EqualsAndHashCode(callSuper = true)
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class OllamaAsyncResultCallback extends Thread { public class OllamaAsyncResultCallback extends Thread {
private final HttpClient client; private final HttpRequest.Builder requestBuilder;
private final URI uri;
private final OllamaRequestModel ollamaRequestModel; private final OllamaRequestModel ollamaRequestModel;
private final Queue<String> queue = new LinkedList<>(); private final Queue<String> queue = new LinkedList<>();
private String result; private String result;
private boolean isDone; private boolean isDone;
private boolean succeeded;
/**
* -- GETTER -- Returns the status of the request. Indicates if the request was successful or a
* failure. If the request was a failure, the `getResponse()` method will return the error
* message.
*/
@Getter private boolean succeeded;
private long requestTimeoutSeconds; private long requestTimeoutSeconds;
private int httpStatusCode; /**
private long responseTime = 0; * -- GETTER -- Returns the HTTP response status code for the request that was made to Ollama
* server.
*/
@Getter private int httpStatusCode;
/** -- GETTER -- Returns the response time in milliseconds. */
@Getter private long responseTime = 0;
public OllamaAsyncResultCallback( public OllamaAsyncResultCallback(
HttpClient client, HttpRequest.Builder requestBuilder,
URI uri,
OllamaRequestModel ollamaRequestModel, OllamaRequestModel ollamaRequestModel,
long requestTimeoutSeconds) { long requestTimeoutSeconds) {
this.client = client; this.requestBuilder = requestBuilder;
this.ollamaRequestModel = ollamaRequestModel; this.ollamaRequestModel = ollamaRequestModel;
this.uri = uri;
this.isDone = false; this.isDone = false;
this.result = ""; this.result = "";
this.queue.add(""); this.queue.add("");
@@ -46,10 +59,11 @@ public class OllamaAsyncResultCallback extends Thread {
@Override @Override
public void run() { public void run() {
HttpClient httpClient = HttpClient.newHttpClient();
try { try {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
HttpRequest request = HttpRequest request =
HttpRequest.newBuilder(uri) requestBuilder
.POST( .POST(
HttpRequest.BodyPublishers.ofString( HttpRequest.BodyPublishers.ofString(
Utils.getObjectMapper().writeValueAsString(ollamaRequestModel))) Utils.getObjectMapper().writeValueAsString(ollamaRequestModel)))
@@ -57,7 +71,7 @@ public class OllamaAsyncResultCallback extends Thread {
.timeout(Duration.ofSeconds(requestTimeoutSeconds)) .timeout(Duration.ofSeconds(requestTimeoutSeconds))
.build(); .build();
HttpResponse<InputStream> response = HttpResponse<InputStream> response =
client.send(request, HttpResponse.BodyHandlers.ofInputStream()); httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
int statusCode = response.statusCode(); int statusCode = response.statusCode();
this.httpStatusCode = statusCode; this.httpStatusCode = statusCode;
@@ -108,25 +122,6 @@ public class OllamaAsyncResultCallback extends Thread {
return isDone; return isDone;
} }
/**
* Returns the HTTP response status code for the request that was made to Ollama server.
*
* @return int - the status code for the request
*/
public int getHttpStatusCode() {
return httpStatusCode;
}
/**
* Returns the status of the request. Indicates if the request was successful or a failure. If the
* request was a failure, the `getResponse()` method will return the error message.
*
* @return boolean - status
*/
public boolean isSucceeded() {
return succeeded;
}
/** /**
* Returns the final response when the execution completes. Does not return intermediate results. * Returns the final response when the execution completes. Does not return intermediate results.
* *
@@ -140,15 +135,6 @@ public class OllamaAsyncResultCallback extends Thread {
return queue; return queue;
} }
/**
* Returns the response time in milliseconds.
*
* @return long - response time in milliseconds.
*/
public long getResponseTime() {
return responseTime;
}
public void setRequestTimeoutSeconds(long requestTimeoutSeconds) { public void setRequestTimeoutSeconds(long requestTimeoutSeconds) {
this.requestTimeoutSeconds = requestTimeoutSeconds; this.requestTimeoutSeconds = requestTimeoutSeconds;
} }

View File

@@ -3,7 +3,7 @@ package io.github.amithkoujalgi.ollama4j.core.utils;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
public class Utils { public class Utils {
public static ObjectMapper getObjectMapper() { public static ObjectMapper getObjectMapper() {
return new ObjectMapper(); return new ObjectMapper();
} }
} }

View File

@@ -11,12 +11,13 @@ import io.github.amithkoujalgi.ollama4j.core.types.OllamaModelType;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
class TestMockedAPIs { class TestMockedAPIs {
@Test @Test
void testMockPullModel() { void testPullModel() {
OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class);
String model = OllamaModelType.LLAMA2; String model = OllamaModelType.LLAMA2;
try { try {
@@ -49,7 +50,7 @@ class TestMockedAPIs {
doNothing().when(ollamaAPI).createModelWithModelFileContents(model, modelFilePath); doNothing().when(ollamaAPI).createModelWithModelFileContents(model, modelFilePath);
ollamaAPI.createModelWithModelFileContents(model, modelFilePath); ollamaAPI.createModelWithModelFileContents(model, modelFilePath);
verify(ollamaAPI, times(1)).createModelWithModelFileContents(model, modelFilePath); verify(ollamaAPI, times(1)).createModelWithModelFileContents(model, modelFilePath);
} catch (IOException | OllamaBaseException | InterruptedException e) { } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -62,7 +63,7 @@ class TestMockedAPIs {
doNothing().when(ollamaAPI).deleteModel(model, true); doNothing().when(ollamaAPI).deleteModel(model, true);
ollamaAPI.deleteModel(model, true); ollamaAPI.deleteModel(model, true);
verify(ollamaAPI, times(1)).deleteModel(model, true); verify(ollamaAPI, times(1)).deleteModel(model, true);
} catch (IOException | OllamaBaseException | InterruptedException e) { } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -75,7 +76,7 @@ class TestMockedAPIs {
when(ollamaAPI.getModelDetails(model)).thenReturn(new ModelDetail()); when(ollamaAPI.getModelDetails(model)).thenReturn(new ModelDetail());
ollamaAPI.getModelDetails(model); ollamaAPI.getModelDetails(model);
verify(ollamaAPI, times(1)).getModelDetails(model); verify(ollamaAPI, times(1)).getModelDetails(model);
} catch (IOException | OllamaBaseException | InterruptedException e) { } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -108,13 +109,43 @@ class TestMockedAPIs {
} }
} }
@Test
void testAskWithImageFiles() {
OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class);
String model = OllamaModelType.LLAMA2;
String prompt = "some prompt text";
try {
when(ollamaAPI.askWithImageFiles(model, prompt, Collections.emptyList()))
.thenReturn(new OllamaResult("", 0, 200));
ollamaAPI.askWithImageFiles(model, prompt, Collections.emptyList());
verify(ollamaAPI, times(1)).askWithImageFiles(model, prompt, Collections.emptyList());
} catch (IOException | OllamaBaseException | InterruptedException e) {
throw new RuntimeException(e);
}
}
@Test
void testAskWithImageURLs() {
OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class);
String model = OllamaModelType.LLAMA2;
String prompt = "some prompt text";
try {
when(ollamaAPI.askWithImageURLs(model, prompt, Collections.emptyList()))
.thenReturn(new OllamaResult("", 0, 200));
ollamaAPI.askWithImageURLs(model, prompt, Collections.emptyList());
verify(ollamaAPI, times(1)).askWithImageURLs(model, prompt, Collections.emptyList());
} catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
throw new RuntimeException(e);
}
}
@Test @Test
void testAskAsync() { void testAskAsync() {
OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class); OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class);
String model = OllamaModelType.LLAMA2; String model = OllamaModelType.LLAMA2;
String prompt = "some prompt text"; String prompt = "some prompt text";
when(ollamaAPI.askAsync(model, prompt)) when(ollamaAPI.askAsync(model, prompt))
.thenReturn(new OllamaAsyncResultCallback(null, null, null, 3)); .thenReturn(new OllamaAsyncResultCallback(null, null, 3));
ollamaAPI.askAsync(model, prompt); ollamaAPI.askAsync(model, prompt);
verify(ollamaAPI, times(1)).askAsync(model, prompt); verify(ollamaAPI, times(1)).askAsync(model, prompt);
} }