mirror of
https://github.com/amithkoujalgi/ollama4j.git
synced 2025-11-02 09:30:41 +01:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9db51a71e | ||
|
|
681a692ca9 | ||
|
|
9a6065fdb3 | ||
|
|
e245d9633f | ||
|
|
590364dd53 | ||
|
|
bb4e7477bd | ||
|
|
c33c1c8315 | ||
|
|
05eecdccaa | ||
|
|
26bb2f9bab | ||
|
|
bbafc95577 | ||
|
|
bee09aa626 | ||
|
|
8aa6e3b066 | ||
|
|
d40912c638 | ||
|
|
ba0444194f | ||
|
|
ac3f505aa6 | ||
|
|
7e5ca53fda | ||
|
|
2b0238b9e8 | ||
|
|
469a0fe491 | ||
|
|
983a3617f0 | ||
|
|
b638b981c9 | ||
|
|
fe5078891f | ||
|
|
44b4de9ed9 | ||
|
|
854c0b4acf | ||
|
|
18c5d06a6c | ||
|
|
22b403d0b0 | ||
|
|
ee0493eb57 | ||
|
|
f966b4b74e | ||
|
|
1dadbacd2c | ||
|
|
714c16c216 | ||
|
|
cf2c510b23 | ||
|
|
a0bcc47b2e | ||
|
|
57ecbc2572 | ||
|
|
99beb3e6d0 | ||
|
|
7756eed9a0 | ||
|
|
b795117f0a | ||
|
|
138497b30f | ||
|
|
3a792090e2 |
@@ -1,21 +1,20 @@
|
|||||||
# This workflow will build a package using Maven and then publish it to GitHub packages when a release is created
|
name: Run Tests
|
||||||
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path
|
|
||||||
|
|
||||||
name: Build on PR Create
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [ opened, reopened ]
|
# types: [opened, reopened, synchronize, edited]
|
||||||
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:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -30,5 +29,8 @@ jobs:
|
|||||||
- name: Build with Maven
|
- name: Build with Maven
|
||||||
run: mvn --file pom.xml -U clean package
|
run: mvn --file pom.xml -U clean package
|
||||||
|
|
||||||
- name: Run Tests
|
- name: Run unit tests
|
||||||
run: mvn --file pom.xml -U clean test -Punit-tests
|
run: mvn --file pom.xml -U clean test -Punit-tests
|
||||||
|
|
||||||
|
- name: Run integration tests
|
||||||
|
run: mvn --file pom.xml -U clean verify -Pintegration-tests
|
||||||
7
.github/workflows/run-tests.yml
vendored
7
.github/workflows/run-tests.yml
vendored
@@ -1,10 +1,9 @@
|
|||||||
name: Run Unit and Integration Tests
|
name: Run Unit and Integration Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
# push:
|
||||||
branches:
|
# branches:
|
||||||
- main
|
# - main
|
||||||
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
branch:
|
branch:
|
||||||
|
|||||||
38
.pre-commit-config.yaml
Normal file
38
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
repos:
|
||||||
|
|
||||||
|
# pre-commit hooks
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: "v5.0.0"
|
||||||
|
hooks:
|
||||||
|
- id: no-commit-to-branch
|
||||||
|
args: ['--branch', 'main']
|
||||||
|
- id: check-merge-conflict
|
||||||
|
- id: check-added-large-files
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-xml
|
||||||
|
- id: check-json
|
||||||
|
- id: pretty-format-json
|
||||||
|
args: ['--no-sort-keys', '--autofix', '--indent=4']
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
exclude: \.json$
|
||||||
|
files: \.java$|\.xml$
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: mixed-line-ending
|
||||||
|
|
||||||
|
# for commit message formatting
|
||||||
|
- repo: https://github.com/commitizen-tools/commitizen
|
||||||
|
rev: v4.4.1
|
||||||
|
hooks:
|
||||||
|
- id: commitizen
|
||||||
|
stages: [commit-msg]
|
||||||
|
|
||||||
|
# # for java code quality
|
||||||
|
# - repo: https://github.com/gherynos/pre-commit-java
|
||||||
|
# rev: v0.6.10
|
||||||
|
# hooks:
|
||||||
|
# - id: pmd
|
||||||
|
# exclude: /test/
|
||||||
|
# - id: cpd
|
||||||
|
# exclude: /test/
|
||||||
|
# - id: checkstyle
|
||||||
|
# exclude: /test/
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
38
README.md
38
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!
|
||||||
|
|
||||||
@@ -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>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class OllamaAPI {
|
|||||||
@Setter
|
@Setter
|
||||||
private int maxChatToolCallRetries = 3;
|
private int maxChatToolCallRetries = 3;
|
||||||
|
|
||||||
private BasicAuth basicAuth;
|
private Auth auth;
|
||||||
|
|
||||||
private final ToolRegistry toolRegistry = new ToolRegistry();
|
private final ToolRegistry toolRegistry = new ToolRegistry();
|
||||||
|
|
||||||
@@ -106,7 +106,16 @@ public class OllamaAPI {
|
|||||||
* @param password the password
|
* @param password the password
|
||||||
*/
|
*/
|
||||||
public void setBasicAuth(String username, String password) {
|
public void setBasicAuth(String username, String password) {
|
||||||
this.basicAuth = new BasicAuth(username, password);
|
this.auth = new BasicAuth(username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set Bearer authentication for accessing Ollama server that's behind a reverse-proxy/gateway.
|
||||||
|
*
|
||||||
|
* @param bearerToken the Bearer authentication token to provide
|
||||||
|
*/
|
||||||
|
public void setBearerAuth(String bearerToken) {
|
||||||
|
this.auth = new BearerAuth(bearerToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -888,7 +897,7 @@ public class OllamaAPI {
|
|||||||
* @throws InterruptedException if the operation is interrupted
|
* @throws InterruptedException if the operation is interrupted
|
||||||
*/
|
*/
|
||||||
public OllamaChatResult chatStreaming(OllamaChatRequest request, OllamaTokenHandler tokenHandler) throws OllamaBaseException, IOException, InterruptedException {
|
public OllamaChatResult chatStreaming(OllamaChatRequest request, OllamaTokenHandler tokenHandler) throws OllamaBaseException, IOException, InterruptedException {
|
||||||
OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose);
|
OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds, verbose);
|
||||||
OllamaChatResult result;
|
OllamaChatResult result;
|
||||||
|
|
||||||
// add all registered tools to Request
|
// add all registered tools to Request
|
||||||
@@ -1094,7 +1103,7 @@ public class OllamaAPI {
|
|||||||
* @throws InterruptedException if the thread is interrupted during the request.
|
* @throws InterruptedException if the thread is interrupted during the request.
|
||||||
*/
|
*/
|
||||||
private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException {
|
private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel, OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException {
|
||||||
OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, basicAuth, requestTimeoutSeconds, verbose);
|
OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds, verbose);
|
||||||
OllamaResult result;
|
OllamaResult result;
|
||||||
if (streamHandler != null) {
|
if (streamHandler != null) {
|
||||||
ollamaRequestModel.setStream(true);
|
ollamaRequestModel.setStream(true);
|
||||||
@@ -1115,28 +1124,18 @@ public class OllamaAPI {
|
|||||||
private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
|
private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
|
||||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).header("Content-Type", "application/json").timeout(Duration.ofSeconds(requestTimeoutSeconds));
|
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).header("Content-Type", "application/json").timeout(Duration.ofSeconds(requestTimeoutSeconds));
|
||||||
if (isBasicAuthCredentialsSet()) {
|
if (isBasicAuthCredentialsSet()) {
|
||||||
requestBuilder.header("Authorization", getBasicAuthHeaderValue());
|
requestBuilder.header("Authorization", auth.getAuthHeaderValue());
|
||||||
}
|
}
|
||||||
return requestBuilder;
|
return requestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get basic authentication header value.
|
|
||||||
*
|
|
||||||
* @return basic authentication header value (encoded credentials)
|
|
||||||
*/
|
|
||||||
private String getBasicAuthHeaderValue() {
|
|
||||||
String credentialsToEncode = basicAuth.getUsername() + ":" + basicAuth.getPassword();
|
|
||||||
return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if Basic Auth credentials set.
|
* Check if Basic Auth credentials set.
|
||||||
*
|
*
|
||||||
* @return true when Basic Auth credentials set
|
* @return true when Basic Auth credentials set
|
||||||
*/
|
*/
|
||||||
private boolean isBasicAuthCredentialsSet() {
|
private boolean isBasicAuthCredentialsSet() {
|
||||||
return basicAuth != null;
|
return auth != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException {
|
private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException {
|
||||||
|
|||||||
10
src/main/java/io/github/ollama4j/models/request/Auth.java
Normal file
10
src/main/java/io/github/ollama4j/models/request/Auth.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package io.github.ollama4j.models.request;
|
||||||
|
|
||||||
|
public abstract class Auth {
|
||||||
|
/**
|
||||||
|
* Get authentication header value.
|
||||||
|
*
|
||||||
|
* @return authentication header value
|
||||||
|
*/
|
||||||
|
public abstract String getAuthHeaderValue();
|
||||||
|
}
|
||||||
@@ -1,13 +1,24 @@
|
|||||||
package io.github.ollama4j.models.request;
|
package io.github.ollama4j.models.request;
|
||||||
|
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class BasicAuth {
|
public class BasicAuth extends Auth {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get basic authentication header value.
|
||||||
|
*
|
||||||
|
* @return basic authentication header value (encoded credentials)
|
||||||
|
*/
|
||||||
|
public String getAuthHeaderValue() {
|
||||||
|
final String credentialsToEncode = this.getUsername() + ":" + this.getPassword();
|
||||||
|
return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package io.github.ollama4j.models.request;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class BearerAuth extends Auth {
|
||||||
|
private String bearerToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get authentication header value.
|
||||||
|
*
|
||||||
|
* @return authentication header value with bearer token
|
||||||
|
*/
|
||||||
|
public String getAuthHeaderValue() {
|
||||||
|
return "Bearer "+ bearerToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,8 +30,8 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
|||||||
|
|
||||||
private OllamaTokenHandler tokenHandler;
|
private OllamaTokenHandler tokenHandler;
|
||||||
|
|
||||||
public OllamaChatEndpointCaller(String host, BasicAuth basicAuth, long requestTimeoutSeconds, boolean verbose) {
|
public OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds, boolean verbose) {
|
||||||
super(host, basicAuth, requestTimeoutSeconds, verbose);
|
super(host, auth, requestTimeoutSeconds, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,26 +1,14 @@
|
|||||||
package io.github.ollama4j.models.request;
|
package io.github.ollama4j.models.request;
|
||||||
|
|
||||||
import io.github.ollama4j.OllamaAPI;
|
import java.net.URI;
|
||||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
import java.net.http.HttpRequest;
|
||||||
import io.github.ollama4j.models.response.OllamaErrorResponse;
|
import java.time.Duration;
|
||||||
import io.github.ollama4j.models.response.OllamaResult;
|
|
||||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
|
||||||
import io.github.ollama4j.utils.Utils;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import io.github.ollama4j.OllamaAPI;
|
||||||
import java.io.IOException;
|
import lombok.Getter;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.http.HttpClient;
|
|
||||||
import java.net.http.HttpRequest;
|
|
||||||
import java.net.http.HttpResponse;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract helperclass to call the ollama api server.
|
* Abstract helperclass to call the ollama api server.
|
||||||
@@ -31,13 +19,13 @@ public abstract class OllamaEndpointCaller {
|
|||||||
private static final Logger LOG = LoggerFactory.getLogger(OllamaAPI.class);
|
private static final Logger LOG = LoggerFactory.getLogger(OllamaAPI.class);
|
||||||
|
|
||||||
private final String host;
|
private final String host;
|
||||||
private final BasicAuth basicAuth;
|
private final Auth auth;
|
||||||
private final long requestTimeoutSeconds;
|
private final long requestTimeoutSeconds;
|
||||||
private final boolean verbose;
|
private final boolean verbose;
|
||||||
|
|
||||||
public OllamaEndpointCaller(String host, BasicAuth basicAuth, long requestTimeoutSeconds, boolean verbose) {
|
public OllamaEndpointCaller(String host, Auth auth, long requestTimeoutSeconds, boolean verbose) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.basicAuth = basicAuth;
|
this.auth = auth;
|
||||||
this.requestTimeoutSeconds = requestTimeoutSeconds;
|
this.requestTimeoutSeconds = requestTimeoutSeconds;
|
||||||
this.verbose = verbose;
|
this.verbose = verbose;
|
||||||
}
|
}
|
||||||
@@ -58,29 +46,19 @@ public abstract class OllamaEndpointCaller {
|
|||||||
HttpRequest.newBuilder(uri)
|
HttpRequest.newBuilder(uri)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.timeout(Duration.ofSeconds(this.requestTimeoutSeconds));
|
.timeout(Duration.ofSeconds(this.requestTimeoutSeconds));
|
||||||
if (isBasicAuthCredentialsSet()) {
|
if (isAuthCredentialsSet()) {
|
||||||
requestBuilder.header("Authorization", getBasicAuthHeaderValue());
|
requestBuilder.header("Authorization", this.auth.getAuthHeaderValue());
|
||||||
}
|
}
|
||||||
return requestBuilder;
|
return requestBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get basic authentication header value.
|
* Check if Auth credentials set.
|
||||||
*
|
*
|
||||||
* @return basic authentication header value (encoded credentials)
|
* @return true when Auth credentials set
|
||||||
*/
|
*/
|
||||||
protected String getBasicAuthHeaderValue() {
|
protected boolean isAuthCredentialsSet() {
|
||||||
String credentialsToEncode = this.basicAuth.getUsername() + ":" + this.basicAuth.getPassword();
|
return this.auth != null;
|
||||||
return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if Basic Auth credentials set.
|
|
||||||
*
|
|
||||||
* @return true when Basic Auth credentials set
|
|
||||||
*/
|
|
||||||
protected boolean isBasicAuthCredentialsSet() {
|
|
||||||
return this.basicAuth != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
|||||||
|
|
||||||
private OllamaGenerateStreamObserver streamObserver;
|
private OllamaGenerateStreamObserver streamObserver;
|
||||||
|
|
||||||
public OllamaGenerateEndpointCaller(String host, BasicAuth basicAuth, long requestTimeoutSeconds, boolean verbose) {
|
public OllamaGenerateEndpointCaller(String host, Auth basicAuth, long requestTimeoutSeconds, boolean verbose) {
|
||||||
super(host, basicAuth, requestTimeoutSeconds, verbose);
|
super(host, basicAuth, requestTimeoutSeconds, verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -192,12 +203,12 @@ public class OllamaAPIIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
@Order(10)
|
@Order(10)
|
||||||
public void testChat() throws Exception {
|
public void testChat() throws Exception {
|
||||||
String chatModel = "qwen2.5:0.5b";
|
String chatModel = "llama3";
|
||||||
api.pullModel(chatModel);
|
api.pullModel(chatModel);
|
||||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance(chatModel);
|
||||||
|
|
||||||
// Create the initial user question
|
// Create the initial user question
|
||||||
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What is the capital of France?")
|
OllamaChatRequest requestModel = builder.withMessage(OllamaChatMessageRole.USER, "What is 1+1? Answer only in numbers.")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Start conversation with model
|
// Start conversation with model
|
||||||
@@ -205,13 +216,13 @@ public class OllamaAPIIntegrationTest {
|
|||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
chatResult.getChatHistory().stream()
|
chatResult.getChatHistory().stream()
|
||||||
.anyMatch(chat -> chat.getContent().contains("Paris")),
|
.anyMatch(chat -> chat.getContent().contains("2")),
|
||||||
"Expected chat history to contain 'Paris'"
|
"Expected chat history to contain '2'"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the next user question: second largest city
|
// Create the next user question: second largest city
|
||||||
requestModel = builder.withMessages(chatResult.getChatHistory())
|
requestModel = builder.withMessages(chatResult.getChatHistory())
|
||||||
.withMessage(OllamaChatMessageRole.USER, "And what is its official language?")
|
.withMessage(OllamaChatMessageRole.USER, "And what is its squared value?")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Continue conversation with model
|
// Continue conversation with model
|
||||||
@@ -219,13 +230,13 @@ public class OllamaAPIIntegrationTest {
|
|||||||
|
|
||||||
assertTrue(
|
assertTrue(
|
||||||
chatResult.getChatHistory().stream()
|
chatResult.getChatHistory().stream()
|
||||||
.anyMatch(chat -> chat.getContent().contains("French")),
|
.anyMatch(chat -> chat.getContent().contains("4")),
|
||||||
"Expected chat history to contain 'French'"
|
"Expected chat history to contain '4'"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the next user question: the third question
|
// Create the next user question: the third question
|
||||||
requestModel = builder.withMessages(chatResult.getChatHistory())
|
requestModel = builder.withMessages(chatResult.getChatHistory())
|
||||||
.withMessage(OllamaChatMessageRole.USER, "What is the largest river in France?")
|
.withMessage(OllamaChatMessageRole.USER, "What is the largest value between 2, 4 and 6?")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Continue conversation with the model for the third question
|
// Continue conversation with the model for the third question
|
||||||
@@ -234,6 +245,356 @@ public class OllamaAPIIntegrationTest {
|
|||||||
// verify the result
|
// verify the result
|
||||||
assertNotNull(chatResult, "Chat result should not be null");
|
assertNotNull(chatResult, "Chat result should not be null");
|
||||||
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("6"), "Response should contain '6'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
Reference in New Issue
Block a user