Merge pull request #105 from ollama4j/integration-tests-refactor

Integration tests refactor
This commit is contained in:
Amith Koujalgi 2025-03-18 22:17:33 +05:30 committed by GitHub
commit 05eecdccaa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 427 additions and 648 deletions

View File

@ -1,16 +1,19 @@
# 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:
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:
run-tests:
runs-on: ubuntu-latest
permissions:

View File

@ -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]

View File

@ -1,3 +1,11 @@
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
build:
mvn -B clean install

View File

@ -191,33 +191,57 @@ 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
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
```
#### 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 +260,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
@ -304,7 +328,7 @@ project.
</a>
</p>
### Appreciate my work?
### Appreciate the work?
<p align="center">
<a href="https://www.buymeacoffee.com/amithkoujalgi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>

View File

@ -407,3 +407,8 @@
</profiles>
</project>

View File

@ -2,49 +2,59 @@ 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;
@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<String> portBindings = new ArrayList<>();
portBindings.add(mappedPort + ":" + internalPort);
ollama.setPortBindings(portBindings);
ollama.start();
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
api.setRequestTimeoutSeconds(60);
api.setRequestTimeoutSeconds(120);
api.setVerbose(true);
}
@Test
@ -84,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<Model> models = api.listModels();
assertNotNull(models, "Models should not be null");
assertFalse(models.isEmpty(), "Models list should contain elements");
@ -102,7 +113,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 +147,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 +247,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(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 {
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<OllamaChatToolCalls> toolCalls = chatResult.getChatHistory().get(1).getToolCalls();
assertEquals(1, toolCalls.size());
OllamaToolCallsFunction function = toolCalls.get(0).getFunction();
assertEquals("get-employee-details", function.getName());
assert !function.getArguments().isEmpty();
Object employeeName = function.getArguments().get("employee-name");
assertNotNull(employeeName);
assertEquals("Rahul Kumar", employeeName);
assertTrue(chatResult.getChatHistory().size() > 2);
List<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<String, Object> 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(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(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);
// }
// }
//}

View File

@ -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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<OllamaChatToolCalls> 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<Double> 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<String, Object> 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);
// }
// }
//
//
//}