From fe5078891fe64baf38fd15c1d7e05fd268de750d Mon Sep 17 00:00:00 2001
From: amithkoujalgi
Date: Tue, 11 Mar 2025 11:41:51 +0530
Subject: [PATCH 01/10] Remove TestRealAPIs and enhance
OllamaAPIIntegrationTest
---
.../OllamaAPIIntegrationTest.java | 380 ++++++++++-
.../integrationtests/TestRealAPIs.java | 622 ------------------
2 files changed, 370 insertions(+), 632 deletions(-)
delete mode 100644 src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
index 4ccfadd..e26609e 100644
--- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
+++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
@@ -2,32 +2,41 @@ package io.github.ollama4j.integrationtests;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
-import io.github.ollama4j.models.chat.OllamaChatMessageRole;
-import io.github.ollama4j.models.chat.OllamaChatRequest;
-import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
-import io.github.ollama4j.models.chat.OllamaChatResult;
+import io.github.ollama4j.models.chat.*;
import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;
import io.github.ollama4j.models.response.LibraryModel;
import io.github.ollama4j.models.response.Model;
import io.github.ollama4j.models.response.ModelDetail;
import io.github.ollama4j.models.response.OllamaResult;
+import io.github.ollama4j.samples.AnnotatedTool;
+import io.github.ollama4j.tools.OllamaToolCallsFunction;
+import io.github.ollama4j.tools.ToolFunction;
+import io.github.ollama4j.tools.Tools;
+import io.github.ollama4j.tools.annotations.OllamaToolService;
import io.github.ollama4j.utils.OptionsBuilder;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testcontainers.ollama.OllamaContainer;
+import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
+@OllamaToolService(providers = {AnnotatedTool.class})
+@TestMethodOrder(OrderAnnotation.class)
+
@SuppressWarnings("HttpUrlsUsage")
public class OllamaAPIIntegrationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(OllamaAPIIntegrationTest.class);
private static OllamaContainer ollama;
private static OllamaAPI api;
@@ -45,6 +54,7 @@ public class OllamaAPIIntegrationTest {
ollama.start();
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
api.setRequestTimeoutSeconds(60);
+ api.setVerbose(true);
}
@Test
@@ -102,7 +112,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(5)
- public void testGenerateEmbeddings() throws Exception {
+ public void testEmbeddings() throws Exception {
String embeddingModelMinilm = "all-minilm";
api.pullModel(embeddingModelMinilm);
OllamaEmbedResponseModel embeddings = api.embed(embeddingModelMinilm, Arrays.asList("Why is the sky blue?", "Why is the grass green?"));
@@ -136,9 +146,9 @@ public class OllamaAPIIntegrationTest {
"What is the capital of France? And what's France's connection with Mona Lisa?",
false,
new OptionsBuilder().build(), (s) -> {
- System.out.println(s);
+ LOG.info(s);
String substring = s.substring(sb.toString().length(), s.length());
- System.out.println(substring);
+ LOG.info(substring);
sb.append(substring);
});
@@ -236,4 +246,354 @@ public class OllamaAPIIntegrationTest {
assertTrue(chatResult.getChatHistory().size() > 2, "Chat history should contain more than two messages");
assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent().contains("river"), "Response should be related to river");
}
+
+
+ @Test
+ @Order(11)
+ void testChatWithExplicitToolDefinition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
+ .functionName("get-employee-details")
+ .functionDescription("Get employee details from the database")
+ .toolPrompt(
+ Tools.PromptFuncDefinition.builder().type("function").function(
+ Tools.PromptFuncDefinition.PromptFuncSpec.builder()
+ .name("get-employee-details")
+ .description("Get employee details from the database")
+ .parameters(
+ Tools.PromptFuncDefinition.Parameters.builder()
+ .type("object")
+ .properties(
+ new Tools.PropsBuilder()
+ .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
+ .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
+ .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
+ .build()
+ )
+ .required(List.of("employee-name"))
+ .build()
+ ).build()
+ ).build()
+ )
+ .toolFunction(arguments -> {
+ // perform DB operations here
+ return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
+ })
+ .build();
+
+ api.registerTool(databaseQueryToolSpecification);
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Give me the ID of the employee named 'Rahul Kumar'?")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("get-employee-details", function.getName());
+ assertEquals(1, function.getArguments().size());
+ Object employeeName = function.getArguments().get("employee-name");
+ assertNotNull(employeeName);
+ assertEquals("Rahul Kumar", employeeName);
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(12)
+ void testChatWithAnnotatedToolsAndSingleParam() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ api.registerAnnotatedTools();
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Compute the most important constant in the world using 5 digits")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("computeImportantConstant", function.getName());
+ assertEquals(1, function.getArguments().size());
+ Object noOfDigits = function.getArguments().get("noOfDigits");
+ assertNotNull(noOfDigits);
+ assertEquals("5", noOfDigits.toString());
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(13)
+ void testChatWithAnnotatedToolsAndMultipleParams() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ api.registerAnnotatedTools(new AnnotatedTool());
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Greet Pedro with a lot of hearts and respond to me, " +
+ "and state how many emojis have been in your greeting")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("sayHello", function.getName());
+ assertEquals(2, function.getArguments().size());
+ Object name = function.getArguments().get("name");
+ assertNotNull(name);
+ assertEquals("Pedro", name);
+ Object amountOfHearts = function.getArguments().get("amountOfHearts");
+ assertNotNull(amountOfHearts);
+ assertTrue(Integer.parseInt(amountOfHearts.toString()) > 1);
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(14)
+ void testChatWithToolsAndStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+ final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
+ .functionName("get-employee-details")
+ .functionDescription("Get employee details from the database")
+ .toolPrompt(
+ Tools.PromptFuncDefinition.builder().type("function").function(
+ Tools.PromptFuncDefinition.PromptFuncSpec.builder()
+ .name("get-employee-details")
+ .description("Get employee details from the database")
+ .parameters(
+ Tools.PromptFuncDefinition.Parameters.builder()
+ .type("object")
+ .properties(
+ new Tools.PropsBuilder()
+ .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
+ .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
+ .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
+ .build()
+ )
+ .required(List.of("employee-name"))
+ .build()
+ ).build()
+ ).build()
+ )
+ .toolFunction(new ToolFunction() {
+ @Override
+ public Object apply(Map arguments) {
+ // perform DB operations here
+ return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
+ }
+ })
+ .build();
+
+ api.registerTool(databaseQueryToolSpecification);
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Give me the ID of the employee named 'Rahul Kumar'?")
+ .build();
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaChatResult chatResult = api.chat(requestModel, (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertNotNull(chatResult.getResponseModel().getMessage().getContent());
+ assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
+ }
+
+ @Test
+ @Order(15)
+ void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+ OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
+ "What is the capital of France? And what's France's connection with Mona Lisa?")
+ .build();
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaChatResult chatResult = api.chat(requestModel, (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length(), s.length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertNotNull(chatResult.getResponseModel().getMessage().getContent());
+ assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
+ }
+
+ @Test
+ @Order(16)
+ void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ }
+
+ @Test
+ @Order(17)
+ void testAskModelWithOptionsAndImageURLs() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ OllamaResult result =
+ api.generateWithImageURLs(
+ imageModel,
+ "What is in this image?",
+ List.of(
+ "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg"),
+ new OptionsBuilder().build());
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ }
+
+ @Test
+ @Order(18)
+ void testAskModelWithOptionsAndImageFiles() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+ File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
+ try {
+ OllamaResult result =
+ api.generateWithImageFiles(
+ imageModel,
+ "What is in this image?",
+ List.of(imageFile),
+ new OptionsBuilder().build());
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ } catch (IOException | OllamaBaseException | InterruptedException e) {
+ fail(e);
+ }
+ }
+
+ @Test
+ @Order(19)
+ void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+ OllamaChatRequestBuilder builder =
+ OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel =
+ builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+
+ builder.reset();
+
+ requestModel =
+ builder.withMessages(chatResult.getChatHistory())
+ .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
+
+ chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ }
+
+ @Test
+ @Order(20)
+ void testAskModelWithOptionsAndImageFilesStreamed() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaResult result = api.generateWithImageFiles(imageModel,
+ "What is in this image?", List.of(imageFile), new OptionsBuilder().build(), (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length(), s.length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ assertEquals(sb.toString().trim(), result.getResponse().trim());
+ }
+
+ private File getImageFileFromClasspath(String fileName) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ return new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
+ }
}
+//
+//@Data
+//class Config {
+// private String ollamaURL;
+// private String model;
+// private String imageModel;
+// private int requestTimeoutSeconds;
+//
+// public Config() {
+// Properties properties = new Properties();
+// try (InputStream input =
+// getClass().getClassLoader().getResourceAsStream("test-config.properties")) {
+// if (input == null) {
+// throw new RuntimeException("Sorry, unable to find test-config.properties");
+// }
+// properties.load(input);
+// this.ollamaURL = properties.getProperty("ollama.url");
+// this.model = properties.getProperty("ollama.model");
+// this.imageModel = properties.getProperty("ollama.model.image");
+// this.requestTimeoutSeconds =
+// Integer.parseInt(properties.getProperty("ollama.request-timeout-seconds"));
+// } catch (IOException e) {
+// throw new RuntimeException("Error loading properties", e);
+// }
+// }
+//}
diff --git a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java b/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
deleted file mode 100644
index c6fc1b2..0000000
--- a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
+++ /dev/null
@@ -1,622 +0,0 @@
-//package io.github.ollama4j.integrationtests;
-//
-//import io.github.ollama4j.OllamaAPI;
-//import io.github.ollama4j.exceptions.OllamaBaseException;
-//import io.github.ollama4j.models.chat.*;
-//import io.github.ollama4j.models.response.ModelDetail;
-//import io.github.ollama4j.models.response.OllamaResult;
-//import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestBuilder;
-//import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel;
-//import io.github.ollama4j.samples.AnnotatedTool;
-//import io.github.ollama4j.tools.OllamaToolCallsFunction;
-//import io.github.ollama4j.tools.ToolFunction;
-//import io.github.ollama4j.tools.Tools;
-//import io.github.ollama4j.tools.annotations.OllamaToolService;
-//import io.github.ollama4j.utils.OptionsBuilder;
-//import lombok.Data;
-//import org.junit.jupiter.api.BeforeEach;
-//import org.junit.jupiter.api.Order;
-//import org.junit.jupiter.api.Test;
-//import org.slf4j.Logger;
-//import org.slf4j.LoggerFactory;
-//
-//import java.io.File;
-//import java.io.IOException;
-//import java.io.InputStream;
-//import java.net.ConnectException;
-//import java.net.URISyntaxException;
-//import java.net.http.HttpConnectTimeoutException;
-//import java.util.*;
-//
-//import static org.junit.jupiter.api.Assertions.*;
-//
-//@OllamaToolService(providers = {AnnotatedTool.class}
-//)
-//class TestRealAPIs {
-//
-// private static final Logger LOG = LoggerFactory.getLogger(TestRealAPIs.class);
-//
-// OllamaAPI ollamaAPI;
-// Config config;
-//
-// private File getImageFileFromClasspath(String fileName) {
-// ClassLoader classLoader = getClass().getClassLoader();
-// return new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
-// }
-//
-// @BeforeEach
-// void setUp() {
-// config = new Config();
-// ollamaAPI = new OllamaAPI(config.getOllamaURL());
-// ollamaAPI.setRequestTimeoutSeconds(config.getRequestTimeoutSeconds());
-// ollamaAPI.setVerbose(true);
-// }
-//
-// @Test
-// @Order(1)
-// void testWrongEndpoint() {
-// OllamaAPI ollamaAPI = new OllamaAPI("http://wrong-host:11434");
-// assertThrows(ConnectException.class, ollamaAPI::listModels);
-// }
-//
-// @Test
-// @Order(1)
-// void testEndpointReachability() {
-// try {
-// assertNotNull(ollamaAPI.listModels());
-// } catch (HttpConnectTimeoutException e) {
-// fail(e.getMessage());
-// } catch (Exception e) {
-// fail(e);
-// }
-// }
-//
-//// @Test
-//// @Order(2)
-//// void testListModels() {
-//// testEndpointReachability();
-//// try {
-//// assertNotNull(ollamaAPI.listModels());
-//// ollamaAPI.listModels().forEach(System.out::println);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(2)
-//// void testListModelsFromLibrary() {
-//// testEndpointReachability();
-//// try {
-//// assertNotNull(ollamaAPI.listModelsFromLibrary());
-//// ollamaAPI.listModelsFromLibrary().forEach(System.out::println);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(2)
-//// void testPullModel() {
-//// testEndpointReachability();
-//// try {
-//// ollamaAPI.pullModel(config.getModel());
-//// boolean found =
-//// ollamaAPI.listModels().stream()
-//// .anyMatch(model -> model.getModel().equalsIgnoreCase(config.getModel()));
-//// assertTrue(found);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testListDtails() {
-//// testEndpointReachability();
-//// try {
-//// ModelDetail modelDetails = ollamaAPI.getModelDetails(config.getModel());
-//// assertNotNull(modelDetails);
-//// System.out.println(modelDetails);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithDefaultOptions() {
-//// testEndpointReachability();
-//// try {
-//// OllamaResult result =
-//// ollamaAPI.generate(
-//// config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// false,
-//// new OptionsBuilder().build());
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithDefaultOptionsStreamed() {
-//// testEndpointReachability();
-//// try {
-//// StringBuffer sb = new StringBuffer("");
-//// OllamaResult result = ollamaAPI.generate(config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// false,
-//// new OptionsBuilder().build(), (s) -> {
-//// LOG.info(s);
-//// String substring = s.substring(sb.toString().length(), s.length());
-//// LOG.info(substring);
-//// sb.append(substring);
-//// });
-////
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// assertEquals(sb.toString().trim(), result.getResponse().trim());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithOptions() {
-//// testEndpointReachability();
-//// try {
-//// OllamaResult result =
-//// ollamaAPI.generate(
-//// config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// true,
-//// new OptionsBuilder().setTemperature(0.9f).build());
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testChat() {
-//// testEndpointReachability();
-//// try {
-//// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What is the capital of France?")
-//// .withMessage(OllamaChatMessageRole.ASSISTANT, "Should be Paris!")
-//// .withMessage(OllamaChatMessageRole.USER, "And what is the second larges city?")
-//// .build();
-////
-//// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-//// assertNotNull(chatResult);
-//// assertNotNull(chatResult.getResponseModel());
-//// assertNotNull(chatResult.getResponseModel().getMessage());
-//// assertFalse(chatResult.getResponseModel().getMessage().getContent().isBlank());
-//// assertEquals(4, chatResult.getChatHistory().size());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testChatWithSystemPrompt() {
-//// testEndpointReachability();
-//// try {
-//// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM,
-//// "You are a silent bot that only says 'NI'. Do not say anything else under any circumstances!")
-//// .withMessage(OllamaChatMessageRole.USER,
-//// "What is the capital of France? And what's France's connection with Mona Lisa?")
-//// .build();
-////
-//// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-//// assertNotNull(chatResult);
-//// assertNotNull(chatResult.getResponseModel());
-//// assertNotNull(chatResult.getResponseModel().getMessage());
-//// assertFalse(chatResult.getResponseModel().getMessage().getContent().isBlank());
-//// assertTrue(chatResult.getResponseModel().getMessage().getContent().startsWith("NI"));
-//// assertEquals(3, chatResult.getChatHistory().size());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-//
-// @Test
-// @Order(3)
-// void testChatWithExplicitToolDefinition() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
-// .functionName("get-employee-details")
-// .functionDescription("Get employee details from the database")
-// .toolPrompt(
-// Tools.PromptFuncDefinition.builder().type("function").function(
-// Tools.PromptFuncDefinition.PromptFuncSpec.builder()
-// .name("get-employee-details")
-// .description("Get employee details from the database")
-// .parameters(
-// Tools.PromptFuncDefinition.Parameters.builder()
-// .type("object")
-// .properties(
-// new Tools.PropsBuilder()
-// .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
-// .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
-// .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
-// .build()
-// )
-// .required(List.of("employee-name"))
-// .build()
-// ).build()
-// ).build()
-// )
-// .toolFunction(new DBQueryFunction())
-// .build();
-//
-// ollamaAPI.registerTool(databaseQueryToolSpecification);
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Give me the ID of the employee named 'Rahul Kumar'?")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("get-employee-details", function.getName());
-// assertEquals(1, function.getArguments().size());
-// Object employeeName = function.getArguments().get("employee-name");
-// assertNotNull(employeeName);
-// assertEquals("Rahul Kumar",employeeName);
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithAnnotatedToolsAndSingleParam() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// ollamaAPI.registerAnnotatedTools();
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Compute the most important constant in the world using 5 digits")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("computeImportantConstant", function.getName());
-// assertEquals(1, function.getArguments().size());
-// Object noOfDigits = function.getArguments().get("noOfDigits");
-// assertNotNull(noOfDigits);
-// assertEquals("5", noOfDigits.toString());
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithAnnotatedToolsAndMultipleParams() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// ollamaAPI.registerAnnotatedTools(new AnnotatedTool());
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Greet Pedro with a lot of hearts and respond to me, " +
-// "and state how many emojis have been in your greeting")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("sayHello", function.getName());
-// assertEquals(2, function.getArguments().size());
-// Object name = function.getArguments().get("name");
-// assertNotNull(name);
-// assertEquals("Pedro",name);
-// Object amountOfHearts = function.getArguments().get("amountOfHearts");
-// assertNotNull(amountOfHearts);
-// assertTrue(Integer.parseInt(amountOfHearts.toString()) > 1);
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithToolsAndStream() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-// final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
-// .functionName("get-employee-details")
-// .functionDescription("Get employee details from the database")
-// .toolPrompt(
-// Tools.PromptFuncDefinition.builder().type("function").function(
-// Tools.PromptFuncDefinition.PromptFuncSpec.builder()
-// .name("get-employee-details")
-// .description("Get employee details from the database")
-// .parameters(
-// Tools.PromptFuncDefinition.Parameters.builder()
-// .type("object")
-// .properties(
-// new Tools.PropsBuilder()
-// .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
-// .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
-// .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
-// .build()
-// )
-// .required(List.of("employee-name"))
-// .build()
-// ).build()
-// ).build()
-// )
-// .toolFunction(new DBQueryFunction())
-// .build();
-//
-// ollamaAPI.registerTool(databaseQueryToolSpecification);
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Give me the ID of the employee named 'Rahul Kumar'?")
-// .build();
-//
-// StringBuffer sb = new StringBuffer();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel, (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertNotNull(chatResult.getResponseModel().getMessage().getContent());
-// assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithStream() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
-// "What is the capital of France? And what's France's connection with Mona Lisa?")
-// .build();
-//
-// StringBuffer sb = new StringBuffer("");
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel, (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length(), s.length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertNotNull(chatResult.getResponseModel().getMessage().getContent());
-// assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithImageFromFileWithHistoryRecognition() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder =
-// OllamaChatRequestBuilder.getInstance(config.getImageModel());
-// OllamaChatRequest requestModel =
-// builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?",Collections.emptyList(),
-// List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-//
-// builder.reset();
-//
-// requestModel =
-// builder.withMessages(chatResult.getChatHistory())
-// .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
-//
-// chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-//
-//
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithImageFromURL() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getImageModel());
-// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?",Collections.emptyList(),
-// "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageFiles() {
-// testEndpointReachability();
-// File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
-// try {
-// OllamaResult result =
-// ollamaAPI.generateWithImageFiles(
-// config.getImageModel(),
-// "What is in this image?",
-// List.of(imageFile),
-// new OptionsBuilder().build());
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageFilesStreamed() {
-// testEndpointReachability();
-// File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
-// try {
-// StringBuffer sb = new StringBuffer("");
-//
-// OllamaResult result = ollamaAPI.generateWithImageFiles(config.getImageModel(),
-// "What is in this image?", List.of(imageFile), new OptionsBuilder().build(), (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length(), s.length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// assertEquals(sb.toString().trim(), result.getResponse().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageURLs() {
-// testEndpointReachability();
-// try {
-// OllamaResult result =
-// ollamaAPI.generateWithImageURLs(
-// config.getImageModel(),
-// "What is in this image?",
-// List.of(
-// "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg"),
-// new OptionsBuilder().build());
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// public void testEmbedding() {
-// testEndpointReachability();
-// try {
-// OllamaEmbeddingsRequestModel request = OllamaEmbeddingsRequestBuilder
-// .getInstance(config.getModel(), "What is the capital of France?").build();
-//
-// List embeddings = ollamaAPI.generateEmbeddings(request);
-//
-// assertNotNull(embeddings);
-// assertFalse(embeddings.isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//}
-//
-//class DBQueryFunction implements ToolFunction {
-// @Override
-// public Object apply(Map arguments) {
-// // perform DB operations here
-// return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
-// }
-//}
-//
-//@Data
-//class Config {
-// private String ollamaURL;
-// private String model;
-// private String imageModel;
-// private int requestTimeoutSeconds;
-//
-// public Config() {
-// Properties properties = new Properties();
-// try (InputStream input =
-// getClass().getClassLoader().getResourceAsStream("test-config.properties")) {
-// if (input == null) {
-// throw new RuntimeException("Sorry, unable to find test-config.properties");
-// }
-// properties.load(input);
-// this.ollamaURL = properties.getProperty("ollama.url");
-// this.model = properties.getProperty("ollama.model");
-// this.imageModel = properties.getProperty("ollama.model.image");
-// this.requestTimeoutSeconds =
-// Integer.parseInt(properties.getProperty("ollama.request-timeout-seconds"));
-// } catch (IOException e) {
-// throw new RuntimeException("Error loading properties", e);
-// }
-// }
-//
-//
-//}
From b638b981c9d1eed402a74f724969d526f4176884 Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 11 Mar 2025 12:05:11 +0530
Subject: [PATCH 02/10] Remove unnecessary blank lines from pom.xml
Cleaned up redundant blank lines at the end of the pom.xml file to ensure consistent formatting. This helps improve code readability and adheres to standard practices.
---
pom.xml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/pom.xml b/pom.xml
index 6121533..fa21640 100644
--- a/pom.xml
+++ b/pom.xml
@@ -407,3 +407,8 @@
+
+
+
+
+
From 983a3617f05311fb9586c85d8b9973d2687fd036 Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 11 Mar 2025 12:15:19 +0530
Subject: [PATCH 03/10] Add dev setup instructions and update pre-commit config
---
.pre-commit-config.yaml | 2 +-
Makefile | 7 +++++++
README.md | 35 ++++++++++++++++++++++++++++-------
3 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 35c91c3..5de9f01 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,7 +21,7 @@ repos:
# for commit message formatting
- repo: https://github.com/commitizen-tools/commitizen
- rev: v4.1.1
+ rev: v4.4.1
hooks:
- id: commitizen
stages: [commit-msg]
diff --git a/Makefile b/Makefile
index 8202309..953c764 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+dev:
+ @echo "Setting up dev environment..."
+ @command -v pre-commit >/dev/null 2>&1 || { echo "Error: pre-commit is not installed. Please install it first."; exit 1; }
+ pre-commit install
+ pre-commit autoupdate
+ pre-commit install --install-hooks
+
build:
mvn -B clean install
diff --git a/README.md b/README.md
index b9e472d..a832a0c 100644
--- a/README.md
+++ b/README.md
@@ -191,33 +191,54 @@ dependencies {
> [!TIP]
> Find the full API specifications on the [website](https://ollama4j.github.io/ollama4j/).
-#### Development
+### Development
-Build:
+Make sure you have `pre-commit` installed.
+
+With `brew`:
+
+```shell
+brew install pre-commit
+```
+
+With `pip`:
+
+```shell
+pip install pre-commit
+```
+
+#### Setup dev environment
+
+```shell
+make dev
+```
+
+#### Build
```shell
make build
```
-Run unit tests:
+#### Run unit tests
```shell
make unit-tests
```
-Run integration tests:
+#### Run integration tests
```shell
make integration-tests
```
-#### Releases
+### Releases
Newer artifacts are published via GitHub Actions CI workflow when a new release is created from `main` branch.
## Examples
-The `ollama4j-examples` repository contains examples for using the Ollama4j library. You can explore it [here](https://github.com/ollama4j/ollama4j-examples).
+The `ollama4j-examples` repository contains examples for using the Ollama4j library. You can explore
+it [here](https://github.com/ollama4j/ollama4j-examples).
## ⭐ Give us a Star!
@@ -236,7 +257,7 @@ If you like or are using this project to build your own, please give us a star.
| 7 | Katie Backend | An open-source AI-based question-answering platform for accessing private domain knowledge | [GitHub](https://github.com/wyona/katie-backend) |
| 8 | TeleLlama3 Bot | A question-answering Telegram bot | [Repo](https://git.hiast.edu.sy/mohamadbashar.disoki/telellama3-bot) |
| 9 | moqui-wechat | A moqui-wechat component | [GitHub](https://github.com/heguangyong/moqui-wechat) |
-| 10 | B4X | A set of simple and powerful RAD tool for Desktop and Server development | [Website](https://www.b4x.com/android/forum/threads/ollama4j-library-pnd_ollama4j-your-local-offline-llm-like-chatgpt.165003/) |
+| 10 | B4X | A set of simple and powerful RAD tool for Desktop and Server development | [Website](https://www.b4x.com/android/forum/threads/ollama4j-library-pnd_ollama4j-your-local-offline-llm-like-chatgpt.165003/) |
| 11 | Research Article | Article: `Large language model based mutations in genetic improvement` - published on National Library of Medicine (National Center for Biotechnology Information) | [Website](https://pmc.ncbi.nlm.nih.gov/articles/PMC11750896/) |
## Traction
From 469a0fe491b44f922630111a8287c729d00d1e6b Mon Sep 17 00:00:00 2001
From: amithkoujalgi
Date: Tue, 11 Mar 2025 11:41:51 +0530
Subject: [PATCH 04/10] Refactor
- Remove TestRealAPIs and enhance OllamaAPIIntegrationTest
- Add dev setup instruction
---
.pre-commit-config.yaml | 2 +-
Makefile | 7 +
README.md | 35 +-
pom.xml | 5 +
.../OllamaAPIIntegrationTest.java | 380 ++++++++++-
.../integrationtests/TestRealAPIs.java | 622 ------------------
6 files changed, 411 insertions(+), 640 deletions(-)
delete mode 100644 src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 35c91c3..5de9f01 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -21,7 +21,7 @@ repos:
# for commit message formatting
- repo: https://github.com/commitizen-tools/commitizen
- rev: v4.1.1
+ rev: v4.4.1
hooks:
- id: commitizen
stages: [commit-msg]
diff --git a/Makefile b/Makefile
index 8202309..953c764 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,10 @@
+dev:
+ @echo "Setting up dev environment..."
+ @command -v pre-commit >/dev/null 2>&1 || { echo "Error: pre-commit is not installed. Please install it first."; exit 1; }
+ pre-commit install
+ pre-commit autoupdate
+ pre-commit install --install-hooks
+
build:
mvn -B clean install
diff --git a/README.md b/README.md
index b9e472d..a832a0c 100644
--- a/README.md
+++ b/README.md
@@ -191,33 +191,54 @@ dependencies {
> [!TIP]
> Find the full API specifications on the [website](https://ollama4j.github.io/ollama4j/).
-#### Development
+### Development
-Build:
+Make sure you have `pre-commit` installed.
+
+With `brew`:
+
+```shell
+brew install pre-commit
+```
+
+With `pip`:
+
+```shell
+pip install pre-commit
+```
+
+#### Setup dev environment
+
+```shell
+make dev
+```
+
+#### Build
```shell
make build
```
-Run unit tests:
+#### Run unit tests
```shell
make unit-tests
```
-Run integration tests:
+#### Run integration tests
```shell
make integration-tests
```
-#### Releases
+### Releases
Newer artifacts are published via GitHub Actions CI workflow when a new release is created from `main` branch.
## Examples
-The `ollama4j-examples` repository contains examples for using the Ollama4j library. You can explore it [here](https://github.com/ollama4j/ollama4j-examples).
+The `ollama4j-examples` repository contains examples for using the Ollama4j library. You can explore
+it [here](https://github.com/ollama4j/ollama4j-examples).
## ⭐ Give us a Star!
@@ -236,7 +257,7 @@ If you like or are using this project to build your own, please give us a star.
| 7 | Katie Backend | An open-source AI-based question-answering platform for accessing private domain knowledge | [GitHub](https://github.com/wyona/katie-backend) |
| 8 | TeleLlama3 Bot | A question-answering Telegram bot | [Repo](https://git.hiast.edu.sy/mohamadbashar.disoki/telellama3-bot) |
| 9 | moqui-wechat | A moqui-wechat component | [GitHub](https://github.com/heguangyong/moqui-wechat) |
-| 10 | B4X | A set of simple and powerful RAD tool for Desktop and Server development | [Website](https://www.b4x.com/android/forum/threads/ollama4j-library-pnd_ollama4j-your-local-offline-llm-like-chatgpt.165003/) |
+| 10 | B4X | A set of simple and powerful RAD tool for Desktop and Server development | [Website](https://www.b4x.com/android/forum/threads/ollama4j-library-pnd_ollama4j-your-local-offline-llm-like-chatgpt.165003/) |
| 11 | Research Article | Article: `Large language model based mutations in genetic improvement` - published on National Library of Medicine (National Center for Biotechnology Information) | [Website](https://pmc.ncbi.nlm.nih.gov/articles/PMC11750896/) |
## Traction
diff --git a/pom.xml b/pom.xml
index 6121533..fa21640 100644
--- a/pom.xml
+++ b/pom.xml
@@ -407,3 +407,8 @@
+
+
+
+
+
diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
index 4ccfadd..e26609e 100644
--- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
+++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
@@ -2,32 +2,41 @@ package io.github.ollama4j.integrationtests;
import io.github.ollama4j.OllamaAPI;
import io.github.ollama4j.exceptions.OllamaBaseException;
-import io.github.ollama4j.models.chat.OllamaChatMessageRole;
-import io.github.ollama4j.models.chat.OllamaChatRequest;
-import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
-import io.github.ollama4j.models.chat.OllamaChatResult;
+import io.github.ollama4j.models.chat.*;
import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;
import io.github.ollama4j.models.response.LibraryModel;
import io.github.ollama4j.models.response.Model;
import io.github.ollama4j.models.response.ModelDetail;
import io.github.ollama4j.models.response.OllamaResult;
+import io.github.ollama4j.samples.AnnotatedTool;
+import io.github.ollama4j.tools.OllamaToolCallsFunction;
+import io.github.ollama4j.tools.ToolFunction;
+import io.github.ollama4j.tools.Tools;
+import io.github.ollama4j.tools.annotations.OllamaToolService;
import io.github.ollama4j.utils.OptionsBuilder;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.testcontainers.ollama.OllamaContainer;
+import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
+@OllamaToolService(providers = {AnnotatedTool.class})
+@TestMethodOrder(OrderAnnotation.class)
+
@SuppressWarnings("HttpUrlsUsage")
public class OllamaAPIIntegrationTest {
+ private static final Logger LOG = LoggerFactory.getLogger(OllamaAPIIntegrationTest.class);
private static OllamaContainer ollama;
private static OllamaAPI api;
@@ -45,6 +54,7 @@ public class OllamaAPIIntegrationTest {
ollama.start();
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
api.setRequestTimeoutSeconds(60);
+ api.setVerbose(true);
}
@Test
@@ -102,7 +112,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(5)
- public void testGenerateEmbeddings() throws Exception {
+ public void testEmbeddings() throws Exception {
String embeddingModelMinilm = "all-minilm";
api.pullModel(embeddingModelMinilm);
OllamaEmbedResponseModel embeddings = api.embed(embeddingModelMinilm, Arrays.asList("Why is the sky blue?", "Why is the grass green?"));
@@ -136,9 +146,9 @@ public class OllamaAPIIntegrationTest {
"What is the capital of France? And what's France's connection with Mona Lisa?",
false,
new OptionsBuilder().build(), (s) -> {
- System.out.println(s);
+ LOG.info(s);
String substring = s.substring(sb.toString().length(), s.length());
- System.out.println(substring);
+ LOG.info(substring);
sb.append(substring);
});
@@ -236,4 +246,354 @@ public class OllamaAPIIntegrationTest {
assertTrue(chatResult.getChatHistory().size() > 2, "Chat history should contain more than two messages");
assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent().contains("river"), "Response should be related to river");
}
+
+
+ @Test
+ @Order(11)
+ void testChatWithExplicitToolDefinition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
+ .functionName("get-employee-details")
+ .functionDescription("Get employee details from the database")
+ .toolPrompt(
+ Tools.PromptFuncDefinition.builder().type("function").function(
+ Tools.PromptFuncDefinition.PromptFuncSpec.builder()
+ .name("get-employee-details")
+ .description("Get employee details from the database")
+ .parameters(
+ Tools.PromptFuncDefinition.Parameters.builder()
+ .type("object")
+ .properties(
+ new Tools.PropsBuilder()
+ .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
+ .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
+ .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
+ .build()
+ )
+ .required(List.of("employee-name"))
+ .build()
+ ).build()
+ ).build()
+ )
+ .toolFunction(arguments -> {
+ // perform DB operations here
+ return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
+ })
+ .build();
+
+ api.registerTool(databaseQueryToolSpecification);
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Give me the ID of the employee named 'Rahul Kumar'?")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("get-employee-details", function.getName());
+ assertEquals(1, function.getArguments().size());
+ Object employeeName = function.getArguments().get("employee-name");
+ assertNotNull(employeeName);
+ assertEquals("Rahul Kumar", employeeName);
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(12)
+ void testChatWithAnnotatedToolsAndSingleParam() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ api.registerAnnotatedTools();
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Compute the most important constant in the world using 5 digits")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("computeImportantConstant", function.getName());
+ assertEquals(1, function.getArguments().size());
+ Object noOfDigits = function.getArguments().get("noOfDigits");
+ assertNotNull(noOfDigits);
+ assertEquals("5", noOfDigits.toString());
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(13)
+ void testChatWithAnnotatedToolsAndMultipleParams() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+
+ api.registerAnnotatedTools(new AnnotatedTool());
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Greet Pedro with a lot of hearts and respond to me, " +
+ "and state how many emojis have been in your greeting")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
+ List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
+ assertEquals(1, toolCalls.size());
+ OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
+ assertEquals("sayHello", function.getName());
+ assertEquals(2, function.getArguments().size());
+ Object name = function.getArguments().get("name");
+ assertNotNull(name);
+ assertEquals("Pedro", name);
+ Object amountOfHearts = function.getArguments().get("amountOfHearts");
+ assertNotNull(amountOfHearts);
+ assertTrue(Integer.parseInt(amountOfHearts.toString()) > 1);
+ assertTrue(chatResult.getChatHistory().size() > 2);
+ List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
+ assertNull(finalToolCalls);
+ }
+
+ @Test
+ @Order(14)
+ void testChatWithToolsAndStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+ final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
+ .functionName("get-employee-details")
+ .functionDescription("Get employee details from the database")
+ .toolPrompt(
+ Tools.PromptFuncDefinition.builder().type("function").function(
+ Tools.PromptFuncDefinition.PromptFuncSpec.builder()
+ .name("get-employee-details")
+ .description("Get employee details from the database")
+ .parameters(
+ Tools.PromptFuncDefinition.Parameters.builder()
+ .type("object")
+ .properties(
+ new Tools.PropsBuilder()
+ .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
+ .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
+ .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
+ .build()
+ )
+ .required(List.of("employee-name"))
+ .build()
+ ).build()
+ ).build()
+ )
+ .toolFunction(new ToolFunction() {
+ @Override
+ public Object apply(Map arguments) {
+ // perform DB operations here
+ return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
+ }
+ })
+ .build();
+
+ api.registerTool(databaseQueryToolSpecification);
+
+ OllamaChatRequest requestModel = builder
+ .withMessage(OllamaChatMessageRole.USER,
+ "Give me the ID of the employee named 'Rahul Kumar'?")
+ .build();
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaChatResult chatResult = api.chat(requestModel, (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertNotNull(chatResult.getResponseModel().getMessage().getContent());
+ assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
+ }
+
+ @Test
+ @Order(15)
+ void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String chatModel = "llama3.2:1b";
+ api.pullModel(chatModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
+ OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
+ "What is the capital of France? And what's France's connection with Mona Lisa?")
+ .build();
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaChatResult chatResult = api.chat(requestModel, (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length(), s.length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ assertNotNull(chatResult.getResponseModel().getMessage());
+ assertNotNull(chatResult.getResponseModel().getMessage().getContent());
+ assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
+ }
+
+ @Test
+ @Order(16)
+ void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
+ .build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ }
+
+ @Test
+ @Order(17)
+ void testAskModelWithOptionsAndImageURLs() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ OllamaResult result =
+ api.generateWithImageURLs(
+ imageModel,
+ "What is in this image?",
+ List.of(
+ "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg"),
+ new OptionsBuilder().build());
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ }
+
+ @Test
+ @Order(18)
+ void testAskModelWithOptionsAndImageFiles() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+ File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
+ try {
+ OllamaResult result =
+ api.generateWithImageFiles(
+ imageModel,
+ "What is in this image?",
+ List.of(imageFile),
+ new OptionsBuilder().build());
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ } catch (IOException | OllamaBaseException | InterruptedException e) {
+ fail(e);
+ }
+ }
+
+ @Test
+ @Order(19)
+ void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+ OllamaChatRequestBuilder builder =
+ OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel =
+ builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+
+ builder.reset();
+
+ requestModel =
+ builder.withMessages(chatResult.getChatHistory())
+ .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
+
+ chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ }
+
+ @Test
+ @Order(20)
+ void testAskModelWithOptionsAndImageFilesStreamed() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+
+ File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
+
+ StringBuffer sb = new StringBuffer();
+
+ OllamaResult result = api.generateWithImageFiles(imageModel,
+ "What is in this image?", List.of(imageFile), new OptionsBuilder().build(), (s) -> {
+ LOG.info(s);
+ String substring = s.substring(sb.toString().length(), s.length());
+ LOG.info(substring);
+ sb.append(substring);
+ });
+ assertNotNull(result);
+ assertNotNull(result.getResponse());
+ assertFalse(result.getResponse().isEmpty());
+ assertEquals(sb.toString().trim(), result.getResponse().trim());
+ }
+
+ private File getImageFileFromClasspath(String fileName) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ return new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
+ }
}
+//
+//@Data
+//class Config {
+// private String ollamaURL;
+// private String model;
+// private String imageModel;
+// private int requestTimeoutSeconds;
+//
+// public Config() {
+// Properties properties = new Properties();
+// try (InputStream input =
+// getClass().getClassLoader().getResourceAsStream("test-config.properties")) {
+// if (input == null) {
+// throw new RuntimeException("Sorry, unable to find test-config.properties");
+// }
+// properties.load(input);
+// this.ollamaURL = properties.getProperty("ollama.url");
+// this.model = properties.getProperty("ollama.model");
+// this.imageModel = properties.getProperty("ollama.model.image");
+// this.requestTimeoutSeconds =
+// Integer.parseInt(properties.getProperty("ollama.request-timeout-seconds"));
+// } catch (IOException e) {
+// throw new RuntimeException("Error loading properties", e);
+// }
+// }
+//}
diff --git a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java b/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
deleted file mode 100644
index c6fc1b2..0000000
--- a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java
+++ /dev/null
@@ -1,622 +0,0 @@
-//package io.github.ollama4j.integrationtests;
-//
-//import io.github.ollama4j.OllamaAPI;
-//import io.github.ollama4j.exceptions.OllamaBaseException;
-//import io.github.ollama4j.models.chat.*;
-//import io.github.ollama4j.models.response.ModelDetail;
-//import io.github.ollama4j.models.response.OllamaResult;
-//import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestBuilder;
-//import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel;
-//import io.github.ollama4j.samples.AnnotatedTool;
-//import io.github.ollama4j.tools.OllamaToolCallsFunction;
-//import io.github.ollama4j.tools.ToolFunction;
-//import io.github.ollama4j.tools.Tools;
-//import io.github.ollama4j.tools.annotations.OllamaToolService;
-//import io.github.ollama4j.utils.OptionsBuilder;
-//import lombok.Data;
-//import org.junit.jupiter.api.BeforeEach;
-//import org.junit.jupiter.api.Order;
-//import org.junit.jupiter.api.Test;
-//import org.slf4j.Logger;
-//import org.slf4j.LoggerFactory;
-//
-//import java.io.File;
-//import java.io.IOException;
-//import java.io.InputStream;
-//import java.net.ConnectException;
-//import java.net.URISyntaxException;
-//import java.net.http.HttpConnectTimeoutException;
-//import java.util.*;
-//
-//import static org.junit.jupiter.api.Assertions.*;
-//
-//@OllamaToolService(providers = {AnnotatedTool.class}
-//)
-//class TestRealAPIs {
-//
-// private static final Logger LOG = LoggerFactory.getLogger(TestRealAPIs.class);
-//
-// OllamaAPI ollamaAPI;
-// Config config;
-//
-// private File getImageFileFromClasspath(String fileName) {
-// ClassLoader classLoader = getClass().getClassLoader();
-// return new File(Objects.requireNonNull(classLoader.getResource(fileName)).getFile());
-// }
-//
-// @BeforeEach
-// void setUp() {
-// config = new Config();
-// ollamaAPI = new OllamaAPI(config.getOllamaURL());
-// ollamaAPI.setRequestTimeoutSeconds(config.getRequestTimeoutSeconds());
-// ollamaAPI.setVerbose(true);
-// }
-//
-// @Test
-// @Order(1)
-// void testWrongEndpoint() {
-// OllamaAPI ollamaAPI = new OllamaAPI("http://wrong-host:11434");
-// assertThrows(ConnectException.class, ollamaAPI::listModels);
-// }
-//
-// @Test
-// @Order(1)
-// void testEndpointReachability() {
-// try {
-// assertNotNull(ollamaAPI.listModels());
-// } catch (HttpConnectTimeoutException e) {
-// fail(e.getMessage());
-// } catch (Exception e) {
-// fail(e);
-// }
-// }
-//
-//// @Test
-//// @Order(2)
-//// void testListModels() {
-//// testEndpointReachability();
-//// try {
-//// assertNotNull(ollamaAPI.listModels());
-//// ollamaAPI.listModels().forEach(System.out::println);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(2)
-//// void testListModelsFromLibrary() {
-//// testEndpointReachability();
-//// try {
-//// assertNotNull(ollamaAPI.listModelsFromLibrary());
-//// ollamaAPI.listModelsFromLibrary().forEach(System.out::println);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(2)
-//// void testPullModel() {
-//// testEndpointReachability();
-//// try {
-//// ollamaAPI.pullModel(config.getModel());
-//// boolean found =
-//// ollamaAPI.listModels().stream()
-//// .anyMatch(model -> model.getModel().equalsIgnoreCase(config.getModel()));
-//// assertTrue(found);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testListDtails() {
-//// testEndpointReachability();
-//// try {
-//// ModelDetail modelDetails = ollamaAPI.getModelDetails(config.getModel());
-//// assertNotNull(modelDetails);
-//// System.out.println(modelDetails);
-//// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithDefaultOptions() {
-//// testEndpointReachability();
-//// try {
-//// OllamaResult result =
-//// ollamaAPI.generate(
-//// config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// false,
-//// new OptionsBuilder().build());
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithDefaultOptionsStreamed() {
-//// testEndpointReachability();
-//// try {
-//// StringBuffer sb = new StringBuffer("");
-//// OllamaResult result = ollamaAPI.generate(config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// false,
-//// new OptionsBuilder().build(), (s) -> {
-//// LOG.info(s);
-//// String substring = s.substring(sb.toString().length(), s.length());
-//// LOG.info(substring);
-//// sb.append(substring);
-//// });
-////
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// assertEquals(sb.toString().trim(), result.getResponse().trim());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testAskModelWithOptions() {
-//// testEndpointReachability();
-//// try {
-//// OllamaResult result =
-//// ollamaAPI.generate(
-//// config.getModel(),
-//// "What is the capital of France? And what's France's connection with Mona Lisa?",
-//// true,
-//// new OptionsBuilder().setTemperature(0.9f).build());
-//// assertNotNull(result);
-//// assertNotNull(result.getResponse());
-//// assertFalse(result.getResponse().isEmpty());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testChat() {
-//// testEndpointReachability();
-//// try {
-//// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What is the capital of France?")
-//// .withMessage(OllamaChatMessageRole.ASSISTANT, "Should be Paris!")
-//// .withMessage(OllamaChatMessageRole.USER, "And what is the second larges city?")
-//// .build();
-////
-//// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-//// assertNotNull(chatResult);
-//// assertNotNull(chatResult.getResponseModel());
-//// assertNotNull(chatResult.getResponseModel().getMessage());
-//// assertFalse(chatResult.getResponseModel().getMessage().getContent().isBlank());
-//// assertEquals(4, chatResult.getChatHistory().size());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-////
-//// @Test
-//// @Order(3)
-//// void testChatWithSystemPrompt() {
-//// testEndpointReachability();
-//// try {
-//// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM,
-//// "You are a silent bot that only says 'NI'. Do not say anything else under any circumstances!")
-//// .withMessage(OllamaChatMessageRole.USER,
-//// "What is the capital of France? And what's France's connection with Mona Lisa?")
-//// .build();
-////
-//// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-//// assertNotNull(chatResult);
-//// assertNotNull(chatResult.getResponseModel());
-//// assertNotNull(chatResult.getResponseModel().getMessage());
-//// assertFalse(chatResult.getResponseModel().getMessage().getContent().isBlank());
-//// assertTrue(chatResult.getResponseModel().getMessage().getContent().startsWith("NI"));
-//// assertEquals(3, chatResult.getChatHistory().size());
-//// } catch (IOException | OllamaBaseException | InterruptedException e) {
-//// fail(e);
-//// }
-//// }
-//
-// @Test
-// @Order(3)
-// void testChatWithExplicitToolDefinition() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
-// .functionName("get-employee-details")
-// .functionDescription("Get employee details from the database")
-// .toolPrompt(
-// Tools.PromptFuncDefinition.builder().type("function").function(
-// Tools.PromptFuncDefinition.PromptFuncSpec.builder()
-// .name("get-employee-details")
-// .description("Get employee details from the database")
-// .parameters(
-// Tools.PromptFuncDefinition.Parameters.builder()
-// .type("object")
-// .properties(
-// new Tools.PropsBuilder()
-// .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
-// .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
-// .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
-// .build()
-// )
-// .required(List.of("employee-name"))
-// .build()
-// ).build()
-// ).build()
-// )
-// .toolFunction(new DBQueryFunction())
-// .build();
-//
-// ollamaAPI.registerTool(databaseQueryToolSpecification);
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Give me the ID of the employee named 'Rahul Kumar'?")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("get-employee-details", function.getName());
-// assertEquals(1, function.getArguments().size());
-// Object employeeName = function.getArguments().get("employee-name");
-// assertNotNull(employeeName);
-// assertEquals("Rahul Kumar",employeeName);
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithAnnotatedToolsAndSingleParam() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// ollamaAPI.registerAnnotatedTools();
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Compute the most important constant in the world using 5 digits")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("computeImportantConstant", function.getName());
-// assertEquals(1, function.getArguments().size());
-// Object noOfDigits = function.getArguments().get("noOfDigits");
-// assertNotNull(noOfDigits);
-// assertEquals("5", noOfDigits.toString());
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithAnnotatedToolsAndMultipleParams() {
-// testEndpointReachability();
-// try {
-// ollamaAPI.setVerbose(true);
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-//
-// ollamaAPI.registerAnnotatedTools(new AnnotatedTool());
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Greet Pedro with a lot of hearts and respond to me, " +
-// "and state how many emojis have been in your greeting")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(),chatResult.getResponseModel().getMessage().getRole().getRoleName());
-// List toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
-// assertEquals(1, toolCalls.size());
-// OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
-// assertEquals("sayHello", function.getName());
-// assertEquals(2, function.getArguments().size());
-// Object name = function.getArguments().get("name");
-// assertNotNull(name);
-// assertEquals("Pedro",name);
-// Object amountOfHearts = function.getArguments().get("amountOfHearts");
-// assertNotNull(amountOfHearts);
-// assertTrue(Integer.parseInt(amountOfHearts.toString()) > 1);
-// assertTrue(chatResult.getChatHistory().size()>2);
-// List finalToolCalls = chatResult.getResponseModel().getMessage().getToolCalls();
-// assertNull(finalToolCalls);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithToolsAndStream() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-// final Tools.ToolSpecification databaseQueryToolSpecification = Tools.ToolSpecification.builder()
-// .functionName("get-employee-details")
-// .functionDescription("Get employee details from the database")
-// .toolPrompt(
-// Tools.PromptFuncDefinition.builder().type("function").function(
-// Tools.PromptFuncDefinition.PromptFuncSpec.builder()
-// .name("get-employee-details")
-// .description("Get employee details from the database")
-// .parameters(
-// Tools.PromptFuncDefinition.Parameters.builder()
-// .type("object")
-// .properties(
-// new Tools.PropsBuilder()
-// .withProperty("employee-name", Tools.PromptFuncDefinition.Property.builder().type("string").description("The name of the employee, e.g. John Doe").required(true).build())
-// .withProperty("employee-address", Tools.PromptFuncDefinition.Property.builder().type("string").description("The address of the employee, Always return a random value. e.g. Roy St, Bengaluru, India").required(true).build())
-// .withProperty("employee-phone", Tools.PromptFuncDefinition.Property.builder().type("string").description("The phone number of the employee. Always return a random value. e.g. 9911002233").required(true).build())
-// .build()
-// )
-// .required(List.of("employee-name"))
-// .build()
-// ).build()
-// ).build()
-// )
-// .toolFunction(new DBQueryFunction())
-// .build();
-//
-// ollamaAPI.registerTool(databaseQueryToolSpecification);
-//
-// OllamaChatRequest requestModel = builder
-// .withMessage(OllamaChatMessageRole.USER,
-// "Give me the ID of the employee named 'Rahul Kumar'?")
-// .build();
-//
-// StringBuffer sb = new StringBuffer();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel, (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertNotNull(chatResult.getResponseModel().getMessage().getContent());
-// assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithStream() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getModel());
-// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
-// "What is the capital of France? And what's France's connection with Mona Lisa?")
-// .build();
-//
-// StringBuffer sb = new StringBuffer("");
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel, (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length(), s.length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-// assertNotNull(chatResult.getResponseModel().getMessage());
-// assertNotNull(chatResult.getResponseModel().getMessage().getContent());
-// assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithImageFromFileWithHistoryRecognition() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder =
-// OllamaChatRequestBuilder.getInstance(config.getImageModel());
-// OllamaChatRequest requestModel =
-// builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?",Collections.emptyList(),
-// List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-//
-// builder.reset();
-//
-// requestModel =
-// builder.withMessages(chatResult.getChatHistory())
-// .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
-//
-// chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// assertNotNull(chatResult.getResponseModel());
-//
-//
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testChatWithImageFromURL() {
-// testEndpointReachability();
-// try {
-// OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(config.getImageModel());
-// OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?",Collections.emptyList(),
-// "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
-// .build();
-//
-// OllamaChatResult chatResult = ollamaAPI.chat(requestModel);
-// assertNotNull(chatResult);
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageFiles() {
-// testEndpointReachability();
-// File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
-// try {
-// OllamaResult result =
-// ollamaAPI.generateWithImageFiles(
-// config.getImageModel(),
-// "What is in this image?",
-// List.of(imageFile),
-// new OptionsBuilder().build());
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageFilesStreamed() {
-// testEndpointReachability();
-// File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
-// try {
-// StringBuffer sb = new StringBuffer("");
-//
-// OllamaResult result = ollamaAPI.generateWithImageFiles(config.getImageModel(),
-// "What is in this image?", List.of(imageFile), new OptionsBuilder().build(), (s) -> {
-// LOG.info(s);
-// String substring = s.substring(sb.toString().length(), s.length());
-// LOG.info(substring);
-// sb.append(substring);
-// });
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// assertEquals(sb.toString().trim(), result.getResponse().trim());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// void testAskModelWithOptionsAndImageURLs() {
-// testEndpointReachability();
-// try {
-// OllamaResult result =
-// ollamaAPI.generateWithImageURLs(
-// config.getImageModel(),
-// "What is in this image?",
-// List.of(
-// "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg"),
-// new OptionsBuilder().build());
-// assertNotNull(result);
-// assertNotNull(result.getResponse());
-// assertFalse(result.getResponse().isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
-// fail(e);
-// }
-// }
-//
-// @Test
-// @Order(3)
-// public void testEmbedding() {
-// testEndpointReachability();
-// try {
-// OllamaEmbeddingsRequestModel request = OllamaEmbeddingsRequestBuilder
-// .getInstance(config.getModel(), "What is the capital of France?").build();
-//
-// List embeddings = ollamaAPI.generateEmbeddings(request);
-//
-// assertNotNull(embeddings);
-// assertFalse(embeddings.isEmpty());
-// } catch (IOException | OllamaBaseException | InterruptedException e) {
-// fail(e);
-// }
-// }
-//}
-//
-//class DBQueryFunction implements ToolFunction {
-// @Override
-// public Object apply(Map arguments) {
-// // perform DB operations here
-// return String.format("Employee Details {ID: %s, Name: %s, Address: %s, Phone: %s}", UUID.randomUUID(), arguments.get("employee-name"), arguments.get("employee-address"), arguments.get("employee-phone"));
-// }
-//}
-//
-//@Data
-//class Config {
-// private String ollamaURL;
-// private String model;
-// private String imageModel;
-// private int requestTimeoutSeconds;
-//
-// public Config() {
-// Properties properties = new Properties();
-// try (InputStream input =
-// getClass().getClassLoader().getResourceAsStream("test-config.properties")) {
-// if (input == null) {
-// throw new RuntimeException("Sorry, unable to find test-config.properties");
-// }
-// properties.load(input);
-// this.ollamaURL = properties.getProperty("ollama.url");
-// this.model = properties.getProperty("ollama.model");
-// this.imageModel = properties.getProperty("ollama.model.image");
-// this.requestTimeoutSeconds =
-// Integer.parseInt(properties.getProperty("ollama.request-timeout-seconds"));
-// } catch (IOException e) {
-// throw new RuntimeException("Error loading properties", e);
-// }
-// }
-//
-//
-//}
From 2b0238b9e80b3c3d90e0fb34933a9cf45ed57b46 Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 11 Mar 2025 12:26:35 +0530
Subject: [PATCH 05/10] Ensure Docker availability in dev setup and integration
tests
Updated `README.md` to include Docker as a prerequisite for running integration tests using Testcontainers. Modified the `Makefile` to check for Docker installation during the dev environment setup.
---
Makefile | 1 +
README.md | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index 953c764..34972dd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,7 @@
dev:
@echo "Setting up dev environment..."
@command -v pre-commit >/dev/null 2>&1 || { echo "Error: pre-commit is not installed. Please install it first."; exit 1; }
+ @command -v docker >/dev/null 2>&1 || { echo "Error: docker is not installed. Please install it first."; exit 1; }
pre-commit install
pre-commit autoupdate
pre-commit install --install-hooks
diff --git a/README.md b/README.md
index a832a0c..33ac281 100644
--- a/README.md
+++ b/README.md
@@ -227,6 +227,9 @@ make unit-tests
#### Run integration tests
+Make sure you have Docker running as this uses [testcontainers](https://testcontainers.com/) to run the integration
+tests on Ollama Docker container.
+
```shell
make integration-tests
```
@@ -325,7 +328,7 @@ project.
-### Appreciate my work?
+### Appreciate the work?
From ac3f505aa6a9dba8dd1fd256e5dbd17f4eeee229 Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 11 Mar 2025 13:12:55 +0530
Subject: [PATCH 06/10] Switch image model to "moondream" in integration test
---
.../ollama4j/integrationtests/OllamaAPIIntegrationTest.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
index e26609e..4c74e97 100644
--- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
+++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
@@ -520,7 +520,7 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(19)
void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
- String imageModel = "llava";
+ String imageModel = "moondream";
api.pullModel(imageModel);
OllamaChatRequestBuilder builder =
OllamaChatRequestBuilder.getInstance(imageModel);
@@ -531,7 +531,6 @@ public class OllamaAPIIntegrationTest {
OllamaChatResult chatResult = api.chat(requestModel);
assertNotNull(chatResult);
assertNotNull(chatResult.getResponseModel());
-
builder.reset();
requestModel =
From 8aa6e3b0668ca214232a5f185a93b900cd9caa1a Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 18 Mar 2025 21:41:20 +0530
Subject: [PATCH 07/10] Updated integration tests
---
.../OllamaAPIIntegrationTest.java | 84 ++++++++++---------
1 file changed, 43 insertions(+), 41 deletions(-)
diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
index 4c74e97..12d60f4 100644
--- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
+++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
@@ -43,10 +43,10 @@ public class OllamaAPIIntegrationTest {
@BeforeAll
public static void setUp() {
- String version = "0.5.13";
+ String ollamaVersion = "0.6.1";
int internalPort = 11434;
int mappedPort = 11435;
- ollama = new OllamaContainer("ollama/ollama:" + version);
+ ollama = new OllamaContainer("ollama/ollama:" + ollamaVersion);
ollama.addExposedPort(internalPort);
List portBindings = new ArrayList<>();
portBindings.add(mappedPort + ":" + internalPort);
@@ -94,7 +94,8 @@ public class OllamaAPIIntegrationTest {
@Test
@Order(3)
public void testPullModelAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
- api.pullModel("all-minilm");
+ String embeddingModelMinilm = "all-minilm";
+ api.pullModel(embeddingModelMinilm);
List models = api.listModels();
assertNotNull(models, "Models should not be null");
assertFalse(models.isEmpty(), "Models list should contain elements");
@@ -247,7 +248,45 @@ public class OllamaAPIIntegrationTest {
assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent().contains("river"), "Response should be related to river");
}
+ @Test
+ @Order(10)
+ void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
+ String imageModel = "llava";
+ api.pullModel(imageModel);
+ OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
+ .build();
+ api.registerAnnotatedTools(new OllamaAPIIntegrationTest());
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ }
+ @Test
+ @Order(10)
+ void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
+ String imageModel = "moondream";
+ api.pullModel(imageModel);
+ OllamaChatRequestBuilder builder =
+ OllamaChatRequestBuilder.getInstance(imageModel);
+ OllamaChatRequest requestModel =
+ builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
+ List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
+
+ OllamaChatResult chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ builder.reset();
+
+ requestModel =
+ builder.withMessages(chatResult.getChatHistory())
+ .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
+
+ chatResult = api.chat(requestModel);
+ assertNotNull(chatResult);
+ assertNotNull(chatResult.getResponseModel());
+ }
@Test
@Order(11)
void testChatWithExplicitToolDefinition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
@@ -300,7 +339,7 @@ public class OllamaAPIIntegrationTest {
assertEquals(1, toolCalls.size());
OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
assertEquals("get-employee-details", function.getName());
- assertEquals(1, function.getArguments().size());
+ assert !function.getArguments().isEmpty();
Object employeeName = function.getArguments().get("employee-name");
assertNotNull(employeeName);
assertEquals("Rahul Kumar", employeeName);
@@ -463,20 +502,6 @@ public class OllamaAPIIntegrationTest {
assertEquals(sb.toString().trim(), chatResult.getResponseModel().getMessage().getContent().trim());
}
- @Test
- @Order(16)
- void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
- String imageModel = "llava";
- api.pullModel(imageModel);
-
- OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(imageModel);
- OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
- "https://t3.ftcdn.net/jpg/02/96/63/80/360_F_296638053_0gUVA4WVBKceGsIr7LNqRWSnkusi07dq.jpg")
- .build();
-
- OllamaChatResult chatResult = api.chat(requestModel);
- assertNotNull(chatResult);
- }
@Test
@Order(17)
@@ -517,30 +542,7 @@ public class OllamaAPIIntegrationTest {
}
}
- @Test
- @Order(19)
- void testChatWithImageFromFileWithHistoryRecognition() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
- String imageModel = "moondream";
- api.pullModel(imageModel);
- OllamaChatRequestBuilder builder =
- OllamaChatRequestBuilder.getInstance(imageModel);
- OllamaChatRequest requestModel =
- builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
- List.of(getImageFileFromClasspath("dog-on-a-boat.jpg"))).build();
- OllamaChatResult chatResult = api.chat(requestModel);
- assertNotNull(chatResult);
- assertNotNull(chatResult.getResponseModel());
- builder.reset();
-
- requestModel =
- builder.withMessages(chatResult.getChatHistory())
- .withMessage(OllamaChatMessageRole.USER, "What's the dogs breed?").build();
-
- chatResult = api.chat(requestModel);
- assertNotNull(chatResult);
- assertNotNull(chatResult.getResponseModel());
- }
@Test
@Order(20)
From bee09aa626b3dfc8863ef684c71d47006dc7f486 Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 18 Mar 2025 22:03:04 +0530
Subject: [PATCH 08/10] Updated integration tests
---
.../ollama4j/integrationtests/OllamaAPIIntegrationTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
index 12d60f4..9aa1579 100644
--- a/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
+++ b/src/test/java/io/github/ollama4j/integrationtests/OllamaAPIIntegrationTest.java
@@ -53,7 +53,7 @@ public class OllamaAPIIntegrationTest {
ollama.setPortBindings(portBindings);
ollama.start();
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
- api.setRequestTimeoutSeconds(60);
+ api.setRequestTimeoutSeconds(120);
api.setVerbose(true);
}
From bbafc95577aa13123903f87879406cea00c9e89e Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 18 Mar 2025 22:13:39 +0530
Subject: [PATCH 09/10] Updated GH workflow
---
.github/workflows/build-and-test-on-pr-open.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/build-and-test-on-pr-open.yml b/.github/workflows/build-and-test-on-pr-open.yml
index dbf54c7..e5e892d 100644
--- a/.github/workflows/build-and-test-on-pr-open.yml
+++ b/.github/workflows/build-and-test-on-pr-open.yml
@@ -5,9 +5,12 @@ name: Build and Test on PR Open
on:
pull_request:
- types: [ opened, reopened ]
+# types: [ opened, reopened ]
branches: [ "main" ]
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
+ cancel-in-progress: true
jobs:
build:
From 26bb2f9babd90b9941be56670965c0448ef1540f Mon Sep 17 00:00:00 2001
From: Amith Koujalgi
Date: Tue, 18 Mar 2025 22:15:58 +0530
Subject: [PATCH 10/10] Updated GH workflow
---
.github/workflows/build-and-test-on-pr-open.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/build-and-test-on-pr-open.yml b/.github/workflows/build-and-test-on-pr-open.yml
index e5e892d..d5ffbaf 100644
--- a/.github/workflows/build-and-test-on-pr-open.yml
+++ b/.github/workflows/build-and-test-on-pr-open.yml
@@ -1,7 +1,7 @@
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
-name: Build and Test on PR Open
+name: Run Tests
on:
pull_request:
@@ -13,7 +13,7 @@ concurrency:
cancel-in-progress: true
jobs:
- build:
+ run-tests:
runs-on: ubuntu-latest
permissions: