mirror of
https://github.com/amithkoujalgi/ollama4j.git
synced 2025-05-14 19:37:11 +02:00
Merge pull request #105 from ollama4j/integration-tests-refactor
Integration tests refactor
This commit is contained in:
commit
05eecdccaa
@ -1,16 +1,19 @@
|
|||||||
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
|
# 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
|
# 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:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened ]
|
# types: [ opened, reopened ]
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
run-tests:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
|
@ -21,7 +21,7 @@ repos:
|
|||||||
|
|
||||||
# for commit message formatting
|
# for commit message formatting
|
||||||
- repo: https://github.com/commitizen-tools/commitizen
|
- repo: https://github.com/commitizen-tools/commitizen
|
||||||
rev: v4.1.1
|
rev: v4.4.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: commitizen
|
- id: commitizen
|
||||||
stages: [commit-msg]
|
stages: [commit-msg]
|
||||||
|
8
Makefile
8
Makefile
@ -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:
|
build:
|
||||||
mvn -B clean install
|
mvn -B clean install
|
||||||
|
|
||||||
|
40
README.md
40
README.md
@ -191,33 +191,57 @@ dependencies {
|
|||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Find the full API specifications on the [website](https://ollama4j.github.io/ollama4j/).
|
> 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
|
```shell
|
||||||
make build
|
make build
|
||||||
```
|
```
|
||||||
|
|
||||||
Run unit tests:
|
#### Run unit tests
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
make unit-tests
|
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
|
```shell
|
||||||
make integration-tests
|
make integration-tests
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Releases
|
### Releases
|
||||||
|
|
||||||
Newer artifacts are published via GitHub Actions CI workflow when a new release is created from `main` branch.
|
Newer artifacts are published via GitHub Actions CI workflow when a new release is created from `main` branch.
|
||||||
|
|
||||||
## Examples
|
## 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!
|
## ⭐ 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) |
|
| 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) |
|
| 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) |
|
| 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/) |
|
| 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
|
## Traction
|
||||||
@ -304,7 +328,7 @@ project.
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### Appreciate my work?
|
### Appreciate the work?
|
||||||
|
|
||||||
<p align="center">
|
<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>
|
<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>
|
||||||
|
@ -2,49 +2,59 @@ package io.github.ollama4j.integrationtests;
|
|||||||
|
|
||||||
import io.github.ollama4j.OllamaAPI;
|
import io.github.ollama4j.OllamaAPI;
|
||||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||||
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
|
import io.github.ollama4j.models.chat.*;
|
||||||
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.embeddings.OllamaEmbedResponseModel;
|
import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;
|
||||||
import io.github.ollama4j.models.response.LibraryModel;
|
import io.github.ollama4j.models.response.LibraryModel;
|
||||||
import io.github.ollama4j.models.response.Model;
|
import io.github.ollama4j.models.response.Model;
|
||||||
import io.github.ollama4j.models.response.ModelDetail;
|
import io.github.ollama4j.models.response.ModelDetail;
|
||||||
import io.github.ollama4j.models.response.OllamaResult;
|
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 io.github.ollama4j.utils.OptionsBuilder;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||||
import org.junit.jupiter.api.Order;
|
import org.junit.jupiter.api.Order;
|
||||||
import org.junit.jupiter.api.Test;
|
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 org.testcontainers.ollama.OllamaContainer;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@OllamaToolService(providers = {AnnotatedTool.class})
|
||||||
|
@TestMethodOrder(OrderAnnotation.class)
|
||||||
|
|
||||||
@SuppressWarnings("HttpUrlsUsage")
|
@SuppressWarnings("HttpUrlsUsage")
|
||||||
public class OllamaAPIIntegrationTest {
|
public class OllamaAPIIntegrationTest {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(OllamaAPIIntegrationTest.class);
|
||||||
|
|
||||||
private static OllamaContainer ollama;
|
private static OllamaContainer ollama;
|
||||||
private static OllamaAPI api;
|
private static OllamaAPI api;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void setUp() {
|
public static void setUp() {
|
||||||
String version = "0.5.13";
|
String ollamaVersion = "0.6.1";
|
||||||
int internalPort = 11434;
|
int internalPort = 11434;
|
||||||
int mappedPort = 11435;
|
int mappedPort = 11435;
|
||||||
ollama = new OllamaContainer("ollama/ollama:" + version);
|
ollama = new OllamaContainer("ollama/ollama:" + ollamaVersion);
|
||||||
ollama.addExposedPort(internalPort);
|
ollama.addExposedPort(internalPort);
|
||||||
List<String> portBindings = new ArrayList<>();
|
List<String> portBindings = new ArrayList<>();
|
||||||
portBindings.add(mappedPort + ":" + internalPort);
|
portBindings.add(mappedPort + ":" + internalPort);
|
||||||
ollama.setPortBindings(portBindings);
|
ollama.setPortBindings(portBindings);
|
||||||
ollama.start();
|
ollama.start();
|
||||||
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
|
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
|
||||||
api.setRequestTimeoutSeconds(60);
|
api.setRequestTimeoutSeconds(120);
|
||||||
|
api.setVerbose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -84,7 +94,8 @@ public class OllamaAPIIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Order(3)
|
@Order(3)
|
||||||
public void testPullModelAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
public void testPullModelAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||||
api.pullModel("all-minilm");
|
String embeddingModelMinilm = "all-minilm";
|
||||||
|
api.pullModel(embeddingModelMinilm);
|
||||||
List<Model> models = api.listModels();
|
List<Model> models = api.listModels();
|
||||||
assertNotNull(models, "Models should not be null");
|
assertNotNull(models, "Models should not be null");
|
||||||
assertFalse(models.isEmpty(), "Models list should contain elements");
|
assertFalse(models.isEmpty(), "Models list should contain elements");
|
||||||
@ -102,7 +113,7 @@ public class OllamaAPIIntegrationTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Order(5)
|
@Order(5)
|
||||||
public void testGenerateEmbeddings() throws Exception {
|
public void testEmbeddings() throws Exception {
|
||||||
String embeddingModelMinilm = "all-minilm";
|
String embeddingModelMinilm = "all-minilm";
|
||||||
api.pullModel(embeddingModelMinilm);
|
api.pullModel(embeddingModelMinilm);
|
||||||
OllamaEmbedResponseModel embeddings = api.embed(embeddingModelMinilm, Arrays.asList("Why is the sky blue?", "Why is the grass green?"));
|
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?",
|
"What is the capital of France? And what's France's connection with Mona Lisa?",
|
||||||
false,
|
false,
|
||||||
new OptionsBuilder().build(), (s) -> {
|
new OptionsBuilder().build(), (s) -> {
|
||||||
System.out.println(s);
|
LOG.info(s);
|
||||||
String substring = s.substring(sb.toString().length(), s.length());
|
String substring = s.substring(sb.toString().length(), s.length());
|
||||||
System.out.println(substring);
|
LOG.info(substring);
|
||||||
sb.append(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().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");
|
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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
@ -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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//}
|
|
Loading…
x
Reference in New Issue
Block a user