mirror of
https://github.com/amithkoujalgi/ollama4j.git
synced 2025-05-15 03:47:13 +02:00
Support for structured output
Added support for structured output
This commit is contained in:
parent
e62a7511db
commit
b9b18271a1
8
Makefile
8
Makefile
@ -7,13 +7,19 @@ dev:
|
||||
pre-commit install --install-hooks
|
||||
|
||||
build:
|
||||
mvn -B clean install -Dgpg.skip=true
|
||||
|
||||
full-build:
|
||||
mvn -B clean install
|
||||
|
||||
unit-tests:
|
||||
mvn clean test -Punit-tests
|
||||
|
||||
integration-tests:
|
||||
mvn clean verify -Pintegration-tests
|
||||
export USE_EXTERNAL_OLLAMA_HOST=false && mvn clean verify -Pintegration-tests
|
||||
|
||||
integration-tests-local:
|
||||
export USE_EXTERNAL_OLLAMA_HOST=true && export OLLAMA_HOST=http://localhost:11434 && mvn clean verify -Pintegration-tests -Dgpg.skip=true
|
||||
|
||||
doxygen:
|
||||
doxygen Doxyfile
|
||||
|
@ -209,6 +209,9 @@ pip install pre-commit
|
||||
|
||||
#### Setup dev environment
|
||||
|
||||
> **Note**
|
||||
> If you're on Windows, install [Chocolatey Package Manager for Windows](https://chocolatey.org/install) and then install `make` by running `choco install make`. Just a little tip - run the command with administrator privileges if installation faiils.
|
||||
|
||||
```shell
|
||||
make dev
|
||||
```
|
||||
|
@ -13,7 +13,7 @@ with [extra parameters](https://github.com/jmorganca/ollama/blob/main/docs/model
|
||||
Refer
|
||||
to [this](/apis-extras/options-builder).
|
||||
|
||||
## Try asking a question about the model.
|
||||
## Try asking a question about the model
|
||||
|
||||
```java
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
@ -87,7 +87,7 @@ You will get a response similar to:
|
||||
> The capital of France is Paris.
|
||||
> Full response: The capital of France is Paris.
|
||||
|
||||
## Try asking a question from general topics.
|
||||
## Try asking a question from general topics
|
||||
|
||||
```java
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
@ -135,7 +135,7 @@ You'd then get a response from the model:
|
||||
> semi-finals. The tournament was
|
||||
> won by the England cricket team, who defeated New Zealand in the final.
|
||||
|
||||
## Try asking for a Database query for your data schema.
|
||||
## Try asking for a Database query for your data schema
|
||||
|
||||
```java
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
@ -161,6 +161,7 @@ public class Main {
|
||||
|
||||
```
|
||||
|
||||
|
||||
_Note: Here I've used
|
||||
a [sample prompt](https://github.com/ollama4j/ollama4j/blob/main/src/main/resources/sample-db-prompt-template.txt)
|
||||
containing a database schema from within this library for demonstration purposes._
|
||||
@ -173,3 +174,124 @@ FROM sales
|
||||
JOIN customers ON sales.customer_id = customers.customer_id
|
||||
GROUP BY customers.name;
|
||||
```
|
||||
|
||||
|
||||
## Generate structured output
|
||||
|
||||
### With response as a `Map`
|
||||
|
||||
```java
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.utils.Utilities;
|
||||
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.response.OllamaResult;
|
||||
import io.github.ollama4j.types.OllamaModelType;
|
||||
|
||||
public class StructuredOutput {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String host = "http://localhost:11434/";
|
||||
|
||||
OllamaAPI api = new OllamaAPI(host);
|
||||
|
||||
String chatModel = "qwen2.5:0.5b";
|
||||
api.pullModel(chatModel);
|
||||
|
||||
String prompt = "Ollama is 22 years old and is busy saving the world. Respond using JSON";
|
||||
Map<String, Object> format = new HashMap<>();
|
||||
format.put("type", "object");
|
||||
format.put("properties", new HashMap<String, Object>() {
|
||||
{
|
||||
put("age", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "integer");
|
||||
}
|
||||
});
|
||||
put("available", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "boolean");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
format.put("required", Arrays.asList("age", "available"));
|
||||
|
||||
OllamaResult result = api.generate(chatModel, prompt, format);
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With response mapped to specified class type
|
||||
|
||||
```java
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.utils.Utilities;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
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.response.OllamaResult;
|
||||
import io.github.ollama4j.types.OllamaModelType;
|
||||
|
||||
public class StructuredOutput {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String host = Utilities.getFromConfig("host");
|
||||
|
||||
OllamaAPI api = new OllamaAPI(host);
|
||||
|
||||
int age = 28;
|
||||
boolean available = false;
|
||||
|
||||
String prompt = "Batman is " + age + " years old and is " + (available ? "available" : "not available")
|
||||
+ " because he is busy saving Gotham City. Respond using JSON";
|
||||
|
||||
Map<String, Object> format = new HashMap<>();
|
||||
format.put("type", "object");
|
||||
format.put("properties", new HashMap<String, Object>() {
|
||||
{
|
||||
put("age", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "integer");
|
||||
}
|
||||
});
|
||||
put("available", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "boolean");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
format.put("required", Arrays.asList("age", "available"));
|
||||
|
||||
OllamaResult result = api.generate(CHAT_MODEL_QWEN_SMALL, prompt, format);
|
||||
|
||||
Person person = result.as(Person.class);
|
||||
System.out.println(person.getAge());
|
||||
System.out.println(person.getAvailable());
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class Person {
|
||||
private int age;
|
||||
private boolean available;
|
||||
}
|
||||
```
|
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,22 @@
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** The type Ollama result. */
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaResult {
|
||||
/**
|
||||
* -- GETTER --
|
||||
@ -44,9 +51,68 @@ public class OllamaResult {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
Map<String, Object> responseMap = new HashMap<>();
|
||||
responseMap.put("response", this.response);
|
||||
responseMap.put("httpStatusCode", this.httpStatusCode);
|
||||
responseMap.put("responseTime", this.responseTime);
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseMap);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the structured response if the response is a JSON object.
|
||||
*
|
||||
* @return Map - structured response
|
||||
* @throws IllegalArgumentException if the response is not a valid JSON object
|
||||
*/
|
||||
public Map<String, Object> getStructuredResponse() {
|
||||
String responseStr = this.getResponse();
|
||||
if (responseStr == null || responseStr.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Response is empty or null");
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
throw new IllegalArgumentException("Response is not a valid JSON object");
|
||||
}
|
||||
|
||||
Map<String, Object> response = getObjectMapper().readValue(responseStr,
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
return response;
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the structured response mapped to a specific class type.
|
||||
*
|
||||
* @param <T> The type of class to map the response to
|
||||
* @param clazz The class to map the response to
|
||||
* @return An instance of the specified class with the response data
|
||||
* @throws IllegalArgumentException if the response is not a valid JSON or is empty
|
||||
* @throws RuntimeException if there is an error mapping the response
|
||||
*/
|
||||
public <T> T as(Class<T> clazz) {
|
||||
String responseStr = this.getResponse();
|
||||
if (responseStr == null || responseStr.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Response is empty or null");
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
throw new IllegalArgumentException("Response is not a valid JSON object");
|
||||
}
|
||||
return getObjectMapper().readValue(responseStr, clazz);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaStructuredResult {
|
||||
private String response;
|
||||
|
||||
private int httpStatusCode;
|
||||
|
||||
private long responseTime = 0;
|
||||
|
||||
private String model;
|
||||
|
||||
public OllamaStructuredResult(String response, long responseTime, int httpStatusCode) {
|
||||
this.response = response;
|
||||
this.responseTime = responseTime;
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the structured response if the response is a JSON object.
|
||||
*
|
||||
* @return Map - structured response
|
||||
*/
|
||||
public Map<String, Object> getStructuredResponse() {
|
||||
try {
|
||||
Map<String, Object> response = getObjectMapper().readValue(this.getResponse(),
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
return response;
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the structured response mapped to a specific class type.
|
||||
*
|
||||
* @param <T> The type of class to map the response to
|
||||
* @param clazz The class to map the response to
|
||||
* @return An instance of the specified class with the response data
|
||||
* @throws RuntimeException if there is an error mapping the response
|
||||
*/
|
||||
public <T> T getStructuredResponse(Class<T> clazz) {
|
||||
try {
|
||||
return getObjectMapper().readValue(this.getResponse(), clazz);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,9 @@ 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.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
import org.junit.jupiter.api.Order;
|
||||
@ -34,15 +37,32 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
@OllamaToolService(providers = { AnnotatedTool.class })
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
|
||||
@SuppressWarnings("HttpUrlsUsage")
|
||||
@SuppressWarnings({ "HttpUrlsUsage", "SpellCheckingInspection" })
|
||||
public class OllamaAPIIntegrationTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(OllamaAPIIntegrationTest.class);
|
||||
|
||||
private static OllamaContainer ollama;
|
||||
private static OllamaAPI api;
|
||||
|
||||
private static final String EMBEDDING_MODEL_MINILM = "all-minilm";
|
||||
private static final String CHAT_MODEL_QWEN_SMALL = "qwen2.5:0.5b";
|
||||
private static final String CHAT_MODEL_INSTRUCT = "qwen2.5:0.5b-instruct";
|
||||
private static final String CHAT_MODEL_SYSTEM_PROMPT = "llama3.2:1b";
|
||||
private static final String CHAT_MODEL_LLAMA3 = "llama3";
|
||||
private static final String IMAGE_MODEL_LLAVA = "llava";
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
try {
|
||||
boolean useExternalOllamaHost = Boolean.parseBoolean(System.getenv("USE_EXTERNAL_OLLAMA_HOST"));
|
||||
String ollamaHost = System.getenv("OLLAMA_HOST");
|
||||
if (useExternalOllamaHost) {
|
||||
api = new OllamaAPI(ollamaHost);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"USE_EXTERNAL_OLLAMA_HOST is not set so, we will be using Testcontainers Ollama host for the tests now. If you would like to use an external host, please set the env var to USE_EXTERNAL_OLLAMA_HOST=true and set the env var OLLAMA_HOST=http://localhost:11435 or a different host/port.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
String ollamaVersion = "0.6.1";
|
||||
int internalPort = 11434;
|
||||
int mappedPort = 11435;
|
||||
@ -53,8 +73,10 @@ public class OllamaAPIIntegrationTest {
|
||||
ollama.setPortBindings(portBindings);
|
||||
ollama.start();
|
||||
api = new OllamaAPI("http://" + ollama.getHost() + ":" + ollama.getMappedPort(internalPort));
|
||||
}
|
||||
api.setRequestTimeoutSeconds(120);
|
||||
api.setVerbose(true);
|
||||
api.setNumberOfRetriesForModelPull(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -67,25 +89,30 @@ public class OllamaAPIIntegrationTest {
|
||||
@Test
|
||||
@Order(1)
|
||||
public void testVersionAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||
String expectedVersion = ollama.getDockerImageName().split(":")[1];
|
||||
// String expectedVersion = ollama.getDockerImageName().split(":")[1];
|
||||
String actualVersion = api.getVersion();
|
||||
assertEquals(expectedVersion, actualVersion, "Version should match the Docker image version");
|
||||
assertNotNull(actualVersion);
|
||||
// assertEquals(expectedVersion, actualVersion, "Version should match the Docker
|
||||
// image version");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void testListModelsAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||
public void testListModelsAPI()
|
||||
throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||
api.pullModel(EMBEDDING_MODEL_MINILM);
|
||||
// Fetch the list of models
|
||||
List<Model> models = api.listModels();
|
||||
// Assert that the models list is not null
|
||||
assertNotNull(models, "Models should not be null");
|
||||
// Assert that models list is either empty or contains more than 0 models
|
||||
assertTrue(models.size() >= 0, "Models list should be empty or contain elements");
|
||||
assertFalse(models.isEmpty(), "Models list should not be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
void testListModelsFromLibrary() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
void testListModelsFromLibrary()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
List<LibraryModel> models = api.listModelsFromLibrary();
|
||||
assertNotNull(models);
|
||||
assertFalse(models.isEmpty());
|
||||
@ -93,9 +120,9 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void testPullModelAPI() throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||
String embeddingModelMinilm = "all-minilm";
|
||||
api.pullModel(embeddingModelMinilm);
|
||||
public void testPullModelAPI()
|
||||
throws URISyntaxException, IOException, OllamaBaseException, InterruptedException {
|
||||
api.pullModel(EMBEDDING_MODEL_MINILM);
|
||||
List<Model> models = api.listModels();
|
||||
assertNotNull(models, "Models should not be null");
|
||||
assertFalse(models.isEmpty(), "Models list should contain elements");
|
||||
@ -104,33 +131,75 @@ public class OllamaAPIIntegrationTest {
|
||||
@Test
|
||||
@Order(4)
|
||||
void testListModelDetails() throws IOException, OllamaBaseException, URISyntaxException, InterruptedException {
|
||||
String embeddingModelMinilm = "all-minilm";
|
||||
api.pullModel(embeddingModelMinilm);
|
||||
ModelDetail modelDetails = api.getModelDetails("all-minilm");
|
||||
api.pullModel(EMBEDDING_MODEL_MINILM);
|
||||
ModelDetail modelDetails = api.getModelDetails(EMBEDDING_MODEL_MINILM);
|
||||
assertNotNull(modelDetails);
|
||||
assertTrue(modelDetails.getModelFile().contains(embeddingModelMinilm));
|
||||
assertTrue(modelDetails.getModelFile().contains(EMBEDDING_MODEL_MINILM));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
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?"));
|
||||
api.pullModel(EMBEDDING_MODEL_MINILM);
|
||||
OllamaEmbedResponseModel embeddings = api.embed(EMBEDDING_MODEL_MINILM,
|
||||
Arrays.asList("Why is the sky blue?", "Why is the grass green?"));
|
||||
assertNotNull(embeddings, "Embeddings should not be null");
|
||||
assertFalse(embeddings.getEmbeddings().isEmpty(), "Embeddings should not be empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
void testAskModelWithDefaultOptions() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
String chatModel = "qwen2.5:0.5b";
|
||||
api.pullModel(chatModel);
|
||||
OllamaResult result =
|
||||
api.generate(
|
||||
chatModel,
|
||||
"What is the capital of France? And what's France's connection with Mona Lisa?",
|
||||
false,
|
||||
void testAskModelWithStructuredOutput()
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
api.pullModel(CHAT_MODEL_QWEN_SMALL);
|
||||
|
||||
int age = 28;
|
||||
boolean available = false;
|
||||
|
||||
String prompt = "Batman is " + age + " years old and is " + (available ? "available" : "not available")
|
||||
+ " because he is busy saving Gotham City. Respond using JSON";
|
||||
|
||||
Map<String, Object> format = new HashMap<>();
|
||||
format.put("type", "object");
|
||||
format.put("properties", new HashMap<String, Object>() {
|
||||
{
|
||||
put("age", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "integer");
|
||||
}
|
||||
});
|
||||
put("available", new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "boolean");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
format.put("required", Arrays.asList("age", "available"));
|
||||
|
||||
OllamaResult result = api.generate(CHAT_MODEL_QWEN_SMALL, prompt, format);
|
||||
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getResponse());
|
||||
assertFalse(result.getResponse().isEmpty());
|
||||
|
||||
assertEquals(result.getStructuredResponse().get("age").toString(),
|
||||
result.getStructuredResponse().get("age").toString());
|
||||
assertEquals(result.getStructuredResponse().get("available").toString(),
|
||||
result.getStructuredResponse().get("available").toString());
|
||||
|
||||
Person person = result.as(Person.class);
|
||||
assertEquals(person.getAge(), age);
|
||||
assertEquals(person.isAvailable(), available);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
void testAskModelWithDefaultOptions()
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
api.pullModel(CHAT_MODEL_QWEN_SMALL);
|
||||
OllamaResult result = api.generate(CHAT_MODEL_QWEN_SMALL,
|
||||
"What is the capital of France? And what's France's connection with Mona Lisa?", false,
|
||||
new OptionsBuilder().build());
|
||||
assertNotNull(result);
|
||||
assertNotNull(result.getResponse());
|
||||
@ -139,13 +208,12 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
void testAskModelWithDefaultOptionsStreamed() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "qwen2.5:0.5b";
|
||||
api.pullModel(chatModel);
|
||||
void testAskModelWithDefaultOptionsStreamed()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_QWEN_SMALL);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
OllamaResult result = api.generate(chatModel,
|
||||
"What is the capital of France? And what's France's connection with Mona Lisa?",
|
||||
false,
|
||||
OllamaResult result = api.generate(CHAT_MODEL_QWEN_SMALL,
|
||||
"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());
|
||||
@ -161,12 +229,13 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
void testAskModelWithOptions() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "qwen2.5:0.5b-instruct";
|
||||
api.pullModel(chatModel);
|
||||
void testAskModelWithOptions()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_INSTRUCT);
|
||||
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM, "You are a helpful assistant who can generate random person's first and last names in the format [First name, Last name].")
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_INSTRUCT);
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM,
|
||||
"You are a helpful assistant who can generate random person's first and last names in the format [First name, Last name].")
|
||||
.build();
|
||||
requestModel = builder.withMessages(requestModel.getMessages())
|
||||
.withMessage(OllamaChatMessageRole.USER, "Give me a cool name")
|
||||
@ -180,16 +249,14 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
void testChatWithSystemPrompt() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "llama3.2:1b";
|
||||
api.pullModel(chatModel);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
void testChatWithSystemPrompt()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.SYSTEM,
|
||||
"You are a silent bot that only says 'Shush'. Do not say anything else under any circumstances!")
|
||||
.withMessage(OllamaChatMessageRole.USER,
|
||||
"What's something that's brown and sticky?")
|
||||
.withOptions(new OptionsBuilder().setTemperature(0.8f).build())
|
||||
.build();
|
||||
.withMessage(OllamaChatMessageRole.USER, "What's something that's brown and sticky?")
|
||||
.withOptions(new OptionsBuilder().setTemperature(0.8f).build()).build();
|
||||
|
||||
OllamaChatResult chatResult = api.chat(requestModel);
|
||||
assertNotNull(chatResult);
|
||||
@ -203,40 +270,34 @@ public class OllamaAPIIntegrationTest {
|
||||
@Test
|
||||
@Order(10)
|
||||
public void testChat() throws Exception {
|
||||
String chatModel = "llama3";
|
||||
api.pullModel(chatModel);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
api.pullModel(CHAT_MODEL_LLAMA3);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_LLAMA3);
|
||||
|
||||
// Create the initial user question
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What is 1+1? Answer only in numbers.")
|
||||
OllamaChatRequest requestModel = builder
|
||||
.withMessage(OllamaChatMessageRole.USER, "What is 1+1? Answer only in numbers.")
|
||||
.build();
|
||||
|
||||
// Start conversation with model
|
||||
OllamaChatResult chatResult = api.chat(requestModel);
|
||||
|
||||
assertTrue(
|
||||
chatResult.getChatHistory().stream()
|
||||
.anyMatch(chat -> chat.getContent().contains("2")),
|
||||
"Expected chat history to contain '2'"
|
||||
);
|
||||
assertTrue(chatResult.getChatHistory().stream().anyMatch(chat -> chat.getContent().contains("2")),
|
||||
"Expected chat history to contain '2'");
|
||||
|
||||
// Create the next user question: second largest city
|
||||
requestModel = builder.withMessages(chatResult.getChatHistory())
|
||||
.withMessage(OllamaChatMessageRole.USER, "And what is its squared value?")
|
||||
.build();
|
||||
.withMessage(OllamaChatMessageRole.USER, "And what is its squared value?").build();
|
||||
|
||||
// Continue conversation with model
|
||||
chatResult = api.chat(requestModel);
|
||||
|
||||
assertTrue(
|
||||
chatResult.getChatHistory().stream()
|
||||
.anyMatch(chat -> chat.getContent().contains("4")),
|
||||
"Expected chat history to contain '4'"
|
||||
);
|
||||
assertTrue(chatResult.getChatHistory().stream().anyMatch(chat -> chat.getContent().contains("4")),
|
||||
"Expected chat history to contain '4'");
|
||||
|
||||
// Create the next user question: the third question
|
||||
requestModel = builder.withMessages(chatResult.getChatHistory())
|
||||
.withMessage(OllamaChatMessageRole.USER, "What is the largest value between 2, 4 and 6?")
|
||||
.withMessage(OllamaChatMessageRole.USER,
|
||||
"What is the largest value between 2, 4 and 6?")
|
||||
.build();
|
||||
|
||||
// Continue conversation with the model for the third question
|
||||
@ -244,18 +305,23 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
// verify the result
|
||||
assertNotNull(chatResult, "Chat result should not be null");
|
||||
assertTrue(chatResult.getChatHistory().size() > 2, "Chat history should contain more than two messages");
|
||||
assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent().contains("6"), "Response should contain '6'");
|
||||
assertTrue(chatResult.getChatHistory().size() > 2,
|
||||
"Chat history should contain more than two messages");
|
||||
assertTrue(chatResult.getChatHistory().get(chatResult.getChatHistory().size() - 1).getContent()
|
||||
.contains("6"),
|
||||
"Response should contain '6'");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
void testChatWithImageFromURL() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
String imageModel = "llava";
|
||||
api.pullModel(imageModel);
|
||||
void testChatWithImageFromURL()
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
api.pullModel(IMAGE_MODEL_LLAVA);
|
||||
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(imageModel);
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What's in the picture?", Collections.emptyList(),
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(IMAGE_MODEL_LLAVA);
|
||||
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());
|
||||
@ -263,65 +329,84 @@ public class 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();
|
||||
void testChatWithImageFromFileWithHistoryRecognition()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(IMAGE_MODEL_LLAVA);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(IMAGE_MODEL_LLAVA);
|
||||
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())
|
||||
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);
|
||||
void testChatWithExplicitToolDefinition()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
|
||||
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()
|
||||
.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()
|
||||
)
|
||||
.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()
|
||||
)
|
||||
.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();
|
||||
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);
|
||||
|
||||
@ -334,7 +419,8 @@ public class OllamaAPIIntegrationTest {
|
||||
assertNotNull(chatResult);
|
||||
assertNotNull(chatResult.getResponseModel());
|
||||
assertNotNull(chatResult.getResponseModel().getMessage());
|
||||
assertEquals(OllamaChatMessageRole.ASSISTANT.getRoleName(), chatResult.getResponseModel().getMessage().getRole().getRoleName());
|
||||
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();
|
||||
@ -350,24 +436,22 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(12)
|
||||
void testChatWithAnnotatedToolsAndSingleParam() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
String chatModel = "llama3.2:1b";
|
||||
api.pullModel(chatModel);
|
||||
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
void testChatWithAnnotatedToolsAndSingleParam()
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
|
||||
api.registerAnnotatedTools();
|
||||
|
||||
OllamaChatRequest requestModel = builder
|
||||
.withMessage(OllamaChatMessageRole.USER,
|
||||
"Compute the most important constant in the world using 5 digits")
|
||||
.build();
|
||||
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());
|
||||
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();
|
||||
@ -383,24 +467,25 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(13)
|
||||
void testChatWithAnnotatedToolsAndMultipleParams() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "llama3.2:1b";
|
||||
api.pullModel(chatModel);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
void testChatWithAnnotatedToolsAndMultipleParams()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
|
||||
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")
|
||||
"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());
|
||||
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();
|
||||
@ -419,41 +504,59 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(14)
|
||||
void testChatWithToolsAndStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "llama3.2:1b";
|
||||
api.pullModel(chatModel);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
void testChatWithToolsAndStream()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
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()
|
||||
.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()
|
||||
)
|
||||
.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()
|
||||
)
|
||||
.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"));
|
||||
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();
|
||||
}).build();
|
||||
|
||||
api.registerTool(databaseQueryToolSpecification);
|
||||
|
||||
@ -480,9 +583,8 @@ public class OllamaAPIIntegrationTest {
|
||||
@Test
|
||||
@Order(15)
|
||||
void testChatWithStream() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String chatModel = "llama3.2:1b";
|
||||
api.pullModel(chatModel);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||
api.pullModel(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(CHAT_MODEL_SYSTEM_PROMPT);
|
||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER,
|
||||
"What is the capital of France? And what's France's connection with Mona Lisa?")
|
||||
.build();
|
||||
@ -502,19 +604,14 @@ public class OllamaAPIIntegrationTest {
|
||||
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);
|
||||
void testAskModelWithOptionsAndImageURLs()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(IMAGE_MODEL_LLAVA);
|
||||
|
||||
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"),
|
||||
OllamaResult result = api.generateWithImageURLs(IMAGE_MODEL_LLAVA, "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());
|
||||
@ -523,15 +620,12 @@ public class OllamaAPIIntegrationTest {
|
||||
|
||||
@Test
|
||||
@Order(18)
|
||||
void testAskModelWithOptionsAndImageFiles() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String imageModel = "llava";
|
||||
api.pullModel(imageModel);
|
||||
void testAskModelWithOptionsAndImageFiles()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(IMAGE_MODEL_LLAVA);
|
||||
File imageFile = getImageFileFromClasspath("dog-on-a-boat.jpg");
|
||||
try {
|
||||
OllamaResult result =
|
||||
api.generateWithImageFiles(
|
||||
imageModel,
|
||||
"What is in this image?",
|
||||
OllamaResult result = api.generateWithImageFiles(IMAGE_MODEL_LLAVA, "What is in this image?",
|
||||
List.of(imageFile),
|
||||
new OptionsBuilder().build());
|
||||
assertNotNull(result);
|
||||
@ -542,20 +636,19 @@ public class OllamaAPIIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
@Order(20)
|
||||
void testAskModelWithOptionsAndImageFilesStreamed() throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String imageModel = "llava";
|
||||
api.pullModel(imageModel);
|
||||
void testAskModelWithOptionsAndImageFilesStreamed()
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
api.pullModel(IMAGE_MODEL_LLAVA);
|
||||
|
||||
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) -> {
|
||||
OllamaResult result = api.generateWithImageFiles(IMAGE_MODEL_LLAVA, "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);
|
||||
@ -572,29 +665,11 @@ public class OllamaAPIIntegrationTest {
|
||||
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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
class Person {
|
||||
private int age;
|
||||
private boolean available;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user