mirror of
https://github.com/amithkoujalgi/ollama4j.git
synced 2025-10-13 17:08:57 +02:00
Add Spotless plugin and update copyright headers
Introduced the Spotless Maven plugin for code formatting in pom.xml. Updated copyright headers to include 'and contributors' and changed the year to 2025 in all main source files. Minor formatting and import order improvements applied throughout the codebase.
This commit is contained in:
parent
329381b1ee
commit
ac92766c6c
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Amith Koujalgi
|
||||
Copyright (c) 2023 Amith Koujalgi and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
65
pom.xml
65
pom.xml
@ -163,6 +163,71 @@
|
||||
<dateFormatTimeZone>Etc/UTC</dateFormatTimeZone>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.diffplug.spotless</groupId>
|
||||
<artifactId>spotless-maven-plugin</artifactId>
|
||||
<version>2.46.1</version>
|
||||
<configuration>
|
||||
<!-- <!– optional: limit format enforcement to just the files changed by this feature branch –>-->
|
||||
<!-- <ratchetFrom>origin/main</ratchetFrom>-->
|
||||
<formats>
|
||||
<!-- you can define as many formats as you want, each is independent -->
|
||||
<format>
|
||||
<!-- define the files to apply to -->
|
||||
<includes>
|
||||
<include>.gitattributes</include>
|
||||
<include>.gitignore</include>
|
||||
</includes>
|
||||
<!-- define the steps to apply to those files -->
|
||||
<trimTrailingWhitespace/>
|
||||
<endWithNewline/>
|
||||
<indent>
|
||||
<tabs>true</tabs>
|
||||
<spacesPerTab>4</spacesPerTab>
|
||||
</indent>
|
||||
</format>
|
||||
</formats>
|
||||
<!-- define a language-specific format -->
|
||||
<java>
|
||||
<!-- no need to specify files, inferred automatically, but you can if you want -->
|
||||
|
||||
<!-- apply a specific flavor of google-java-format and reflow long strings -->
|
||||
<googleJavaFormat>
|
||||
<version>1.28.0</version>
|
||||
<style>AOSP</style>
|
||||
<reflowLongStrings>true</reflowLongStrings>
|
||||
<formatJavadoc>false</formatJavadoc>
|
||||
</googleJavaFormat>
|
||||
|
||||
<!-- make sure every file has the following copyright header.
|
||||
optionally, Spotless can set copyright years by digging
|
||||
through git history (see "license" section below) -->
|
||||
<licenseHeader>
|
||||
<content>
|
||||
<![CDATA[
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) $YEAR Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
]]>
|
||||
</content> <!-- or <file>${project.basedir}/license-header</file> -->
|
||||
</licenseHeader>
|
||||
</java>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<pluginManagement>
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
@ -22,10 +30,6 @@ import io.github.ollama4j.tools.annotations.ToolSpec;
|
||||
import io.github.ollama4j.utils.Constants;
|
||||
import io.github.ollama4j.utils.Options;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@ -41,6 +45,9 @@ import java.nio.file.Files;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.Setter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The base Ollama API class.
|
||||
@ -61,14 +68,12 @@ public class OllamaAPI {
|
||||
* for a response
|
||||
* from the Ollama server before timing out.
|
||||
*/
|
||||
@Setter
|
||||
private long requestTimeoutSeconds = 10;
|
||||
@Setter private long requestTimeoutSeconds = 10;
|
||||
|
||||
@Setter
|
||||
private int imageURLReadTimeoutSeconds = 10;
|
||||
@Setter private int imageURLReadTimeoutSeconds = 10;
|
||||
|
||||
@Setter private int imageURLConnectTimeoutSeconds = 10;
|
||||
|
||||
@Setter
|
||||
private int imageURLConnectTimeoutSeconds = 10;
|
||||
/**
|
||||
* The maximum number of retries for tool calls during chat interactions.
|
||||
* <p>
|
||||
@ -76,8 +81,7 @@ public class OllamaAPI {
|
||||
* event of a failure.
|
||||
* Default is 3.
|
||||
*/
|
||||
@Setter
|
||||
private int maxChatToolCallRetries = 3;
|
||||
@Setter private int maxChatToolCallRetries = 3;
|
||||
|
||||
/**
|
||||
* The number of retries to attempt when pulling a model from the Ollama server.
|
||||
@ -98,8 +102,7 @@ public class OllamaAPI {
|
||||
* <p>
|
||||
* Default is false for backward compatibility.
|
||||
*/
|
||||
@Setter
|
||||
private boolean clientHandlesTools = false;
|
||||
@Setter private boolean clientHandlesTools = false;
|
||||
|
||||
/**
|
||||
* Instantiates the Ollama API with default Ollama host:
|
||||
@ -154,9 +157,14 @@ public class OllamaAPI {
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
HttpRequest httpRequest;
|
||||
try {
|
||||
httpRequest = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
httpRequest =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.GET()
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
@ -183,15 +191,22 @@ public class OllamaAPI {
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
* @throws OllamaBaseException if the response indicates an error status
|
||||
*/
|
||||
public ModelsProcessResponse ps() throws IOException, InterruptedException, OllamaBaseException {
|
||||
public ModelsProcessResponse ps()
|
||||
throws IOException, InterruptedException, OllamaBaseException {
|
||||
String url = this.host + "/api/ps";
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
HttpRequest httpRequest = null;
|
||||
try {
|
||||
httpRequest = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.GET().build();
|
||||
httpRequest =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.GET()
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -215,18 +230,28 @@ public class OllamaAPI {
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
* @throws URISyntaxException if the URI for the request is malformed
|
||||
*/
|
||||
public List<Model> listModels() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
public List<Model> listModels()
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
String url = this.host + "/api/tags";
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
|
||||
HttpRequest httpRequest =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response =
|
||||
httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
String responseString = response.body();
|
||||
if (statusCode == 200) {
|
||||
return Utils.getObjectMapper().readValue(responseString, ListModelsResponse.class).getModels();
|
||||
return Utils.getObjectMapper()
|
||||
.readValue(responseString, ListModelsResponse.class)
|
||||
.getModels();
|
||||
} else {
|
||||
throw new OllamaBaseException(statusCode + " - " + responseString);
|
||||
}
|
||||
@ -266,24 +291,34 @@ public class OllamaAPI {
|
||||
this.doPullModel(modelName);
|
||||
return;
|
||||
} catch (OllamaBaseException e) {
|
||||
handlePullRetry(modelName, numberOfRetries, numberOfRetriesForModelPull, baseDelayMillis);
|
||||
handlePullRetry(
|
||||
modelName, numberOfRetries, numberOfRetriesForModelPull, baseDelayMillis);
|
||||
numberOfRetries++;
|
||||
}
|
||||
}
|
||||
throw new OllamaBaseException(
|
||||
"Failed to pull model " + modelName + " after " + numberOfRetriesForModelPull + " retries");
|
||||
"Failed to pull model "
|
||||
+ modelName
|
||||
+ " after "
|
||||
+ numberOfRetriesForModelPull
|
||||
+ " retries");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles retry backoff for pullModel.
|
||||
*/
|
||||
private void handlePullRetry(String modelName, int currentRetry, int maxRetries, long baseDelayMillis)
|
||||
private void handlePullRetry(
|
||||
String modelName, int currentRetry, int maxRetries, long baseDelayMillis)
|
||||
throws InterruptedException {
|
||||
int attempt = currentRetry + 1;
|
||||
if (attempt < maxRetries) {
|
||||
long backoffMillis = baseDelayMillis * (1L << currentRetry);
|
||||
LOG.error("Failed to pull model {}, retrying in {}s... (attempt {}/{})",
|
||||
modelName, backoffMillis / 1000, attempt, maxRetries);
|
||||
LOG.error(
|
||||
"Failed to pull model {}, retrying in {}s... (attempt {}/{})",
|
||||
modelName,
|
||||
backoffMillis / 1000,
|
||||
attempt,
|
||||
maxRetries);
|
||||
try {
|
||||
Thread.sleep(backoffMillis);
|
||||
} catch (InterruptedException ie) {
|
||||
@ -291,7 +326,10 @@ public class OllamaAPI {
|
||||
throw ie;
|
||||
}
|
||||
} else {
|
||||
LOG.error("Failed to pull model {} after {} attempts, no more retries.", modelName, maxRetries);
|
||||
LOG.error(
|
||||
"Failed to pull model {} after {} attempts, no more retries.",
|
||||
modelName,
|
||||
maxRetries);
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,25 +337,36 @@ public class OllamaAPI {
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String url = this.host + "/api/pull";
|
||||
String jsonData = new ModelRequest(modelName).toString();
|
||||
HttpRequest request = getRequestBuilderDefault(new URI(url)).POST(HttpRequest.BodyPublishers.ofString(jsonData))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
HttpRequest request =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.build();
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
HttpResponse<InputStream> response =
|
||||
client.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
int statusCode = response.statusCode();
|
||||
InputStream responseBodyStream = response.body();
|
||||
String responseString = "";
|
||||
boolean success = false; // Flag to check the pull success.
|
||||
try (BufferedReader reader = new BufferedReader(
|
||||
try (BufferedReader reader =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
ModelPullResponse modelPullResponse = Utils.getObjectMapper().readValue(line, ModelPullResponse.class);
|
||||
ModelPullResponse modelPullResponse =
|
||||
Utils.getObjectMapper().readValue(line, ModelPullResponse.class);
|
||||
if (modelPullResponse != null) {
|
||||
// Check for error in response body first
|
||||
if (modelPullResponse.getError() != null && !modelPullResponse.getError().trim().isEmpty()) {
|
||||
throw new OllamaBaseException("Model pull failed: " + modelPullResponse.getError());
|
||||
if (modelPullResponse.getError() != null
|
||||
&& !modelPullResponse.getError().trim().isEmpty()) {
|
||||
throw new OllamaBaseException(
|
||||
"Model pull failed: " + modelPullResponse.getError());
|
||||
}
|
||||
|
||||
if (modelPullResponse.getStatus() != null) {
|
||||
@ -341,18 +390,28 @@ public class OllamaAPI {
|
||||
}
|
||||
}
|
||||
|
||||
public String getVersion() throws URISyntaxException, IOException, InterruptedException, OllamaBaseException {
|
||||
public String getVersion()
|
||||
throws URISyntaxException, IOException, InterruptedException, OllamaBaseException {
|
||||
String url = this.host + "/api/version";
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
|
||||
HttpRequest httpRequest =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.GET()
|
||||
.build();
|
||||
HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response =
|
||||
httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
String responseString = response.body();
|
||||
if (statusCode == 200) {
|
||||
return Utils.getObjectMapper().readValue(responseString, OllamaVersion.class).getVersion();
|
||||
return Utils.getObjectMapper()
|
||||
.readValue(responseString, OllamaVersion.class)
|
||||
.getVersion();
|
||||
} else {
|
||||
throw new OllamaBaseException(statusCode + " - " + responseString);
|
||||
}
|
||||
@ -374,7 +433,8 @@ public class OllamaAPI {
|
||||
*/
|
||||
public void pullModel(LibraryModelTag libraryModelTag)
|
||||
throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
|
||||
String tagToPull = String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag());
|
||||
String tagToPull =
|
||||
String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag());
|
||||
pullModel(tagToPull);
|
||||
}
|
||||
|
||||
@ -392,10 +452,16 @@ public class OllamaAPI {
|
||||
throws IOException, OllamaBaseException, InterruptedException, URISyntaxException {
|
||||
String url = this.host + "/api/show";
|
||||
String jsonData = new ModelRequest(modelName).toString();
|
||||
HttpRequest request = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
|
||||
HttpRequest request =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
|
||||
.build();
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
@ -422,10 +488,16 @@ public class OllamaAPI {
|
||||
throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
|
||||
String url = this.host + "/api/create";
|
||||
String jsonData = customModelRequest.toString();
|
||||
HttpRequest request = getRequestBuilderDefault(new URI(url))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
|
||||
HttpRequest request =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
|
||||
.build();
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
@ -454,16 +526,26 @@ public class OllamaAPI {
|
||||
throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
|
||||
String url = this.host + "/api/delete";
|
||||
String jsonData = new ModelRequest(modelName).toString();
|
||||
HttpRequest request = getRequestBuilderDefault(new URI(url))
|
||||
.method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
HttpRequest request =
|
||||
getRequestBuilderDefault(new URI(url))
|
||||
.method(
|
||||
"DELETE",
|
||||
HttpRequest.BodyPublishers.ofString(
|
||||
jsonData, StandardCharsets.UTF_8))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.build();
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
String responseBody = response.body();
|
||||
if (statusCode == 404 && responseBody.contains("model") && responseBody.contains("not found")) {
|
||||
if (statusCode == 404
|
||||
&& responseBody.contains("model")
|
||||
&& responseBody.contains("not found")) {
|
||||
return;
|
||||
}
|
||||
if (statusCode != 200) {
|
||||
@ -486,11 +568,16 @@ public class OllamaAPI {
|
||||
String jsonData = Utils.getObjectMapper().writeValueAsString(modelRequest);
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder(uri)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
|
||||
HttpRequest request =
|
||||
HttpRequest.newBuilder(uri)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
String responseBody = response.body();
|
||||
|
||||
@ -527,8 +614,13 @@ public class OllamaAPI {
|
||||
* @throws IOException if an I/O error occurs during the HTTP request
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
*/
|
||||
public OllamaResult generate(String model, String prompt, boolean raw, Options options,
|
||||
OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException {
|
||||
public OllamaResult generate(
|
||||
String model,
|
||||
String prompt,
|
||||
boolean raw,
|
||||
Options options,
|
||||
OllamaStreamHandler responseStreamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
|
||||
ollamaRequestModel.setRaw(raw);
|
||||
ollamaRequestModel.setThink(false);
|
||||
@ -563,14 +655,20 @@ public class OllamaAPI {
|
||||
* @throws IOException if an I/O error occurs during the HTTP request
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
*/
|
||||
public OllamaResult generate(String model, String prompt, boolean raw, Options options,
|
||||
OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
|
||||
public OllamaResult generate(
|
||||
String model,
|
||||
String prompt,
|
||||
boolean raw,
|
||||
Options options,
|
||||
OllamaStreamHandler thinkingStreamHandler,
|
||||
OllamaStreamHandler responseStreamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
|
||||
ollamaRequestModel.setRaw(raw);
|
||||
ollamaRequestModel.setThink(true);
|
||||
ollamaRequestModel.setOptions(options.getOptionsMap());
|
||||
return generateSyncForOllamaRequestModel(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
|
||||
return generateSyncForOllamaRequestModel(
|
||||
ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -596,7 +694,8 @@ public class OllamaAPI {
|
||||
* @throws IOException if an I/O error occurs during the HTTP request
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
*/
|
||||
public OllamaResult generate(String model, String prompt, boolean raw, boolean think, Options options)
|
||||
public OllamaResult generate(
|
||||
String model, String prompt, boolean raw, boolean think, Options options)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
if (think) {
|
||||
return generate(model, prompt, raw, options, null, null);
|
||||
@ -635,27 +734,41 @@ public class OllamaAPI {
|
||||
String jsonData = Utils.getObjectMapper().writeValueAsString(requestBody);
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
|
||||
HttpRequest request = getRequestBuilderDefault(uri)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
|
||||
HttpRequest request =
|
||||
getRequestBuilderDefault(uri)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_ACCEPT,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonData))
|
||||
.build();
|
||||
|
||||
try {
|
||||
String prettyJson = Utils.getObjectMapper().writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(Utils.getObjectMapper().readValue(jsonData, Object.class));
|
||||
String prettyJson =
|
||||
Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(
|
||||
Utils.getObjectMapper().readValue(jsonData, Object.class));
|
||||
LOG.debug("Asking model:\n{}", prettyJson);
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Asking model: {}", jsonData);
|
||||
}
|
||||
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
HttpResponse<String> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
int statusCode = response.statusCode();
|
||||
String responseBody = response.body();
|
||||
if (statusCode == 200) {
|
||||
OllamaStructuredResult structuredResult = Utils.getObjectMapper().readValue(responseBody,
|
||||
OllamaStructuredResult.class);
|
||||
OllamaResult ollamaResult = new OllamaResult(structuredResult.getResponse(), structuredResult.getThinking(),
|
||||
structuredResult.getResponseTime(), statusCode);
|
||||
OllamaStructuredResult structuredResult =
|
||||
Utils.getObjectMapper().readValue(responseBody, OllamaStructuredResult.class);
|
||||
OllamaResult ollamaResult =
|
||||
new OllamaResult(
|
||||
structuredResult.getResponse(),
|
||||
structuredResult.getThinking(),
|
||||
structuredResult.getResponseTime(),
|
||||
statusCode);
|
||||
|
||||
ollamaResult.setModel(structuredResult.getModel());
|
||||
ollamaResult.setCreatedAt(structuredResult.getCreatedAt());
|
||||
@ -671,8 +784,11 @@ public class OllamaAPI {
|
||||
LOG.debug("Model response:\n{}", ollamaResult);
|
||||
return ollamaResult;
|
||||
} else {
|
||||
LOG.debug("Model response:\n{}",
|
||||
Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseBody));
|
||||
LOG.debug(
|
||||
"Model response:\n{}",
|
||||
Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(responseBody));
|
||||
throw new OllamaBaseException(statusCode + " - " + responseBody);
|
||||
}
|
||||
}
|
||||
@ -688,7 +804,6 @@ public class OllamaAPI {
|
||||
* using the registered tool implementations, and their results are collected.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>Typical usage:</b>
|
||||
* <pre>{@code
|
||||
* OllamaToolsResult result = ollamaAPI.generateWithTools(
|
||||
@ -700,7 +815,6 @@ public class OllamaAPI {
|
||||
* String modelResponse = result.getModelResult().getResponse();
|
||||
* Map<ToolFunctionCallSpec, Object> toolResults = result.getToolResults();
|
||||
* }</pre>
|
||||
* </p>
|
||||
*
|
||||
* @param model the name or identifier of the AI model to use for generating the response
|
||||
* @param prompt the input text or prompt to provide to the AI model
|
||||
@ -713,7 +827,8 @@ public class OllamaAPI {
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
* @throws ToolInvocationException if a tool call fails to execute
|
||||
*/
|
||||
public OllamaToolsResult generateWithTools(String model, String prompt, Options options, OllamaStreamHandler streamHandler)
|
||||
public OllamaToolsResult generateWithTools(
|
||||
String model, String prompt, Options options, OllamaStreamHandler streamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
|
||||
boolean raw = true;
|
||||
OllamaToolsResult toolResult = new OllamaToolsResult();
|
||||
@ -744,11 +859,18 @@ public class OllamaAPI {
|
||||
// Try to parse the string to see if it's a valid JSON
|
||||
objectMapper.readTree(toolsResponse);
|
||||
} catch (JsonParseException e) {
|
||||
LOG.warn("Response from model does not contain any tool calls. Returning the response as is.");
|
||||
LOG.warn(
|
||||
"Response from model does not contain any tool calls. Returning the"
|
||||
+ " response as is.");
|
||||
return toolResult;
|
||||
}
|
||||
toolFunctionCallSpecs = objectMapper.readValue(toolsResponse,
|
||||
objectMapper.getTypeFactory().constructCollectionType(List.class, ToolFunctionCallSpec.class));
|
||||
toolFunctionCallSpecs =
|
||||
objectMapper.readValue(
|
||||
toolsResponse,
|
||||
objectMapper
|
||||
.getTypeFactory()
|
||||
.constructCollectionType(
|
||||
List.class, ToolFunctionCallSpec.class));
|
||||
}
|
||||
for (ToolFunctionCallSpec toolFunctionCallSpec : toolFunctionCallSpecs) {
|
||||
toolResults.put(toolFunctionCallSpec, invokeTool(toolFunctionCallSpec));
|
||||
@ -795,12 +917,14 @@ public class OllamaAPI {
|
||||
* @return an {@link OllamaAsyncResultStreamer} handle for polling and
|
||||
* retrieving streamed results
|
||||
*/
|
||||
public OllamaAsyncResultStreamer generate(String model, String prompt, boolean raw, boolean think) {
|
||||
public OllamaAsyncResultStreamer generate(
|
||||
String model, String prompt, boolean raw, boolean think) {
|
||||
OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
|
||||
ollamaRequestModel.setRaw(raw);
|
||||
ollamaRequestModel.setThink(think);
|
||||
URI uri = URI.create(this.host + "/api/generate");
|
||||
OllamaAsyncResultStreamer ollamaAsyncResultStreamer = new OllamaAsyncResultStreamer(
|
||||
OllamaAsyncResultStreamer ollamaAsyncResultStreamer =
|
||||
new OllamaAsyncResultStreamer(
|
||||
getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds);
|
||||
ollamaAsyncResultStreamer.start();
|
||||
return ollamaAsyncResultStreamer;
|
||||
@ -833,8 +957,14 @@ public class OllamaAPI {
|
||||
* @throws InterruptedException if the operation is interrupted
|
||||
* @throws URISyntaxException if an image URL is malformed
|
||||
*/
|
||||
public OllamaResult generateWithImages(String model, String prompt, List<Object> images, Options options, Map<String, Object> format,
|
||||
OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
public OllamaResult generateWithImages(
|
||||
String model,
|
||||
String prompt,
|
||||
List<Object> images,
|
||||
Options options,
|
||||
Map<String, Object> format,
|
||||
OllamaStreamHandler streamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
|
||||
List<String> encodedImages = new ArrayList<>();
|
||||
for (Object image : images) {
|
||||
if (image instanceof File) {
|
||||
@ -845,12 +975,19 @@ public class OllamaAPI {
|
||||
encodedImages.add(encodeByteArrayToBase64((byte[]) image));
|
||||
} else if (image instanceof String) {
|
||||
LOG.debug("Using image URL: {}", image);
|
||||
encodedImages.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl((String) image, imageURLConnectTimeoutSeconds, imageURLReadTimeoutSeconds)));
|
||||
encodedImages.add(
|
||||
encodeByteArrayToBase64(
|
||||
Utils.loadImageBytesFromUrl(
|
||||
(String) image,
|
||||
imageURLConnectTimeoutSeconds,
|
||||
imageURLReadTimeoutSeconds)));
|
||||
} else {
|
||||
throw new OllamaBaseException("Unsupported image type. Please provide a File, byte[], or a URL String.");
|
||||
throw new OllamaBaseException(
|
||||
"Unsupported image type. Please provide a File, byte[], or a URL String.");
|
||||
}
|
||||
}
|
||||
OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt, encodedImages);
|
||||
OllamaGenerateRequest ollamaRequestModel =
|
||||
new OllamaGenerateRequest(model, prompt, encodedImages);
|
||||
if (format != null) {
|
||||
ollamaRequestModel.setFormat(format);
|
||||
}
|
||||
@ -879,11 +1016,14 @@ public class OllamaAPI {
|
||||
*/
|
||||
public OllamaChatResult chat(OllamaChatRequest request, OllamaTokenHandler tokenHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
|
||||
OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds);
|
||||
OllamaChatEndpointCaller requestCaller =
|
||||
new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds);
|
||||
OllamaChatResult result;
|
||||
|
||||
// add all registered tools to Request
|
||||
request.setTools(toolRegistry.getRegisteredSpecs().stream().map(Tools.ToolSpecification::getToolPrompt)
|
||||
request.setTools(
|
||||
toolRegistry.getRegisteredSpecs().stream()
|
||||
.map(Tools.ToolSpecification::getToolPrompt)
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
if (tokenHandler != null) {
|
||||
@ -900,7 +1040,9 @@ public class OllamaAPI {
|
||||
// check if toolCallIsWanted
|
||||
List<OllamaChatToolCalls> toolCalls = result.getResponseModel().getMessage().getToolCalls();
|
||||
int toolCallTries = 0;
|
||||
while (toolCalls != null && !toolCalls.isEmpty() && toolCallTries < maxChatToolCallRetries) {
|
||||
while (toolCalls != null
|
||||
&& !toolCalls.isEmpty()
|
||||
&& toolCallTries < maxChatToolCallRetries) {
|
||||
for (OllamaChatToolCalls toolCall : toolCalls) {
|
||||
String toolName = toolCall.getFunction().getName();
|
||||
ToolFunction toolFunction = toolRegistry.getToolFunction(toolName);
|
||||
@ -909,11 +1051,21 @@ public class OllamaAPI {
|
||||
}
|
||||
Map<String, Object> arguments = toolCall.getFunction().getArguments();
|
||||
Object res = toolFunction.apply(arguments);
|
||||
String argumentKeys = arguments.keySet().stream()
|
||||
String argumentKeys =
|
||||
arguments.keySet().stream()
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(", "));
|
||||
request.getMessages().add(new OllamaChatMessage(OllamaChatMessageRole.TOOL,
|
||||
"[TOOL_RESULTS] " + toolName + "(" + argumentKeys + "): " + res + " [/TOOL_RESULTS]"));
|
||||
request.getMessages()
|
||||
.add(
|
||||
new OllamaChatMessage(
|
||||
OllamaChatMessageRole.TOOL,
|
||||
"[TOOL_RESULTS] "
|
||||
+ toolName
|
||||
+ "("
|
||||
+ argumentKeys
|
||||
+ "): "
|
||||
+ res
|
||||
+ " [/TOOL_RESULTS]"));
|
||||
}
|
||||
|
||||
if (tokenHandler != null) {
|
||||
@ -982,21 +1134,26 @@ public class OllamaAPI {
|
||||
try {
|
||||
Class<?> callerClass = null;
|
||||
try {
|
||||
callerClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
|
||||
callerClass =
|
||||
Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
OllamaToolService ollamaToolServiceAnnotation = callerClass.getDeclaredAnnotation(OllamaToolService.class);
|
||||
OllamaToolService ollamaToolServiceAnnotation =
|
||||
callerClass.getDeclaredAnnotation(OllamaToolService.class);
|
||||
if (ollamaToolServiceAnnotation == null) {
|
||||
throw new IllegalStateException(callerClass + " is not annotated as " + OllamaToolService.class);
|
||||
throw new IllegalStateException(
|
||||
callerClass + " is not annotated as " + OllamaToolService.class);
|
||||
}
|
||||
|
||||
Class<?>[] providers = ollamaToolServiceAnnotation.providers();
|
||||
for (Class<?> provider : providers) {
|
||||
registerAnnotatedTools(provider.getDeclaredConstructor().newInstance());
|
||||
}
|
||||
} catch (InstantiationException | NoSuchMethodException | IllegalAccessException
|
||||
} catch (InstantiationException
|
||||
| NoSuchMethodException
|
||||
| IllegalAccessException
|
||||
| InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -1029,36 +1186,61 @@ public class OllamaAPI {
|
||||
final Tools.PropsBuilder propsBuilder = new Tools.PropsBuilder();
|
||||
LinkedHashMap<String, String> methodParams = new LinkedHashMap<>();
|
||||
for (Parameter parameter : m.getParameters()) {
|
||||
final ToolProperty toolPropertyAnn = parameter.getDeclaredAnnotation(ToolProperty.class);
|
||||
final ToolProperty toolPropertyAnn =
|
||||
parameter.getDeclaredAnnotation(ToolProperty.class);
|
||||
String propType = parameter.getType().getTypeName();
|
||||
if (toolPropertyAnn == null) {
|
||||
methodParams.put(parameter.getName(), null);
|
||||
continue;
|
||||
}
|
||||
String propName = !toolPropertyAnn.name().isBlank() ? toolPropertyAnn.name() : parameter.getName();
|
||||
String propName =
|
||||
!toolPropertyAnn.name().isBlank()
|
||||
? toolPropertyAnn.name()
|
||||
: parameter.getName();
|
||||
methodParams.put(propName, propType);
|
||||
propsBuilder.withProperty(propName, Tools.PromptFuncDefinition.Property.builder().type(propType)
|
||||
.description(toolPropertyAnn.desc()).required(toolPropertyAnn.required()).build());
|
||||
propsBuilder.withProperty(
|
||||
propName,
|
||||
Tools.PromptFuncDefinition.Property.builder()
|
||||
.type(propType)
|
||||
.description(toolPropertyAnn.desc())
|
||||
.required(toolPropertyAnn.required())
|
||||
.build());
|
||||
}
|
||||
final Map<String, Tools.PromptFuncDefinition.Property> params = propsBuilder.build();
|
||||
List<String> reqProps = params.entrySet().stream().filter(e -> e.getValue().isRequired())
|
||||
.map(Map.Entry::getKey).collect(Collectors.toList());
|
||||
List<String> reqProps =
|
||||
params.entrySet().stream()
|
||||
.filter(e -> e.getValue().isRequired())
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Tools.ToolSpecification toolSpecification = Tools.ToolSpecification.builder().functionName(operationName)
|
||||
Tools.ToolSpecification toolSpecification =
|
||||
Tools.ToolSpecification.builder()
|
||||
.functionName(operationName)
|
||||
.functionDescription(operationDesc)
|
||||
.toolPrompt(Tools.PromptFuncDefinition.builder().type("function")
|
||||
.function(Tools.PromptFuncDefinition.PromptFuncSpec.builder().name(operationName)
|
||||
.description(operationDesc).parameters(Tools.PromptFuncDefinition.Parameters
|
||||
.builder().type("object").properties(params).required(reqProps).build())
|
||||
.toolPrompt(
|
||||
Tools.PromptFuncDefinition.builder()
|
||||
.type("function")
|
||||
.function(
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec
|
||||
.builder()
|
||||
.name(operationName)
|
||||
.description(operationDesc)
|
||||
.parameters(
|
||||
Tools.PromptFuncDefinition
|
||||
.Parameters.builder()
|
||||
.type("object")
|
||||
.properties(params)
|
||||
.required(reqProps)
|
||||
.build())
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
ReflectionalToolFunction reflectionalToolFunction = new ReflectionalToolFunction(object, m, methodParams);
|
||||
ReflectionalToolFunction reflectionalToolFunction =
|
||||
new ReflectionalToolFunction(object, m, methodParams);
|
||||
toolSpecification.setToolFunction(reflectionalToolFunction);
|
||||
toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1135,14 +1317,19 @@ public class OllamaAPI {
|
||||
* process.
|
||||
* @throws InterruptedException if the thread is interrupted during the request.
|
||||
*/
|
||||
private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel,
|
||||
OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
|
||||
private OllamaResult generateSyncForOllamaRequestModel(
|
||||
OllamaGenerateRequest ollamaRequestModel,
|
||||
OllamaStreamHandler thinkingStreamHandler,
|
||||
OllamaStreamHandler responseStreamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds);
|
||||
OllamaGenerateEndpointCaller requestCaller =
|
||||
new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds);
|
||||
OllamaResult result;
|
||||
if (responseStreamHandler != null) {
|
||||
ollamaRequestModel.setStream(true);
|
||||
result = requestCaller.call(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
|
||||
result =
|
||||
requestCaller.call(
|
||||
ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
|
||||
} else {
|
||||
result = requestCaller.callSync(ollamaRequestModel);
|
||||
}
|
||||
@ -1156,8 +1343,11 @@ public class OllamaAPI {
|
||||
* @return HttpRequest.Builder
|
||||
*/
|
||||
private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
HttpRequest.Builder requestBuilder =
|
||||
HttpRequest.newBuilder(uri)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.timeout(Duration.ofSeconds(requestTimeoutSeconds));
|
||||
if (isAuthSet()) {
|
||||
requestBuilder.header("Authorization", auth.getAuthHeaderValue());
|
||||
@ -1174,7 +1364,8 @@ public class OllamaAPI {
|
||||
return auth != null;
|
||||
}
|
||||
|
||||
private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException {
|
||||
private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec)
|
||||
throws ToolInvocationException {
|
||||
try {
|
||||
String methodName = toolFunctionCallSpec.getName();
|
||||
Map<String, Object> arguments = toolFunctionCallSpec.getArguments();
|
||||
@ -1182,11 +1373,14 @@ public class OllamaAPI {
|
||||
LOG.debug("Invoking function {} with arguments {}", methodName, arguments);
|
||||
if (function == null) {
|
||||
throw new ToolNotFoundException(
|
||||
"No such tool: " + methodName + ". Please register the tool before invoking it.");
|
||||
"No such tool: "
|
||||
+ methodName
|
||||
+ ". Please register the tool before invoking it.");
|
||||
}
|
||||
return function.apply(arguments);
|
||||
} catch (Exception e) {
|
||||
throw new ToolInvocationException("Failed to invoke tool: " + toolFunctionCallSpec.getName(), e);
|
||||
throw new ToolInvocationException(
|
||||
"Failed to invoke tool: " + toolFunctionCallSpec.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class OllamaBaseException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class RoleNotFoundException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class ToolInvocationException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.exceptions;
|
||||
|
||||
public class ToolNotFoundException extends Exception {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.impl;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaStreamHandler;
|
||||
|
@ -1,15 +1,22 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.github.ollama4j.utils.FileToBase64Serializer;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* Defines a single Message to be used inside a chat request against the ollama /api/chat endpoint.
|
||||
@ -23,11 +30,9 @@ import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class OllamaChatMessage {
|
||||
|
||||
@NonNull
|
||||
private OllamaChatMessageRole role;
|
||||
@NonNull private OllamaChatMessageRole role;
|
||||
|
||||
@NonNull
|
||||
private String content;
|
||||
@NonNull private String content;
|
||||
|
||||
private String thinking;
|
||||
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import io.github.ollama4j.exceptions.RoleNotFoundException;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Defines the possible Chat Message roles.
|
||||
@ -19,8 +26,7 @@ public class OllamaChatMessageRole {
|
||||
public static final OllamaChatMessageRole ASSISTANT = new OllamaChatMessageRole("assistant");
|
||||
public static final OllamaChatMessageRole TOOL = new OllamaChatMessageRole("tool");
|
||||
|
||||
@JsonValue
|
||||
private final String roleName;
|
||||
@JsonValue private final String roleName;
|
||||
|
||||
private OllamaChatMessageRole(String roleName) {
|
||||
this.roleName = roleName;
|
||||
@ -28,8 +34,8 @@ public class OllamaChatMessageRole {
|
||||
}
|
||||
|
||||
public static OllamaChatMessageRole newCustomRole(String roleName) {
|
||||
// OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName);
|
||||
// roles.add(customRole);
|
||||
// OllamaChatMessageRole customRole = new OllamaChatMessageRole(roleName);
|
||||
// roles.add(customRole);
|
||||
return new OllamaChatMessageRole(roleName);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.models.request.OllamaCommonRequest;
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines a Request to use against the ollama /api/chat endpoint.
|
||||
*
|
||||
@ -25,8 +32,7 @@ public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequ
|
||||
|
||||
private boolean think;
|
||||
|
||||
public OllamaChatRequest() {
|
||||
}
|
||||
public OllamaChatRequest() {}
|
||||
|
||||
public OllamaChatRequest(String model, boolean think, List<OllamaChatMessage> messages) {
|
||||
this.model = model;
|
||||
@ -42,5 +48,4 @@ public class OllamaChatRequest extends OllamaCommonRequest implements OllamaRequ
|
||||
|
||||
return this.toString().equals(o.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@ -12,6 +17,8 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Helper class for creating {@link OllamaChatRequest} objects using the builder-pattern.
|
||||
@ -23,7 +30,8 @@ public class OllamaChatRequestBuilder {
|
||||
private int imageURLConnectTimeoutSeconds = 10;
|
||||
private int imageURLReadTimeoutSeconds = 10;
|
||||
|
||||
public OllamaChatRequestBuilder withImageURLConnectTimeoutSeconds(int imageURLConnectTimeoutSeconds) {
|
||||
public OllamaChatRequestBuilder withImageURLConnectTimeoutSeconds(
|
||||
int imageURLConnectTimeoutSeconds) {
|
||||
this.imageURLConnectTimeoutSeconds = imageURLConnectTimeoutSeconds;
|
||||
return this;
|
||||
}
|
||||
@ -55,40 +63,67 @@ public class OllamaChatRequestBuilder {
|
||||
return withMessage(role, content, Collections.emptyList());
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls) {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
messages.add(new OllamaChatMessage(role, content, null, toolCalls, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls, List<File> images) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role,
|
||||
String content,
|
||||
List<OllamaChatToolCalls> toolCalls,
|
||||
List<File> images) {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
|
||||
List<byte[]> binaryImages = images.stream().map(file -> {
|
||||
List<byte[]> binaryImages =
|
||||
images.stream()
|
||||
.map(
|
||||
file -> {
|
||||
try {
|
||||
return Files.readAllBytes(file.toPath());
|
||||
} catch (IOException e) {
|
||||
LOG.warn("File '{}' could not be accessed, will not add to message!", file.toPath(), e);
|
||||
LOG.warn(
|
||||
"File '{}' could not be accessed, will not add to"
|
||||
+ " message!",
|
||||
file.toPath(),
|
||||
e);
|
||||
return new byte[0];
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
messages.add(new OllamaChatMessage(role, content, null, toolCalls, binaryImages));
|
||||
return this;
|
||||
}
|
||||
|
||||
public OllamaChatRequestBuilder withMessage(OllamaChatMessageRole role, String content, List<OllamaChatToolCalls> toolCalls, String... imageUrls) {
|
||||
public OllamaChatRequestBuilder withMessage(
|
||||
OllamaChatMessageRole role,
|
||||
String content,
|
||||
List<OllamaChatToolCalls> toolCalls,
|
||||
String... imageUrls) {
|
||||
List<OllamaChatMessage> messages = this.request.getMessages();
|
||||
List<byte[]> binaryImages = null;
|
||||
if (imageUrls.length > 0) {
|
||||
binaryImages = new ArrayList<>();
|
||||
for (String imageUrl : imageUrls) {
|
||||
try {
|
||||
binaryImages.add(Utils.loadImageBytesFromUrl(imageUrl, imageURLConnectTimeoutSeconds, imageURLReadTimeoutSeconds));
|
||||
binaryImages.add(
|
||||
Utils.loadImageBytesFromUrl(
|
||||
imageUrl,
|
||||
imageURLConnectTimeoutSeconds,
|
||||
imageURLReadTimeoutSeconds));
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Content of URL '{}' could not be read, will not add to message!", imageUrl, e);
|
||||
LOG.warn(
|
||||
"Content of URL '{}' could not be read, will not add to message!",
|
||||
imageUrl,
|
||||
e);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warn("Loading image from URL '{}' was interrupted, will not add to message!", imageUrl, e);
|
||||
LOG.warn(
|
||||
"Loading image from URL '{}' was interrupted, will not add to message!",
|
||||
imageUrl,
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OllamaChatResponseModel {
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Specific chat-API result that contains the chat history sent to the model and appends the answer as {@link OllamaChatResult} given by the
|
||||
* {@link OllamaChatMessageRole#ASSISTANT} role.
|
||||
@ -18,7 +25,8 @@ public class OllamaChatResult {
|
||||
|
||||
private final OllamaChatResponseModel responseModel;
|
||||
|
||||
public OllamaChatResult(OllamaChatResponseModel responseModel, List<OllamaChatMessage> chatHistory) {
|
||||
public OllamaChatResult(
|
||||
OllamaChatResponseModel responseModel, List<OllamaChatMessage> chatHistory) {
|
||||
this.chatHistory = chatHistory;
|
||||
this.responseModel = responseModel;
|
||||
appendAnswerToChatHistory(responseModel);
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaStreamHandler;
|
||||
@ -23,16 +31,15 @@ public class OllamaChatStreamObserver implements OllamaTokenHandler {
|
||||
boolean hasThinking = thinking != null && !thinking.isEmpty();
|
||||
boolean hasContent = !content.isEmpty();
|
||||
|
||||
// if (hasThinking && !hasContent) {
|
||||
//// message += thinking;
|
||||
// message = thinking;
|
||||
// } else {
|
||||
//// message += content;
|
||||
// message = content;
|
||||
// }
|
||||
//
|
||||
// responseStreamHandler.accept(message);
|
||||
|
||||
// if (hasThinking && !hasContent) {
|
||||
//// message += thinking;
|
||||
// message = thinking;
|
||||
// } else {
|
||||
//// message += content;
|
||||
// message = content;
|
||||
// }
|
||||
//
|
||||
// responseStreamHandler.accept(message);
|
||||
|
||||
if (!hasContent && hasThinking && thinkingStreamHandler != null) {
|
||||
// message = message + thinking;
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.chat;
|
||||
|
||||
import io.github.ollama4j.tools.OllamaToolCallsFunction;
|
||||
@ -11,6 +19,4 @@ import lombok.NoArgsConstructor;
|
||||
public class OllamaChatToolCalls {
|
||||
|
||||
private OllamaToolCallsFunction function;
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,14 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -1,26 +1,31 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OllamaEmbedRequestModel {
|
||||
@NonNull
|
||||
private String model;
|
||||
@NonNull private String model;
|
||||
|
||||
@NonNull
|
||||
private List<String> input;
|
||||
@NonNull private List<String> input;
|
||||
|
||||
private Map<String, Object> options;
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
@ -28,5 +36,4 @@ public class OllamaEmbeddingsRequestBuilder {
|
||||
this.request.setKeepAlive(keepAlive);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,27 +1,33 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.embeddings;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Deprecated(since = "1.0.90")
|
||||
public class OllamaEmbeddingsRequestModel {
|
||||
@NonNull
|
||||
private String model;
|
||||
@NonNull
|
||||
private String prompt;
|
||||
@NonNull private String model;
|
||||
@NonNull private String prompt;
|
||||
|
||||
protected Map<String, Object> options;
|
||||
|
||||
@JsonProperty(value = "keep_alive")
|
||||
private String keepAlive;
|
||||
|
||||
|
@ -1,13 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
|
||||
import io.github.ollama4j.models.request.OllamaCommonRequest;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class OllamaGenerateRequest extends OllamaCommonRequest implements OllamaRequestBody {
|
||||
@ -19,8 +25,7 @@ public class OllamaGenerateRequest extends OllamaCommonRequest implements Ollama
|
||||
private boolean raw;
|
||||
private boolean think;
|
||||
|
||||
public OllamaGenerateRequest() {
|
||||
}
|
||||
public OllamaGenerateRequest() {}
|
||||
|
||||
public OllamaGenerateRequest(String model, String prompt) {
|
||||
this.model = model;
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
@ -51,5 +59,4 @@ public class OllamaGenerateRequestBuilder {
|
||||
this.request.setKeepAlive(keepAlive);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,17 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -12,7 +20,8 @@ public class OllamaGenerateStreamObserver {
|
||||
|
||||
private String message = "";
|
||||
|
||||
public OllamaGenerateStreamObserver(OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) {
|
||||
public OllamaGenerateStreamObserver(
|
||||
OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) {
|
||||
this.responseStreamHandler = responseStreamHandler;
|
||||
this.thinkingStreamHandler = thinkingStreamHandler;
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
@ -1,8 +1,14 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.generate;
|
||||
|
||||
import io.github.ollama4j.models.chat.OllamaChatResponseModel;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface OllamaTokenHandler extends Consumer<OllamaChatResponseModel> {
|
||||
}
|
||||
public interface OllamaTokenHandler extends Consumer<OllamaChatResponseModel> {}
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.ps;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
public abstract class Auth {
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import java.util.Base64;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class CustomModelFileContentsRequest {
|
||||
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class CustomModelFilePathRequest {
|
||||
|
@ -1,15 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
|
@ -1,11 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class ModelRequest {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@ -7,9 +15,6 @@ import io.github.ollama4j.models.chat.*;
|
||||
import io.github.ollama4j.models.generate.OllamaTokenHandler;
|
||||
import io.github.ollama4j.models.response.OllamaErrorResponse;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -20,6 +25,8 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Specialization class for requests
|
||||
@ -52,11 +59,15 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
* @return TRUE, if ollama-Response has 'done' state
|
||||
*/
|
||||
@Override
|
||||
protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
protected boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
try {
|
||||
OllamaChatResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
// it seems that under heavy load ollama responds with an empty chat message part in the streamed response
|
||||
// thus, we null check the message and hope that the next streamed response has some message content again
|
||||
OllamaChatResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
// it seems that under heavy load ollama responds with an empty chat message part in the
|
||||
// streamed response
|
||||
// thus, we null check the message and hope that the next streamed response has some
|
||||
// message content again
|
||||
OllamaChatMessage message = ollamaResponseModel.getMessage();
|
||||
if (message != null) {
|
||||
if (message.getThinking() != null) {
|
||||
@ -81,14 +92,13 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
return callSync(body);
|
||||
}
|
||||
|
||||
public OllamaChatResult callSync(OllamaChatRequest body) throws OllamaBaseException, IOException, InterruptedException {
|
||||
public OllamaChatResult callSync(OllamaChatRequest body)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
// Create Request
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
URI uri = URI.create(getHost() + getEndpointSuffix());
|
||||
HttpRequest.Builder requestBuilder =
|
||||
getRequestBuilderDefault(uri)
|
||||
.POST(
|
||||
body.getBodyPublisher());
|
||||
getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
HttpRequest request = requestBuilder.build();
|
||||
LOG.debug("Asking model: {}", body);
|
||||
HttpResponse<InputStream> response =
|
||||
@ -101,7 +111,8 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
OllamaChatResponseModel ollamaChatResponseModel = null;
|
||||
List<OllamaChatToolCalls> wantedToolsForStream = null;
|
||||
try (BufferedReader reader =
|
||||
new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
|
||||
new BufferedReader(
|
||||
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
@ -114,22 +125,27 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller {
|
||||
LOG.warn("Status code: 401 (Unauthorized)");
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class);
|
||||
.readValue(
|
||||
"{\"error\":\"Unauthorized\"}",
|
||||
OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 400) {
|
||||
LOG.warn("Status code: 400 (Bad Request)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
|
||||
OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 500) {
|
||||
LOG.warn("Status code: 500 (Internal Server Error)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
|
||||
OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
ollamaChatResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
|
||||
boolean finished =
|
||||
parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
ollamaChatResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
|
||||
if (body.stream
|
||||
&& ollamaChatResponseModel.getMessage().getToolCalls() != null) {
|
||||
wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
|
||||
}
|
||||
if (finished && body.stream) {
|
||||
|
@ -1,32 +1,43 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public abstract class OllamaCommonRequest {
|
||||
|
||||
protected String model;
|
||||
|
||||
// @JsonSerialize(using = BooleanToJsonFormatFlagSerializer.class)
|
||||
// this can either be set to format=json or format={"key1": "val1", "key2": "val2"}
|
||||
// this can either be set to format=json or format={"key1": "val1", "key2": "val2"}
|
||||
@JsonProperty(value = "format", required = false, defaultValue = "json")
|
||||
protected Object format;
|
||||
|
||||
protected Map<String, Object> options;
|
||||
protected String template;
|
||||
protected boolean stream;
|
||||
|
||||
@JsonProperty(value = "keep_alive")
|
||||
protected String keepAlive;
|
||||
|
||||
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import io.github.ollama4j.utils.Constants;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.time.Duration;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Abstract helperclass to call the ollama api server.
|
||||
@ -25,8 +32,8 @@ public abstract class OllamaEndpointCaller {
|
||||
|
||||
protected abstract String getEndpointSuffix();
|
||||
|
||||
protected abstract boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer);
|
||||
|
||||
protected abstract boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer);
|
||||
|
||||
/**
|
||||
* Get default request builder.
|
||||
@ -37,7 +44,9 @@ public abstract class OllamaEndpointCaller {
|
||||
protected HttpRequest.Builder getRequestBuilderDefault(URI uri) {
|
||||
HttpRequest.Builder requestBuilder =
|
||||
HttpRequest.newBuilder(uri)
|
||||
.header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.timeout(Duration.ofSeconds(this.requestTimeoutSeconds));
|
||||
if (isAuthCredentialsSet()) {
|
||||
requestBuilder.header("Authorization", this.auth.getAuthHeaderValue());
|
||||
@ -53,5 +62,4 @@ public abstract class OllamaEndpointCaller {
|
||||
protected boolean isAuthCredentialsSet() {
|
||||
return this.auth != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.request;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
@ -9,9 +17,6 @@ import io.github.ollama4j.models.response.OllamaErrorResponse;
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -21,6 +26,8 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
@ -39,9 +46,11 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
protected boolean parseResponseAndAddToBuffer(
|
||||
String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
|
||||
try {
|
||||
OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
OllamaGenerateResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
if (ollamaResponseModel.getResponse() != null) {
|
||||
responseBuffer.append(ollamaResponseModel.getResponse());
|
||||
}
|
||||
@ -58,8 +67,13 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
}
|
||||
}
|
||||
|
||||
public OllamaResult call(OllamaRequestBody body, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException {
|
||||
responseStreamObserver = new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler);
|
||||
public OllamaResult call(
|
||||
OllamaRequestBody body,
|
||||
OllamaStreamHandler thinkingStreamHandler,
|
||||
OllamaStreamHandler responseStreamHandler)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
responseStreamObserver =
|
||||
new OllamaGenerateStreamObserver(thinkingStreamHandler, responseStreamHandler);
|
||||
return callSync(body);
|
||||
}
|
||||
|
||||
@ -73,40 +87,54 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
* @throws InterruptedException in case the server is not reachable or network issues happen
|
||||
*/
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public OllamaResult callSync(OllamaRequestBody body) throws OllamaBaseException, IOException, InterruptedException {
|
||||
public OllamaResult callSync(OllamaRequestBody body)
|
||||
throws OllamaBaseException, IOException, InterruptedException {
|
||||
// Create Request
|
||||
long startTime = System.currentTimeMillis();
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
URI uri = URI.create(getHost() + getEndpointSuffix());
|
||||
HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
HttpRequest.Builder requestBuilder =
|
||||
getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
|
||||
HttpRequest request = requestBuilder.build();
|
||||
LOG.debug("Asking model: {}", body);
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
HttpResponse<InputStream> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
|
||||
int statusCode = response.statusCode();
|
||||
InputStream responseBodyStream = response.body();
|
||||
StringBuilder responseBuffer = new StringBuilder();
|
||||
StringBuilder thinkingBuffer = new StringBuilder();
|
||||
OllamaGenerateResponseModel ollamaGenerateResponseModel = null;
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
|
||||
try (BufferedReader reader =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (statusCode == 404) {
|
||||
LOG.warn("Status code: 404 (Not Found)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 401) {
|
||||
LOG.warn("Status code: 401 (Unauthorized)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue(
|
||||
"{\"error\":\"Unauthorized\"}",
|
||||
OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else if (statusCode == 400) {
|
||||
LOG.warn("Status code: 400 (Bad Request)");
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
boolean finished =
|
||||
parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
|
||||
if (finished) {
|
||||
ollamaGenerateResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
ollamaGenerateResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaGenerateResponseModel.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -118,7 +146,12 @@ public class OllamaGenerateEndpointCaller extends OllamaEndpointCaller {
|
||||
throw new OllamaBaseException(responseBuffer.toString());
|
||||
} else {
|
||||
long endTime = System.currentTimeMillis();
|
||||
OllamaResult ollamaResult = new OllamaResult(responseBuffer.toString(), thinkingBuffer.toString(), endTime - startTime, statusCode);
|
||||
OllamaResult ollamaResult =
|
||||
new OllamaResult(
|
||||
responseBuffer.toString(),
|
||||
thinkingBuffer.toString(),
|
||||
endTime - startTime,
|
||||
statusCode);
|
||||
|
||||
ollamaResult.setModel(ollamaGenerateResponseModel.getModel());
|
||||
ollamaResult.setCreatedAt(ollamaGenerateResponseModel.getCreatedAt());
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LibraryModel {
|
||||
|
@ -1,8 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class LibraryModelDetail {
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,8 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ListModelsResponse {
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@ -14,16 +21,19 @@ public class Model {
|
||||
|
||||
private String name;
|
||||
private String model;
|
||||
|
||||
@JsonProperty("modified_at")
|
||||
private OffsetDateTime modifiedAt;
|
||||
|
||||
@JsonProperty("expires_at")
|
||||
private OffsetDateTime expiresAt;
|
||||
|
||||
private String digest;
|
||||
private long size;
|
||||
|
||||
@JsonProperty("details")
|
||||
private ModelMeta modelMeta;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the model name without its version
|
||||
*
|
||||
@ -45,10 +55,11 @@ public class Model {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@ -22,7 +30,9 @@ public class ModelDetail {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@ -27,7 +35,9 @@ public class ModelMeta {
|
||||
@Override
|
||||
public String toString() {
|
||||
try {
|
||||
return Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
|
||||
return Utils.getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
@ -5,11 +13,6 @@ import io.github.ollama4j.models.generate.OllamaGenerateRequest;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateResponseModel;
|
||||
import io.github.ollama4j.utils.Constants;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -19,6 +22,10 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ -31,32 +38,30 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
private String completeResponse;
|
||||
private String completeThinkingResponse;
|
||||
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the status of the request. Indicates if the request was successful or a
|
||||
* failure. If the request was a failure, the `getResponse()` method will return the error
|
||||
* message.
|
||||
*/
|
||||
@Getter
|
||||
private boolean succeeded;
|
||||
@Getter private boolean succeeded;
|
||||
|
||||
@Setter
|
||||
private long requestTimeoutSeconds;
|
||||
@Setter private long requestTimeoutSeconds;
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the HTTP response status code for the request that was made to Ollama
|
||||
* server.
|
||||
*/
|
||||
@Getter
|
||||
private int httpStatusCode;
|
||||
@Getter private int httpStatusCode;
|
||||
|
||||
/**
|
||||
* -- GETTER -- Returns the response time in milliseconds.
|
||||
*/
|
||||
@Getter
|
||||
private long responseTime = 0;
|
||||
@Getter private long responseTime = 0;
|
||||
|
||||
public OllamaAsyncResultStreamer(HttpRequest.Builder requestBuilder, OllamaGenerateRequest ollamaRequestModel, long requestTimeoutSeconds) {
|
||||
public OllamaAsyncResultStreamer(
|
||||
HttpRequest.Builder requestBuilder,
|
||||
OllamaGenerateRequest ollamaRequestModel,
|
||||
long requestTimeoutSeconds) {
|
||||
this.requestBuilder = requestBuilder;
|
||||
this.ollamaRequestModel = ollamaRequestModel;
|
||||
this.completeResponse = "";
|
||||
@ -70,25 +75,41 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
HttpRequest request = requestBuilder.POST(HttpRequest.BodyPublishers.ofString(Utils.getObjectMapper().writeValueAsString(ollamaRequestModel))).header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).timeout(Duration.ofSeconds(requestTimeoutSeconds)).build();
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
HttpRequest request =
|
||||
requestBuilder
|
||||
.POST(
|
||||
HttpRequest.BodyPublishers.ofString(
|
||||
Utils.getObjectMapper()
|
||||
.writeValueAsString(ollamaRequestModel)))
|
||||
.header(
|
||||
Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE,
|
||||
Constants.HttpConstants.APPLICATION_JSON)
|
||||
.timeout(Duration.ofSeconds(requestTimeoutSeconds))
|
||||
.build();
|
||||
HttpResponse<InputStream> response =
|
||||
httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
int statusCode = response.statusCode();
|
||||
this.httpStatusCode = statusCode;
|
||||
|
||||
InputStream responseBodyStream = response.body();
|
||||
BufferedReader reader = null;
|
||||
try {
|
||||
reader = new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8));
|
||||
reader =
|
||||
new BufferedReader(
|
||||
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8));
|
||||
String line;
|
||||
StringBuilder thinkingBuffer = new StringBuilder();
|
||||
StringBuilder responseBuffer = new StringBuilder();
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (statusCode == 404) {
|
||||
OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
OllamaErrorResponse ollamaResponseModel =
|
||||
Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
|
||||
responseStream.add(ollamaResponseModel.getError());
|
||||
responseBuffer.append(ollamaResponseModel.getError());
|
||||
} else {
|
||||
OllamaGenerateResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaGenerateResponseModel.class);
|
||||
OllamaGenerateResponseModel ollamaResponseModel =
|
||||
Utils.getObjectMapper()
|
||||
.readValue(line, OllamaGenerateResponseModel.class);
|
||||
String thinkingTokens = ollamaResponseModel.getThinking();
|
||||
String responseTokens = ollamaResponseModel.getResponse();
|
||||
if (thinkingTokens == null) {
|
||||
@ -134,5 +155,4 @@ public class OllamaAsyncResultStreamer extends Thread {
|
||||
this.completeResponse = "[FAILED] " + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
@ -1,16 +1,23 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
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 java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* The type Ollama result.
|
||||
@ -24,14 +31,17 @@ public class OllamaResult {
|
||||
* Get the completion/response text
|
||||
*/
|
||||
private final String response;
|
||||
|
||||
/**
|
||||
* Get the thinking text (if available)
|
||||
*/
|
||||
private final String thinking;
|
||||
|
||||
/**
|
||||
* Get the response status code.
|
||||
*/
|
||||
private int httpStatusCode;
|
||||
|
||||
/**
|
||||
* Get the response time in milliseconds.
|
||||
*/
|
||||
@ -75,7 +85,9 @@ public class OllamaResult {
|
||||
responseMap.put("promptEvalDuration", this.promptEvalDuration);
|
||||
responseMap.put("evalCount", this.evalCount);
|
||||
responseMap.put("evalDuration", this.evalDuration);
|
||||
return getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseMap);
|
||||
return getObjectMapper()
|
||||
.writerWithDefaultPrettyPrinter()
|
||||
.writeValueAsString(responseMap);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -95,17 +107,18 @@ public class OllamaResult {
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
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>>() {
|
||||
});
|
||||
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);
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,13 +139,14 @@ public class OllamaResult {
|
||||
|
||||
try {
|
||||
// Check if the response is a valid JSON
|
||||
if ((!responseStr.trim().startsWith("{") && !responseStr.trim().startsWith("[")) ||
|
||||
(!responseStr.trim().endsWith("}") && !responseStr.trim().endsWith("]"))) {
|
||||
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);
|
||||
throw new IllegalArgumentException(
|
||||
"Failed to parse response as JSON: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
@ -1,18 +1,25 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
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 java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static io.github.ollama4j.utils.Utils.getObjectMapper;
|
||||
|
||||
@Getter
|
||||
@SuppressWarnings("unused")
|
||||
@Data
|
||||
@ -58,9 +65,11 @@ public class OllamaStructuredResult {
|
||||
*/
|
||||
public Map<String, Object> getStructuredResponse() {
|
||||
try {
|
||||
Map<String, Object> response = getObjectMapper().readValue(this.getResponse(),
|
||||
new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
Map<String, Object> response =
|
||||
getObjectMapper()
|
||||
.readValue(
|
||||
this.getResponse(),
|
||||
new TypeReference<Map<String, Object>>() {});
|
||||
return response;
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.models.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ -22,7 +29,8 @@ public class OllamaToolsResult {
|
||||
return results;
|
||||
}
|
||||
for (Map.Entry<ToolFunctionCallSpec, Object> r : this.toolResults.entrySet()) {
|
||||
results.add(new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue()));
|
||||
results.add(
|
||||
new ToolResult(r.getKey().getName(), r.getKey().getArguments(), r.getValue()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Specification of a {@link ToolFunction} that provides the implementation via java reflection calling.
|
||||
@ -25,7 +32,8 @@ public class ReflectionalToolFunction implements ToolFunction {
|
||||
public Object apply(Map<String, Object> arguments) {
|
||||
LinkedHashMap<String, Object> argumentsCopy = new LinkedHashMap<>(this.propertyDefinition);
|
||||
for (Map.Entry<String, String> param : this.propertyDefinition.entrySet()) {
|
||||
argumentsCopy.replace(param.getKey(), typeCast(arguments.get(param.getKey()), param.getValue()));
|
||||
argumentsCopy.replace(
|
||||
param.getKey(), typeCast(arguments.get(param.getKey()), param.getValue()));
|
||||
}
|
||||
try {
|
||||
return function.invoke(functionHolder, argumentsCopy.values().toArray());
|
||||
@ -50,5 +58,4 @@ public class ReflectionalToolFunction implements ToolFunction {
|
||||
return inputValueString;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -1,11 +1,18 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@ -6,15 +14,14 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
public class Tools {
|
||||
@Data
|
||||
@ -62,11 +69,12 @@ public class Tools {
|
||||
public static class Property {
|
||||
private String type;
|
||||
private String description;
|
||||
|
||||
@JsonProperty("enum")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
private List<String> enumValues;
|
||||
@JsonIgnore
|
||||
private boolean required;
|
||||
|
||||
@JsonIgnore private boolean required;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +97,11 @@ public class Tools {
|
||||
private String promptText;
|
||||
|
||||
public String build() throws JsonProcessingException {
|
||||
return "[AVAILABLE_TOOLS] " + Utils.getObjectMapper().writeValueAsString(tools) + "[/AVAILABLE_TOOLS][INST] " + promptText + " [/INST]";
|
||||
return "[AVAILABLE_TOOLS] "
|
||||
+ Utils.getObjectMapper().writeValueAsString(tools)
|
||||
+ "[/AVAILABLE_TOOLS][INST] "
|
||||
+ promptText
|
||||
+ " [/INST]";
|
||||
}
|
||||
|
||||
public PromptBuilder withPrompt(String prompt) throws JsonProcessingException {
|
||||
@ -101,7 +113,8 @@ public class Tools {
|
||||
PromptFuncDefinition def = new PromptFuncDefinition();
|
||||
def.setType("function");
|
||||
|
||||
PromptFuncDefinition.PromptFuncSpec functionDetail = new PromptFuncDefinition.PromptFuncSpec();
|
||||
PromptFuncDefinition.PromptFuncSpec functionDetail =
|
||||
new PromptFuncDefinition.PromptFuncSpec();
|
||||
functionDetail.setName(spec.getFunctionName());
|
||||
functionDetail.setDescription(spec.getFunctionDescription());
|
||||
|
||||
@ -110,7 +123,8 @@ public class Tools {
|
||||
parameters.setProperties(spec.getToolPrompt().getFunction().parameters.getProperties());
|
||||
|
||||
List<String> requiredValues = new ArrayList<>();
|
||||
for (Map.Entry<String, PromptFuncDefinition.Property> p : spec.getToolPrompt().getFunction().getParameters().getProperties().entrySet()) {
|
||||
for (Map.Entry<String, PromptFuncDefinition.Property> p :
|
||||
spec.getToolPrompt().getFunction().getParameters().getProperties().entrySet()) {
|
||||
if (p.getValue().isRequired()) {
|
||||
requiredValues.add(p.getKey());
|
||||
}
|
||||
|
@ -1,7 +1,14 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
@ -1,7 +1,14 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.annotations;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
@ -1,15 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.tools.sampletools;
|
||||
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public class WeatherTool {
|
||||
private String paramCityName = "cityName";
|
||||
|
||||
public WeatherTool() {
|
||||
}
|
||||
public WeatherTool() {}
|
||||
|
||||
public String getCurrentWeather(Map<String, Object> arguments) {
|
||||
String city = (String) arguments.get(paramCityName);
|
||||
@ -20,14 +26,14 @@ public class WeatherTool {
|
||||
return Tools.ToolSpecification.builder()
|
||||
.functionName("weather-reporter")
|
||||
.functionDescription(
|
||||
"You are a tool who simply finds the city name from the user's message input/query about weather.")
|
||||
"You are a tool who simply finds the city name from the user's message"
|
||||
+ " input/query about weather.")
|
||||
.toolFunction(this::getCurrentWeather)
|
||||
.toolPrompt(
|
||||
Tools.PromptFuncDefinition.builder()
|
||||
.type("prompt")
|
||||
.function(
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec
|
||||
.builder()
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec.builder()
|
||||
.name("get-city-name")
|
||||
.description("Get the city name")
|
||||
.parameters(
|
||||
@ -37,15 +43,24 @@ public class WeatherTool {
|
||||
.properties(
|
||||
Map.of(
|
||||
paramCityName,
|
||||
Tools.PromptFuncDefinition.Property
|
||||
Tools
|
||||
.PromptFuncDefinition
|
||||
.Property
|
||||
.builder()
|
||||
.type("string")
|
||||
.type(
|
||||
"string")
|
||||
.description(
|
||||
"The name of the city. e.g. Bengaluru")
|
||||
.required(true)
|
||||
"The name"
|
||||
+ " of the"
|
||||
+ " city."
|
||||
+ " e.g."
|
||||
+ " Bengaluru")
|
||||
.required(
|
||||
true)
|
||||
.build()))
|
||||
.required(java.util.List
|
||||
.of(paramCityName))
|
||||
.required(
|
||||
java.util.List.of(
|
||||
paramCityName))
|
||||
.build())
|
||||
.build())
|
||||
.build())
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.types;
|
||||
|
||||
/**
|
||||
|
@ -1,15 +1,23 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BooleanToJsonFormatFlagSerializer extends JsonSerializer<Boolean> {
|
||||
|
||||
@Override
|
||||
public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
|
||||
public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers)
|
||||
throws IOException {
|
||||
gen.writeString("json");
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
public final class Constants {
|
||||
public static final class HttpConstants {
|
||||
private HttpConstants() {
|
||||
}
|
||||
private HttpConstants() {}
|
||||
|
||||
public static final String APPLICATION_JSON = "application/json";
|
||||
public static final String APPLICATION_XML = "application/xml";
|
||||
|
@ -1,9 +1,16 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
@ -11,7 +18,9 @@ import java.util.Collection;
|
||||
public class FileToBase64Serializer extends JsonSerializer<Collection<byte[]>> {
|
||||
|
||||
@Override
|
||||
public void serialize(Collection<byte[]> value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
|
||||
public void serialize(
|
||||
Collection<byte[]> value, JsonGenerator jsonGenerator, SerializerProvider serializers)
|
||||
throws IOException {
|
||||
jsonGenerator.writeStartArray();
|
||||
for (byte[] file : value) {
|
||||
jsonGenerator.writeString(Base64.getEncoder().encodeToString(file));
|
||||
|
@ -1,8 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import java.net.http.HttpRequest.BodyPublisher;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
|
||||
@ -19,8 +26,7 @@ public interface OllamaRequestBody {
|
||||
@JsonIgnore
|
||||
default BodyPublisher getBodyPublisher() {
|
||||
try {
|
||||
return BodyPublishers.ofString(
|
||||
Utils.getObjectMapper().writeValueAsString(this));
|
||||
return BodyPublishers.ofString(Utils.getObjectMapper().writeValueAsString(this));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new IllegalArgumentException("Request not Body convertible.", e);
|
||||
}
|
||||
|
@ -1,8 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Class for options for Ollama model.
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -230,15 +238,16 @@ public class OptionsBuilder {
|
||||
* @return The updated OptionsBuilder.
|
||||
* @throws IllegalArgumentException if parameter has an unsupported type
|
||||
*/
|
||||
public OptionsBuilder setCustomOption(String name, Object value) throws IllegalArgumentException {
|
||||
public OptionsBuilder setCustomOption(String name, Object value)
|
||||
throws IllegalArgumentException {
|
||||
if (!(value instanceof Integer || value instanceof Float || value instanceof String)) {
|
||||
throw new IllegalArgumentException("Invalid type for parameter. Allowed types are: Integer, Float, or String.");
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid type for parameter. Allowed types are: Integer, Float, or String.");
|
||||
}
|
||||
options.getOptionsMap().put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the options map.
|
||||
*
|
||||
@ -247,6 +256,4 @@ public class OptionsBuilder {
|
||||
public Options build() {
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,3 +1,11 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
/**
|
||||
|
@ -1,10 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@ -13,6 +18,8 @@ import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class Utils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
|
||||
@ -27,26 +34,40 @@ public class Utils {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
public static byte[] loadImageBytesFromUrl(String imageUrl, int connectTimeoutSeconds, int readTimeoutSeconds)
|
||||
public static byte[] loadImageBytesFromUrl(
|
||||
String imageUrl, int connectTimeoutSeconds, int readTimeoutSeconds)
|
||||
throws IOException, InterruptedException {
|
||||
LOG.debug("Attempting to load image from URL: {} (connectTimeout={}s, readTimeout={}s)", imageUrl, connectTimeoutSeconds, readTimeoutSeconds);
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
LOG.debug(
|
||||
"Attempting to load image from URL: {} (connectTimeout={}s, readTimeout={}s)",
|
||||
imageUrl,
|
||||
connectTimeoutSeconds,
|
||||
readTimeoutSeconds);
|
||||
HttpClient client =
|
||||
HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(connectTimeoutSeconds))
|
||||
.build();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
HttpRequest request =
|
||||
HttpRequest.newBuilder()
|
||||
.uri(URI.create(imageUrl))
|
||||
.timeout(Duration.ofSeconds(readTimeoutSeconds))
|
||||
.header("User-Agent", "Mozilla/5.0")
|
||||
.GET()
|
||||
.build();
|
||||
LOG.debug("Sending HTTP GET request to {}", imageUrl);
|
||||
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
HttpResponse<byte[]> response =
|
||||
client.send(request, HttpResponse.BodyHandlers.ofByteArray());
|
||||
LOG.debug("Received HTTP response with status code: {}", response.statusCode());
|
||||
if (response.statusCode() >= 200 && response.statusCode() < 300) {
|
||||
LOG.debug("Successfully loaded image from URL: {} ({} bytes)", imageUrl, response.body().length);
|
||||
LOG.debug(
|
||||
"Successfully loaded image from URL: {} ({} bytes)",
|
||||
imageUrl,
|
||||
response.body().length);
|
||||
return response.body();
|
||||
} else {
|
||||
LOG.error("Failed to load image from URL: {}. HTTP status: {}", imageUrl, response.statusCode());
|
||||
LOG.error(
|
||||
"Failed to load image from URL: {}. HTTP status: {}",
|
||||
imageUrl,
|
||||
response.statusCode());
|
||||
throw new IOException("Failed to load image: HTTP " + response.statusCode());
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,28 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import io.github.ollama4j.samples.AnnotatedTool;
|
||||
import io.github.ollama4j.tools.annotations.OllamaToolService;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
import org.junit.jupiter.api.Order;
|
||||
@ -19,20 +37,14 @@ import org.testcontainers.ollama.OllamaContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
import org.testcontainers.utility.MountableFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@OllamaToolService(providers = {AnnotatedTool.class})
|
||||
@TestMethodOrder(OrderAnnotation.class)
|
||||
@SuppressWarnings({"HttpUrlsUsage", "SpellCheckingInspection", "resource", "ResultOfMethodCallIgnored"})
|
||||
@SuppressWarnings({
|
||||
"HttpUrlsUsage",
|
||||
"SpellCheckingInspection",
|
||||
"resource",
|
||||
"ResultOfMethodCallIgnored"
|
||||
})
|
||||
public class WithAuth {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WithAuth.class);
|
||||
@ -42,8 +54,7 @@ public class WithAuth {
|
||||
private static final String NGINX_VERSION = "nginx:1.23.4-alpine";
|
||||
private static final String BEARER_AUTH_TOKEN = "secret-token";
|
||||
private static final String GENERAL_PURPOSE_MODEL = "gemma3:270m";
|
||||
// private static final String THINKING_MODEL = "gpt-oss:20b";
|
||||
|
||||
// private static final String THINKING_MODEL = "gpt-oss:20b";
|
||||
|
||||
private static OllamaContainer ollama;
|
||||
private static GenericContainer<?> nginx;
|
||||
@ -63,43 +74,48 @@ public class WithAuth {
|
||||
api.setRequestTimeoutSeconds(120);
|
||||
api.setNumberOfRetriesForModelPull(3);
|
||||
|
||||
String ollamaUrl = "http://" + ollama.getHost() + ":" + ollama.getMappedPort(OLLAMA_INTERNAL_PORT);
|
||||
String ollamaUrl =
|
||||
"http://" + ollama.getHost() + ":" + ollama.getMappedPort(OLLAMA_INTERNAL_PORT);
|
||||
String nginxUrl = "http://" + nginx.getHost() + ":" + nginx.getMappedPort(NGINX_PORT);
|
||||
LOG.info(
|
||||
"The Ollama service is now accessible via the Nginx proxy with bearer-auth authentication mode.\n" +
|
||||
"→ Ollama URL: {}\n" +
|
||||
"→ Proxy URL: {}",
|
||||
ollamaUrl, nginxUrl
|
||||
);
|
||||
"The Ollama service is now accessible via the Nginx proxy with bearer-auth"
|
||||
+ " authentication mode.\n"
|
||||
+ "→ Ollama URL: {}\n"
|
||||
+ "→ Proxy URL: {}",
|
||||
ollamaUrl,
|
||||
nginxUrl);
|
||||
LOG.info("OllamaAPI initialized with bearer auth token: {}", BEARER_AUTH_TOKEN);
|
||||
}
|
||||
|
||||
private static OllamaContainer createOllamaContainer() {
|
||||
return new OllamaContainer("ollama/ollama:" + OLLAMA_VERSION).withExposedPorts(OLLAMA_INTERNAL_PORT);
|
||||
return new OllamaContainer("ollama/ollama:" + OLLAMA_VERSION)
|
||||
.withExposedPorts(OLLAMA_INTERNAL_PORT);
|
||||
}
|
||||
|
||||
private static String generateNginxConfig(int ollamaPort) {
|
||||
return String.format("events {}\n" +
|
||||
"\n" +
|
||||
"http {\n" +
|
||||
" server {\n" +
|
||||
" listen 80;\n" +
|
||||
"\n" +
|
||||
" location / {\n" +
|
||||
" set $auth_header $http_authorization;\n" +
|
||||
"\n" +
|
||||
" if ($auth_header != \"Bearer secret-token\") {\n" +
|
||||
" return 401;\n" +
|
||||
" }\n" +
|
||||
"\n" +
|
||||
" proxy_pass http://host.docker.internal:%s/;\n" +
|
||||
" proxy_set_header Host $host;\n" +
|
||||
" proxy_set_header X-Real-IP $remote_addr;\n" +
|
||||
" proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n" +
|
||||
" proxy_set_header X-Forwarded-Proto $scheme;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}\n", ollamaPort);
|
||||
return String.format(
|
||||
"events {}\n"
|
||||
+ "\n"
|
||||
+ "http {\n"
|
||||
+ " server {\n"
|
||||
+ " listen 80;\n"
|
||||
+ "\n"
|
||||
+ " location / {\n"
|
||||
+ " set $auth_header $http_authorization;\n"
|
||||
+ "\n"
|
||||
+ " if ($auth_header != \"Bearer secret-token\") {\n"
|
||||
+ " return 401;\n"
|
||||
+ " }\n"
|
||||
+ "\n"
|
||||
+ " proxy_pass http://host.docker.internal:%s/;\n"
|
||||
+ " proxy_set_header Host $host;\n"
|
||||
+ " proxy_set_header X-Real-IP $remote_addr;\n"
|
||||
+ " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"
|
||||
+ " proxy_set_header X-Forwarded-Proto $scheme;\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
+ "}\n",
|
||||
ollamaPort);
|
||||
}
|
||||
|
||||
public static GenericContainer<?> createNginxContainer(int ollamaPort) {
|
||||
@ -117,14 +133,12 @@ public class WithAuth {
|
||||
.withExposedPorts(NGINX_PORT)
|
||||
.withCopyFileToContainer(
|
||||
MountableFile.forHostPath(nginxConf.getAbsolutePath()),
|
||||
"/etc/nginx/nginx.conf"
|
||||
)
|
||||
"/etc/nginx/nginx.conf")
|
||||
.withExtraHost("host.docker.internal", "host-gateway")
|
||||
.waitingFor(
|
||||
Wait.forHttp("/")
|
||||
.forStatusCode(401)
|
||||
.withStartupTimeout(Duration.ofSeconds(30))
|
||||
);
|
||||
.withStartupTimeout(Duration.ofSeconds(30)));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to create nginx.conf", e);
|
||||
}
|
||||
@ -134,14 +148,18 @@ public class WithAuth {
|
||||
@Order(1)
|
||||
void testOllamaBehindProxy() {
|
||||
api.setBearerAuth(BEARER_AUTH_TOKEN);
|
||||
assertTrue(api.ping(), "Expected OllamaAPI to successfully ping through NGINX with valid auth token.");
|
||||
assertTrue(
|
||||
api.ping(),
|
||||
"Expected OllamaAPI to successfully ping through NGINX with valid auth token.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
void testWithWrongToken() {
|
||||
api.setBearerAuth("wrong-token");
|
||||
assertFalse(api.ping(), "Expected OllamaAPI ping to fail through NGINX with an invalid auth token.");
|
||||
assertFalse(
|
||||
api.ping(),
|
||||
"Expected OllamaAPI ping to fail through NGINX with an invalid auth token.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -152,13 +170,19 @@ public class WithAuth {
|
||||
String model = GENERAL_PURPOSE_MODEL;
|
||||
api.pullModel(model);
|
||||
|
||||
String prompt = "The sun is shining brightly and is directly overhead at the zenith, casting my shadow over my foot, so it must be noon.";
|
||||
String prompt =
|
||||
"The sun is shining brightly and is directly overhead at the zenith, casting my"
|
||||
+ " shadow over my foot, so it must be noon.";
|
||||
|
||||
Map<String, Object> format = new HashMap<>();
|
||||
format.put("type", "object");
|
||||
format.put("properties", new HashMap<String, Object>() {
|
||||
format.put(
|
||||
"properties",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("isNoon", new HashMap<String, Object>() {
|
||||
put(
|
||||
"isNoon",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("type", "boolean");
|
||||
}
|
||||
|
@ -1,21 +1,35 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.samples;
|
||||
|
||||
import io.github.ollama4j.tools.annotations.ToolProperty;
|
||||
import io.github.ollama4j.tools.annotations.ToolSpec;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class AnnotatedTool {
|
||||
|
||||
@ToolSpec(desc = "Computes the most important constant all around the globe!")
|
||||
public String computeImportantConstant(@ToolProperty(name = "noOfDigits", desc = "Number of digits that shall be returned") Integer noOfDigits) {
|
||||
public String computeImportantConstant(
|
||||
@ToolProperty(name = "noOfDigits", desc = "Number of digits that shall be returned")
|
||||
Integer noOfDigits) {
|
||||
return BigDecimal.valueOf((long) (Math.random() * 1000000L), noOfDigits).toString();
|
||||
}
|
||||
|
||||
@ToolSpec(desc = "Says hello to a friend!")
|
||||
public String sayHello(@ToolProperty(name = "name", desc = "Name of the friend") String name, @ToolProperty(name = "numberOfHearts", desc = "number of heart emojis that should be used", required = false) Integer numberOfHearts) {
|
||||
public String sayHello(
|
||||
@ToolProperty(name = "name", desc = "Name of the friend") String name,
|
||||
@ToolProperty(
|
||||
name = "numberOfHearts",
|
||||
desc = "number of heart emojis that should be used",
|
||||
required = false)
|
||||
Integer numberOfHearts) {
|
||||
String hearts = numberOfHearts != null ? "♡".repeat(numberOfHearts) : "";
|
||||
return "Hello, " + name + "! " + hearts;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,31 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.tools.annotations.OllamaToolService;
|
||||
import io.github.ollama4j.tools.annotations.ToolProperty;
|
||||
import io.github.ollama4j.tools.annotations.ToolSpec;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestAnnotations {
|
||||
|
||||
@OllamaToolService(providers = {SampleProvider.class})
|
||||
static class SampleToolService {
|
||||
}
|
||||
static class SampleToolService {}
|
||||
|
||||
static class SampleProvider {
|
||||
@ToolSpec(name = "sum", desc = "adds two numbers")
|
||||
public int sum(@ToolProperty(name = "a", desc = "first addend") int a,
|
||||
public int sum(
|
||||
@ToolProperty(name = "a", desc = "first addend") int a,
|
||||
@ToolProperty(name = "b", desc = "second addend", required = false) int b) {
|
||||
return a + b;
|
||||
}
|
||||
@ -28,7 +35,7 @@ class TestAnnotations {
|
||||
void testOllamaToolServiceProvidersPresent() throws Exception {
|
||||
OllamaToolService ann = SampleToolService.class.getAnnotation(OllamaToolService.class);
|
||||
assertNotNull(ann);
|
||||
assertArrayEquals(new Class<?>[]{SampleProvider.class}, ann.providers());
|
||||
assertArrayEquals(new Class<?>[] {SampleProvider.class}, ann.providers());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,12 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.github.ollama4j.models.request.BasicAuth;
|
||||
import io.github.ollama4j.models.request.BearerAuth;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TestAuth {
|
||||
|
||||
@Test
|
||||
|
@ -1,5 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@ -8,8 +18,6 @@ import io.github.ollama4j.utils.BooleanToJsonFormatFlagSerializer;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TestBooleanToJsonFormatFlagSerializer {
|
||||
|
||||
static class Holder {
|
||||
|
@ -1,15 +1,22 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import io.github.ollama4j.utils.FileToBase64Serializer;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TestFileToBase64Serializer {
|
||||
|
||||
|
@ -1,5 +1,17 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import io.github.ollama4j.OllamaAPI;
|
||||
import io.github.ollama4j.exceptions.OllamaBaseException;
|
||||
import io.github.ollama4j.exceptions.RoleNotFoundException;
|
||||
@ -12,18 +24,13 @@ import io.github.ollama4j.models.response.OllamaAsyncResultStreamer;
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import io.github.ollama4j.types.OllamaModelType;
|
||||
import io.github.ollama4j.utils.OptionsBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
class TestMockedAPIs {
|
||||
@Test
|
||||
@ -54,7 +61,12 @@ class TestMockedAPIs {
|
||||
@Test
|
||||
void testCreateModel() {
|
||||
OllamaAPI ollamaAPI = Mockito.mock(OllamaAPI.class);
|
||||
CustomModelRequest customModelRequest = CustomModelRequest.builder().model("mario").from("llama3.2:latest").system("You are Mario from Super Mario Bros.").build();
|
||||
CustomModelRequest customModelRequest =
|
||||
CustomModelRequest.builder()
|
||||
.model("mario")
|
||||
.from("llama3.2:latest")
|
||||
.system("You are Mario from Super Mario Bros.")
|
||||
.build();
|
||||
try {
|
||||
doNothing().when(ollamaAPI).createModel(customModelRequest);
|
||||
ollamaAPI.createModel(customModelRequest);
|
||||
@ -128,7 +140,8 @@ class TestMockedAPIs {
|
||||
String model = OllamaModelType.LLAMA2;
|
||||
List<String> inputs = List.of("some prompt text");
|
||||
try {
|
||||
when(ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs))).thenReturn(new OllamaEmbedResponseModel());
|
||||
when(ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs)))
|
||||
.thenReturn(new OllamaEmbedResponseModel());
|
||||
ollamaAPI.embed(new OllamaEmbedRequestModel(model, inputs));
|
||||
verify(ollamaAPI, times(1)).embed(new OllamaEmbedRequestModel(model, inputs));
|
||||
} catch (IOException | OllamaBaseException | InterruptedException e) {
|
||||
@ -146,7 +159,8 @@ class TestMockedAPIs {
|
||||
when(ollamaAPI.generate(model, prompt, false, false, optionsBuilder.build()))
|
||||
.thenReturn(new OllamaResult("", "", 0, 200));
|
||||
ollamaAPI.generate(model, prompt, false, false, optionsBuilder.build());
|
||||
verify(ollamaAPI, times(1)).generate(model, prompt, false, false, optionsBuilder.build());
|
||||
verify(ollamaAPI, times(1))
|
||||
.generate(model, prompt, false, false, optionsBuilder.build());
|
||||
} catch (IOException | OllamaBaseException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -159,13 +173,28 @@ class TestMockedAPIs {
|
||||
String prompt = "some prompt text";
|
||||
try {
|
||||
when(ollamaAPI.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null))
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null))
|
||||
.thenReturn(new OllamaResult("", "", 0, 200));
|
||||
ollamaAPI.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null);
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null);
|
||||
verify(ollamaAPI, times(1))
|
||||
.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null);
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -178,13 +207,28 @@ class TestMockedAPIs {
|
||||
String prompt = "some prompt text";
|
||||
try {
|
||||
when(ollamaAPI.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null))
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null))
|
||||
.thenReturn(new OllamaResult("", "", 0, 200));
|
||||
ollamaAPI.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null);
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null);
|
||||
verify(ollamaAPI, times(1))
|
||||
.generateWithImages(
|
||||
model, prompt, Collections.emptyList(), new OptionsBuilder().build(), null, null);
|
||||
model,
|
||||
prompt,
|
||||
Collections.emptyList(),
|
||||
new OptionsBuilder().build(),
|
||||
null,
|
||||
null);
|
||||
} catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -229,7 +273,8 @@ class TestMockedAPIs {
|
||||
OllamaAPI ollamaAPI = mock(OllamaAPI.class);
|
||||
String roleName = "non-existing-role";
|
||||
try {
|
||||
when(ollamaAPI.getRole(roleName)).thenThrow(new RoleNotFoundException("Role not found"));
|
||||
when(ollamaAPI.getRole(roleName))
|
||||
.thenThrow(new RoleNotFoundException("Role not found"));
|
||||
} catch (RoleNotFoundException exception) {
|
||||
throw new RuntimeException("Failed to run test: testGetRoleNotFound");
|
||||
}
|
||||
|
@ -1,23 +1,33 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.github.ollama4j.models.chat.OllamaChatMessage;
|
||||
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TestOllamaChatMessage {
|
||||
|
||||
@Test
|
||||
void testToStringProducesJson() {
|
||||
OllamaChatMessage msg = new OllamaChatMessage(OllamaChatMessageRole.USER, "hello", null, null, null);
|
||||
OllamaChatMessage msg =
|
||||
new OllamaChatMessage(OllamaChatMessageRole.USER, "hello", null, null, null);
|
||||
String json = msg.toString();
|
||||
JSONObject obj = new JSONObject(json);
|
||||
assertEquals("user", obj.getString("role"));
|
||||
assertEquals("hello", obj.getString("content"));
|
||||
assertTrue(obj.has("tool_calls"));
|
||||
// thinking and images may or may not be present depending on null handling, just ensure no exception
|
||||
// thinking and images may or may not be present depending on null handling, just ensure no
|
||||
// exception
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.exceptions.RoleNotFoundException;
|
||||
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestOllamaChatMessageRole {
|
||||
|
||||
@ -33,12 +40,14 @@ class TestOllamaChatMessageRole {
|
||||
void testCustomRoleCreationAndLookup() throws Exception {
|
||||
OllamaChatMessageRole custom = OllamaChatMessageRole.newCustomRole("myrole");
|
||||
assertEquals("myrole", custom.toString());
|
||||
// custom roles are registered globally (per current implementation), so lookup should succeed
|
||||
// custom roles are registered globally (per current implementation), so lookup should
|
||||
// succeed
|
||||
assertSame(custom, OllamaChatMessageRole.getRole("myrole"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRoleThrowsOnUnknown() {
|
||||
assertThrows(RoleNotFoundException.class, () -> OllamaChatMessageRole.getRole("does-not-exist"));
|
||||
assertThrows(
|
||||
RoleNotFoundException.class, () -> OllamaChatMessageRole.getRole("does-not-exist"));
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,28 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.models.chat.OllamaChatMessage;
|
||||
import io.github.ollama4j.models.chat.OllamaChatMessageRole;
|
||||
import io.github.ollama4j.models.chat.OllamaChatRequest;
|
||||
import io.github.ollama4j.models.chat.OllamaChatRequestBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestOllamaChatRequestBuilder {
|
||||
|
||||
@Test
|
||||
void testResetClearsMessagesButKeepsModelAndThink() {
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("my-model")
|
||||
OllamaChatRequestBuilder builder =
|
||||
OllamaChatRequestBuilder.getInstance("my-model")
|
||||
.withThinking(true)
|
||||
.withMessage(OllamaChatMessageRole.USER, "first");
|
||||
|
||||
@ -33,17 +41,22 @@ class TestOllamaChatRequestBuilder {
|
||||
|
||||
@Test
|
||||
void testImageUrlFailuresAreIgnoredAndDoNotBreakBuild() {
|
||||
// Provide a syntactically invalid URL, but catch the expected exception to verify builder robustness
|
||||
// Provide a syntactically invalid URL, but catch the expected exception to verify builder
|
||||
// robustness
|
||||
OllamaChatRequestBuilder builder = OllamaChatRequestBuilder.getInstance("m");
|
||||
try {
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "hi", Collections.emptyList(),
|
||||
builder.withMessage(
|
||||
OllamaChatMessageRole.USER,
|
||||
"hi",
|
||||
Collections.emptyList(),
|
||||
"ht!tp://invalid url \n not a uri");
|
||||
fail("Expected IllegalArgumentException due to malformed URL");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected: malformed URL should throw IllegalArgumentException
|
||||
}
|
||||
// The builder should still be usable after the exception
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "hello", Collections.emptyList())
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "hello", Collections.emptyList())
|
||||
.build();
|
||||
|
||||
assertNotNull(req.getMessages());
|
||||
|
@ -1,15 +1,22 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import io.github.ollama4j.utils.OllamaRequestBody;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.Flow;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestOllamaRequestBody {
|
||||
|
||||
@ -30,7 +37,8 @@ class TestOllamaRequestBody {
|
||||
var publisher = req.getBodyPublisher();
|
||||
|
||||
StringBuilder data = new StringBuilder();
|
||||
publisher.subscribe(new Flow.Subscriber<>() {
|
||||
publisher.subscribe(
|
||||
new Flow.Subscriber<>() {
|
||||
@Override
|
||||
public void onSubscribe(Flow.Subscription subscription) {
|
||||
subscription.request(Long.MAX_VALUE);
|
||||
@ -42,17 +50,16 @@ class TestOllamaRequestBody {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
}
|
||||
public void onError(Throwable throwable) {}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
public void onComplete() {}
|
||||
});
|
||||
|
||||
// Trigger the publishing by converting it to a string via the same mapper for determinism
|
||||
String expected = Utils.getObjectMapper().writeValueAsString(req);
|
||||
// Due to asynchronous nature, expected content already delivered synchronously by StringPublisher
|
||||
// Due to asynchronous nature, expected content already delivered synchronously by
|
||||
// StringPublisher
|
||||
assertEquals(expected, data.toString());
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,22 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.models.response.OllamaResult;
|
||||
import io.github.ollama4j.tools.OllamaToolsResult;
|
||||
import io.github.ollama4j.tools.ToolFunctionCallSpec;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TestOllamaToolsResult {
|
||||
|
||||
|
@ -1,21 +1,29 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.utils.Options;
|
||||
import io.github.ollama4j.utils.OptionsBuilder;
|
||||
import io.github.ollama4j.utils.PromptBuilder;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestOptionsAndUtils {
|
||||
|
||||
@Test
|
||||
void testOptionsBuilderSetsValues() {
|
||||
Options options = new OptionsBuilder()
|
||||
Options options =
|
||||
new OptionsBuilder()
|
||||
.setMirostat(1)
|
||||
.setMirostatEta(0.2f)
|
||||
.setMirostatTau(4.5f)
|
||||
@ -60,19 +68,22 @@ class TestOptionsAndUtils {
|
||||
@Test
|
||||
void testOptionsBuilderRejectsUnsupportedCustomType() {
|
||||
OptionsBuilder builder = new OptionsBuilder();
|
||||
assertThrows(IllegalArgumentException.class, () -> builder.setCustomOption("bad", new Object()));
|
||||
assertThrows(
|
||||
IllegalArgumentException.class, () -> builder.setCustomOption("bad", new Object()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPromptBuilderBuildsExpectedString() {
|
||||
String prompt = new PromptBuilder()
|
||||
String prompt =
|
||||
new PromptBuilder()
|
||||
.add("Hello")
|
||||
.addLine(", world!")
|
||||
.addSeparator()
|
||||
.add("Continue.")
|
||||
.build();
|
||||
|
||||
String expected = "Hello, world!\n\n--------------------------------------------------\nContinue.";
|
||||
String expected =
|
||||
"Hello, world!\n\n--------------------------------------------------\nContinue.";
|
||||
assertEquals(expected, prompt);
|
||||
}
|
||||
|
||||
@ -80,7 +91,8 @@ class TestOptionsAndUtils {
|
||||
void testUtilsGetObjectMapperSingletonAndModule() {
|
||||
assertSame(Utils.getObjectMapper(), Utils.getObjectMapper());
|
||||
// Basic serialization sanity check with JavaTimeModule registered
|
||||
assertDoesNotThrow(() -> Utils.getObjectMapper().writeValueAsString(java.time.OffsetDateTime.now()));
|
||||
assertDoesNotThrow(
|
||||
() -> Utils.getObjectMapper().writeValueAsString(java.time.OffsetDateTime.now()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,14 +1,21 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import io.github.ollama4j.tools.ReflectionalToolFunction;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.tools.ReflectionalToolFunction;
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestReflectionalToolFunction {
|
||||
|
||||
@ -25,7 +32,9 @@ class TestReflectionalToolFunction {
|
||||
@Test
|
||||
void testApplyInvokesMethodWithTypeCasting() throws Exception {
|
||||
SampleToolHolder holder = new SampleToolHolder();
|
||||
Method method = SampleToolHolder.class.getMethod("combine", Integer.class, Boolean.class, BigDecimal.class, String.class);
|
||||
Method method =
|
||||
SampleToolHolder.class.getMethod(
|
||||
"combine", Integer.class, Boolean.class, BigDecimal.class, String.class);
|
||||
|
||||
LinkedHashMap<String, String> propDef = new LinkedHashMap<>();
|
||||
// preserve order to match method parameters
|
||||
@ -36,7 +45,8 @@ class TestReflectionalToolFunction {
|
||||
|
||||
ReflectionalToolFunction fn = new ReflectionalToolFunction(holder, method, propDef);
|
||||
|
||||
Map<String, Object> args = Map.of(
|
||||
Map<String, Object> args =
|
||||
Map.of(
|
||||
"i", "42",
|
||||
"b", "true",
|
||||
"d", "3.14",
|
||||
@ -50,7 +60,9 @@ class TestReflectionalToolFunction {
|
||||
@Test
|
||||
void testTypeCastNullsWhenClassOrValueIsNull() throws Exception {
|
||||
SampleToolHolder holder = new SampleToolHolder();
|
||||
Method method = SampleToolHolder.class.getMethod("combine", Integer.class, Boolean.class, BigDecimal.class, String.class);
|
||||
Method method =
|
||||
SampleToolHolder.class.getMethod(
|
||||
"combine", Integer.class, Boolean.class, BigDecimal.class, String.class);
|
||||
|
||||
LinkedHashMap<String, String> propDef = new LinkedHashMap<>();
|
||||
propDef.put("i", null); // className null -> expect null passed
|
||||
|
@ -1,13 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.tools.ToolFunction;
|
||||
import io.github.ollama4j.tools.ToolRegistry;
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestToolRegistry {
|
||||
|
||||
@ -16,7 +23,8 @@ class TestToolRegistry {
|
||||
ToolRegistry registry = new ToolRegistry();
|
||||
ToolFunction fn = args -> "ok:" + args.get("x");
|
||||
|
||||
Tools.ToolSpecification spec = Tools.ToolSpecification.builder()
|
||||
Tools.ToolSpecification spec =
|
||||
Tools.ToolSpecification.builder()
|
||||
.functionName("test")
|
||||
.functionDescription("desc")
|
||||
.toolFunction(fn)
|
||||
|
@ -1,54 +1,65 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import io.github.ollama4j.tools.Tools;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TestToolsPromptBuilder {
|
||||
|
||||
@Test
|
||||
void testPromptBuilderIncludesToolsAndPrompt() throws JsonProcessingException {
|
||||
Tools.PromptFuncDefinition.Property cityProp = Tools.PromptFuncDefinition.Property.builder()
|
||||
Tools.PromptFuncDefinition.Property cityProp =
|
||||
Tools.PromptFuncDefinition.Property.builder()
|
||||
.type("string")
|
||||
.description("city name")
|
||||
.required(true)
|
||||
.build();
|
||||
|
||||
Tools.PromptFuncDefinition.Property unitsProp = Tools.PromptFuncDefinition.Property.builder()
|
||||
Tools.PromptFuncDefinition.Property unitsProp =
|
||||
Tools.PromptFuncDefinition.Property.builder()
|
||||
.type("string")
|
||||
.description("units")
|
||||
.enumValues(List.of("metric", "imperial"))
|
||||
.required(false)
|
||||
.build();
|
||||
|
||||
Tools.PromptFuncDefinition.Parameters params = Tools.PromptFuncDefinition.Parameters.builder()
|
||||
Tools.PromptFuncDefinition.Parameters params =
|
||||
Tools.PromptFuncDefinition.Parameters.builder()
|
||||
.type("object")
|
||||
.properties(Map.of("city", cityProp, "units", unitsProp))
|
||||
.build();
|
||||
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec spec = Tools.PromptFuncDefinition.PromptFuncSpec.builder()
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec spec =
|
||||
Tools.PromptFuncDefinition.PromptFuncSpec.builder()
|
||||
.name("getWeather")
|
||||
.description("Get weather for a city")
|
||||
.parameters(params)
|
||||
.build();
|
||||
|
||||
Tools.PromptFuncDefinition def = Tools.PromptFuncDefinition.builder()
|
||||
.type("function")
|
||||
.function(spec)
|
||||
.build();
|
||||
Tools.PromptFuncDefinition def =
|
||||
Tools.PromptFuncDefinition.builder().type("function").function(spec).build();
|
||||
|
||||
Tools.ToolSpecification toolSpec = Tools.ToolSpecification.builder()
|
||||
Tools.ToolSpecification toolSpec =
|
||||
Tools.ToolSpecification.builder()
|
||||
.functionName("getWeather")
|
||||
.functionDescription("Get weather for a city")
|
||||
.toolPrompt(def)
|
||||
.build();
|
||||
|
||||
Tools.PromptBuilder pb = new Tools.PromptBuilder()
|
||||
Tools.PromptBuilder pb =
|
||||
new Tools.PromptBuilder()
|
||||
.withToolSpecification(toolSpec)
|
||||
.withPrompt("Tell me the weather.");
|
||||
|
||||
|
@ -1,12 +1,20 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.github.ollama4j.utils.Utils;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public abstract class AbstractSerializationTest<T> {
|
||||
|
||||
protected ObjectMapper mapper = Utils.getObjectMapper();
|
||||
@ -29,8 +37,7 @@ public abstract class AbstractSerializationTest<T> {
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertEqualsAfterUnmarshalling(T unmarshalledObject,
|
||||
T req) {
|
||||
protected void assertEqualsAfterUnmarshalling(T unmarshalledObject, T req) {
|
||||
assertEquals(req, unmarshalledObject);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,26 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
|
||||
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.utils.OptionsBuilder;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TestChatRequestSerialization extends AbstractSerializationTest<OllamaChatRequest> {
|
||||
|
||||
@ -26,14 +33,16 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
|
||||
@Test
|
||||
public void testRequestOnlyMandatoryFields() {
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt").build();
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "Some prompt").build();
|
||||
String jsonRequest = serialize(req);
|
||||
assertEqualsAfterUnmarshalling(deserialize(jsonRequest, OllamaChatRequest.class), req);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestMultipleMessages() {
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.SYSTEM, "System prompt")
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.SYSTEM, "System prompt")
|
||||
.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.build();
|
||||
String jsonRequest = serialize(req);
|
||||
@ -42,8 +51,13 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
|
||||
@Test
|
||||
public void testRequestWithMessageAndImage() {
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt", Collections.emptyList(),
|
||||
List.of(new File("src/test/resources/dog-on-a-boat.jpg"))).build();
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(
|
||||
OllamaChatMessageRole.USER,
|
||||
"Some prompt",
|
||||
Collections.emptyList(),
|
||||
List.of(new File("src/test/resources/dog-on-a-boat.jpg")))
|
||||
.build();
|
||||
String jsonRequest = serialize(req);
|
||||
assertEqualsAfterUnmarshalling(deserialize(jsonRequest, OllamaChatRequest.class), req);
|
||||
}
|
||||
@ -51,7 +65,8 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
@Test
|
||||
public void testRequestWithOptions() {
|
||||
OptionsBuilder b = new OptionsBuilder();
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.withOptions(b.setMirostat(1).build())
|
||||
.withOptions(b.setTemperature(1L).build())
|
||||
.withOptions(b.setMirostatEta(1L).build())
|
||||
@ -86,17 +101,23 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
@Test
|
||||
public void testRequestWithInvalidCustomOption() {
|
||||
OptionsBuilder b = new OptionsBuilder();
|
||||
assertThrowsExactly(IllegalArgumentException.class, () -> {
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.withOptions(b.setCustomOption("cust_obj", new Object()).build())
|
||||
assertThrowsExactly(
|
||||
IllegalArgumentException.class,
|
||||
() -> {
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.withOptions(
|
||||
b.setCustomOption("cust_obj", new Object()).build())
|
||||
.build();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithJsonFormat() {
|
||||
OllamaChatRequest req = builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.withGetJsonResponse().build();
|
||||
OllamaChatRequest req =
|
||||
builder.withMessage(OllamaChatMessageRole.USER, "Some prompt")
|
||||
.withGetJsonResponse()
|
||||
.build();
|
||||
|
||||
String jsonRequest = serialize(req);
|
||||
// no jackson deserialization as format property is not boolean ==> omit as deserialization
|
||||
@ -108,8 +129,7 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
|
||||
@Test
|
||||
public void testWithTemplate() {
|
||||
OllamaChatRequest req = builder.withTemplate("System Template")
|
||||
.build();
|
||||
OllamaChatRequest req = builder.withTemplate("System Template").build();
|
||||
String jsonRequest = serialize(req);
|
||||
assertEqualsAfterUnmarshalling(deserialize(jsonRequest, OllamaChatRequest.class), req);
|
||||
}
|
||||
@ -124,9 +144,10 @@ public class TestChatRequestSerialization extends AbstractSerializationTest<Olla
|
||||
@Test
|
||||
public void testWithKeepAlive() {
|
||||
String expectedKeepAlive = "5m";
|
||||
OllamaChatRequest req = builder.withKeepAlive(expectedKeepAlive)
|
||||
.build();
|
||||
OllamaChatRequest req = builder.withKeepAlive(expectedKeepAlive).build();
|
||||
String jsonRequest = serialize(req);
|
||||
assertEquals(deserialize(jsonRequest, OllamaChatRequest.class).getKeepAlive(), expectedKeepAlive);
|
||||
assertEquals(
|
||||
deserialize(jsonRequest, OllamaChatRequest.class).getKeepAlive(),
|
||||
expectedKeepAlive);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,23 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import io.github.ollama4j.models.embeddings.OllamaEmbedRequestBuilder;
|
||||
import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel;
|
||||
import io.github.ollama4j.utils.OptionsBuilder;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestEmbedRequestSerialization extends AbstractSerializationTest<OllamaEmbedRequestModel> {
|
||||
public class TestEmbedRequestSerialization
|
||||
extends AbstractSerializationTest<OllamaEmbedRequestModel> {
|
||||
|
||||
private OllamaEmbedRequestBuilder builder;
|
||||
|
||||
@ -21,17 +30,18 @@ public class TestEmbedRequestSerialization extends AbstractSerializationTest<Oll
|
||||
public void testRequestOnlyMandatoryFields() {
|
||||
OllamaEmbedRequestModel req = builder.build();
|
||||
String jsonRequest = serialize(req);
|
||||
assertEqualsAfterUnmarshalling(deserialize(jsonRequest, OllamaEmbedRequestModel.class), req);
|
||||
assertEqualsAfterUnmarshalling(
|
||||
deserialize(jsonRequest, OllamaEmbedRequestModel.class), req);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithOptions() {
|
||||
OptionsBuilder b = new OptionsBuilder();
|
||||
OllamaEmbedRequestModel req = builder
|
||||
.withOptions(b.setMirostat(1).build()).build();
|
||||
OllamaEmbedRequestModel req = builder.withOptions(b.setMirostat(1).build()).build();
|
||||
|
||||
String jsonRequest = serialize(req);
|
||||
OllamaEmbedRequestModel deserializeRequest = deserialize(jsonRequest, OllamaEmbedRequestModel.class);
|
||||
OllamaEmbedRequestModel deserializeRequest =
|
||||
deserialize(jsonRequest, OllamaEmbedRequestModel.class);
|
||||
assertEqualsAfterUnmarshalling(deserializeRequest, req);
|
||||
assertEquals(1, deserializeRequest.getOptions().get("mirostat"));
|
||||
}
|
||||
|
@ -1,5 +1,15 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateRequest;
|
||||
import io.github.ollama4j.models.generate.OllamaGenerateRequestBuilder;
|
||||
import io.github.ollama4j.utils.OptionsBuilder;
|
||||
@ -7,9 +17,8 @@ import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class TestGenerateRequestSerialization extends AbstractSerializationTest<OllamaGenerateRequest> {
|
||||
public class TestGenerateRequestSerialization
|
||||
extends AbstractSerializationTest<OllamaGenerateRequest> {
|
||||
|
||||
private OllamaGenerateRequestBuilder builder;
|
||||
|
||||
@ -33,15 +42,15 @@ public class TestGenerateRequestSerialization extends AbstractSerializationTest<
|
||||
builder.withPrompt("Some prompt").withOptions(b.setMirostat(1).build()).build();
|
||||
|
||||
String jsonRequest = serialize(req);
|
||||
OllamaGenerateRequest deserializeRequest = deserialize(jsonRequest, OllamaGenerateRequest.class);
|
||||
OllamaGenerateRequest deserializeRequest =
|
||||
deserialize(jsonRequest, OllamaGenerateRequest.class);
|
||||
assertEqualsAfterUnmarshalling(deserializeRequest, req);
|
||||
assertEquals(1, deserializeRequest.getOptions().get("mirostat"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithJsonFormat() {
|
||||
OllamaGenerateRequest req =
|
||||
builder.withPrompt("Some prompt").withGetJsonResponse().build();
|
||||
OllamaGenerateRequest req = builder.withPrompt("Some prompt").withGetJsonResponse().build();
|
||||
|
||||
String jsonRequest = serialize(req);
|
||||
System.out.printf(jsonRequest);
|
||||
|
@ -1,17 +1,26 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.models.response.ModelPullResponse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Test serialization and deserialization of ModelPullResponse,
|
||||
* This test verifies that the ModelPullResponse class can properly parse
|
||||
* error responses from Ollama server that return HTTP 200 with error messages
|
||||
* in the JSON body.
|
||||
*/
|
||||
public class TestModelPullResponseSerialization extends AbstractSerializationTest<ModelPullResponse> {
|
||||
public class TestModelPullResponseSerialization
|
||||
extends AbstractSerializationTest<ModelPullResponse> {
|
||||
|
||||
/**
|
||||
* Test the specific error case reported in GitHub issue #138.
|
||||
@ -20,7 +29,16 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes
|
||||
@Test
|
||||
public void testDeserializationWithErrorFromGitHubIssue138() {
|
||||
// This is the exact error JSON from GitHub issue #138
|
||||
String errorJson = "{\"error\":\"pull model manifest: 412: \\n\\nThe model you are attempting to pull requires a newer version of Ollama.\\n\\nPlease download the latest version at:\\n\\n\\thttps://ollama.com/download\\n\\n\"}";
|
||||
String errorJson =
|
||||
"{\"error\":\"pull model manifest: 412: \\n"
|
||||
+ "\\n"
|
||||
+ "The model you are attempting to pull requires a newer version of Ollama.\\n"
|
||||
+ "\\n"
|
||||
+ "Please download the latest version at:\\n"
|
||||
+ "\\n"
|
||||
+ "\\thttps://ollama.com/download\\n"
|
||||
+ "\\n"
|
||||
+ "\"}";
|
||||
|
||||
ModelPullResponse response = deserialize(errorJson, ModelPullResponse.class);
|
||||
|
||||
@ -59,7 +77,9 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes
|
||||
*/
|
||||
@Test
|
||||
public void testDeserializationWithProgressFields() {
|
||||
String progressJson = "{\"status\":\"pulling digestname\",\"digest\":\"sha256:abc123\",\"total\":2142590208,\"completed\":241970}";
|
||||
String progressJson =
|
||||
"{\"status\":\"pulling"
|
||||
+ " digestname\",\"digest\":\"sha256:abc123\",\"total\":2142590208,\"completed\":241970}";
|
||||
|
||||
ModelPullResponse response = deserialize(progressJson, ModelPullResponse.class);
|
||||
|
||||
@ -95,7 +115,8 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes
|
||||
*/
|
||||
@Test
|
||||
public void testDeserializationWithAllFields() {
|
||||
String completeJson = "{\"status\":\"downloading\",\"digest\":\"sha256:def456\",\"total\":1000000,\"completed\":500000,\"error\":null}";
|
||||
String completeJson =
|
||||
"{\"status\":\"downloading\",\"digest\":\"sha256:def456\",\"total\":1000000,\"completed\":500000,\"error\":null}";
|
||||
|
||||
ModelPullResponse response = deserialize(completeJson, ModelPullResponse.class);
|
||||
|
||||
@ -115,7 +136,9 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes
|
||||
@Test
|
||||
public void testDeserializationWithUnknownFields() {
|
||||
// Test that unknown fields are ignored due to @JsonIgnoreProperties(ignoreUnknown = true)
|
||||
String jsonWithUnknownFields = "{\"status\":\"pulling\",\"unknown_field\":\"should_be_ignored\",\"error\":\"test error\",\"another_unknown\":123,\"nested_unknown\":{\"key\":\"value\"}}";
|
||||
String jsonWithUnknownFields =
|
||||
"{\"status\":\"pulling\",\"unknown_field\":\"should_be_ignored\",\"error\":\"test"
|
||||
+ " error\",\"another_unknown\":123,\"nested_unknown\":{\"key\":\"value\"}}";
|
||||
|
||||
ModelPullResponse response = deserialize(jsonWithUnknownFields, ModelPullResponse.class);
|
||||
|
||||
@ -227,21 +250,25 @@ public class TestModelPullResponseSerialization extends AbstractSerializationTes
|
||||
String errorJson = "{\"error\":\"test error\"}";
|
||||
ModelPullResponse errorResponse = deserialize(errorJson, ModelPullResponse.class);
|
||||
|
||||
assertTrue(errorResponse.getError() != null && !errorResponse.getError().trim().isEmpty(),
|
||||
assertTrue(
|
||||
errorResponse.getError() != null && !errorResponse.getError().trim().isEmpty(),
|
||||
"Error response should trigger error handling logic");
|
||||
|
||||
// Normal case - should not trigger error handling
|
||||
String normalJson = "{\"status\":\"pulling\"}";
|
||||
ModelPullResponse normalResponse = deserialize(normalJson, ModelPullResponse.class);
|
||||
|
||||
assertFalse(normalResponse.getError() != null && !normalResponse.getError().trim().isEmpty(),
|
||||
assertFalse(
|
||||
normalResponse.getError() != null && !normalResponse.getError().trim().isEmpty(),
|
||||
"Normal response should not trigger error handling logic");
|
||||
|
||||
// Empty error case - should not trigger error handling
|
||||
String emptyErrorJson = "{\"error\":\"\",\"status\":\"pulling\"}";
|
||||
ModelPullResponse emptyErrorResponse = deserialize(emptyErrorJson, ModelPullResponse.class);
|
||||
|
||||
assertFalse(emptyErrorResponse.getError() != null && !emptyErrorResponse.getError().trim().isEmpty(),
|
||||
assertFalse(
|
||||
emptyErrorResponse.getError() != null
|
||||
&& !emptyErrorResponse.getError().trim().isEmpty(),
|
||||
"Empty error response should not trigger error handling logic");
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,45 @@
|
||||
/*
|
||||
* Ollama4j - Java library for interacting with Ollama server.
|
||||
* Copyright (c) 2025 Amith Koujalgi and contributors.
|
||||
*
|
||||
* Licensed under the MIT License (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
*/
|
||||
package io.github.ollama4j.unittests.jackson;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import io.github.ollama4j.models.response.Model;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
public class TestModelRequestSerialization extends AbstractSerializationTest<Model> {
|
||||
|
||||
@Test
|
||||
public void testDeserializationOfModelResponseWithOffsetTime() {
|
||||
String serializedTestStringWithOffsetTime = "{\n" +
|
||||
" \"name\": \"codellama:13b\",\n" +
|
||||
" \"modified_at\": \"2023-11-04T14:56:49.277302595-07:00\",\n" +
|
||||
" \"size\": 7365960935,\n" +
|
||||
" \"digest\": \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n" +
|
||||
" \"details\": {\n" +
|
||||
" \"format\": \"gguf\",\n" +
|
||||
" \"family\": \"llama\",\n" +
|
||||
" \"families\": null,\n" +
|
||||
" \"parameter_size\": \"13B\",\n" +
|
||||
" \"quantization_level\": \"Q4_0\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
String serializedTestStringWithOffsetTime =
|
||||
"{\n"
|
||||
+ " \"name\": \"codellama:13b\",\n"
|
||||
+ " \"modified_at\": \"2023-11-04T14:56:49.277302595-07:00\",\n"
|
||||
+ " \"size\": 7365960935,\n"
|
||||
+ " \"digest\":"
|
||||
+ " \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n"
|
||||
+ " \"details\": {\n"
|
||||
+ " \"format\": \"gguf\",\n"
|
||||
+ " \"family\": \"llama\",\n"
|
||||
+ " \"families\": null,\n"
|
||||
+ " \"parameter_size\": \"13B\",\n"
|
||||
+ " \"quantization_level\": \"Q4_0\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Model model = deserialize(serializedTestStringWithOffsetTime, Model.class);
|
||||
assertNotNull(model);
|
||||
assertEquals("codellama:13b", model.getName());
|
||||
assertEquals("2023-11-04T21:56:49.277302595Z", model.getModifiedAt().toString());
|
||||
assertEquals(7365960935L, model.getSize());
|
||||
assertEquals("9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697", model.getDigest());
|
||||
assertEquals(
|
||||
"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697",
|
||||
model.getDigest());
|
||||
assertNotNull(model.getModelMeta());
|
||||
assertEquals("gguf", model.getModelMeta().getFormat());
|
||||
assertEquals("llama", model.getModelMeta().getFamily());
|
||||
@ -38,25 +50,29 @@ public class TestModelRequestSerialization extends AbstractSerializationTest<Mod
|
||||
|
||||
@Test
|
||||
public void testDeserializationOfModelResponseWithZuluTime() {
|
||||
String serializedTestStringWithZuluTimezone = "{\n" +
|
||||
" \"name\": \"codellama:13b\",\n" +
|
||||
" \"modified_at\": \"2023-11-04T14:56:49.277302595Z\",\n" +
|
||||
" \"size\": 7365960935,\n" +
|
||||
" \"digest\": \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n" +
|
||||
" \"details\": {\n" +
|
||||
" \"format\": \"gguf\",\n" +
|
||||
" \"family\": \"llama\",\n" +
|
||||
" \"families\": null,\n" +
|
||||
" \"parameter_size\": \"13B\",\n" +
|
||||
" \"quantization_level\": \"Q4_0\"\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
String serializedTestStringWithZuluTimezone =
|
||||
"{\n"
|
||||
+ " \"name\": \"codellama:13b\",\n"
|
||||
+ " \"modified_at\": \"2023-11-04T14:56:49.277302595Z\",\n"
|
||||
+ " \"size\": 7365960935,\n"
|
||||
+ " \"digest\":"
|
||||
+ " \"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697\",\n"
|
||||
+ " \"details\": {\n"
|
||||
+ " \"format\": \"gguf\",\n"
|
||||
+ " \"family\": \"llama\",\n"
|
||||
+ " \"families\": null,\n"
|
||||
+ " \"parameter_size\": \"13B\",\n"
|
||||
+ " \"quantization_level\": \"Q4_0\"\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
Model model = deserialize(serializedTestStringWithZuluTimezone, Model.class);
|
||||
assertNotNull(model);
|
||||
assertEquals("codellama:13b", model.getName());
|
||||
assertEquals("2023-11-04T14:56:49.277302595Z", model.getModifiedAt().toString());
|
||||
assertEquals(7365960935L, model.getSize());
|
||||
assertEquals("9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697", model.getDigest());
|
||||
assertEquals(
|
||||
"9f438cb9cd581fc025612d27f7c1a6669ff83a8bb0ed86c94fcf4c5440555697",
|
||||
model.getDigest());
|
||||
assertNotNull(model.getModelMeta());
|
||||
assertEquals("gguf", model.getModelMeta().getFormat());
|
||||
assertEquals("llama", model.getModelMeta().getFamily());
|
||||
@ -64,5 +80,4 @@ public class TestModelRequestSerialization extends AbstractSerializationTest<Mod
|
||||
assertEquals("13B", model.getModelMeta().getParameterSize());
|
||||
assertEquals("Q4_0", model.getModelMeta().getQuantizationLevel());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user