Ollama4j
A Java library (wrapper/binding) for Ollama server.
Loading...
Searching...
No Matches
OllamaAPI.java
Go to the documentation of this file.
1package io.github.ollama4j;
2
3import com.fasterxml.jackson.core.JsonParseException;
4import com.fasterxml.jackson.databind.JsonNode;
5import com.fasterxml.jackson.databind.ObjectMapper;
6import io.github.ollama4j.exceptions.OllamaBaseException;
7import io.github.ollama4j.exceptions.RoleNotFoundException;
8import io.github.ollama4j.exceptions.ToolInvocationException;
9import io.github.ollama4j.exceptions.ToolNotFoundException;
10import io.github.ollama4j.models.chat.*;
11import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel;
12import io.github.ollama4j.models.embeddings.OllamaEmbedResponseModel;
13import io.github.ollama4j.models.embeddings.OllamaEmbeddingResponseModel;
14import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel;
15import io.github.ollama4j.models.generate.OllamaGenerateRequest;
16import io.github.ollama4j.models.generate.OllamaStreamHandler;
17import io.github.ollama4j.models.generate.OllamaTokenHandler;
18import io.github.ollama4j.models.ps.ModelsProcessResponse;
19import io.github.ollama4j.models.request.*;
20import io.github.ollama4j.models.response.*;
21import io.github.ollama4j.tools.*;
22import io.github.ollama4j.tools.annotations.OllamaToolService;
23import io.github.ollama4j.tools.annotations.ToolProperty;
24import io.github.ollama4j.tools.annotations.ToolSpec;
25import io.github.ollama4j.utils.Constants;
26import io.github.ollama4j.utils.Options;
27import io.github.ollama4j.utils.Utils;
28import lombok.Setter;
29import org.jsoup.Jsoup;
30import org.jsoup.nodes.Document;
31import org.jsoup.nodes.Element;
32import org.jsoup.select.Elements;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import java.io.*;
37import java.lang.reflect.InvocationTargetException;
38import java.lang.reflect.Method;
39import java.lang.reflect.Parameter;
40import java.net.URI;
41import java.net.URISyntaxException;
42import java.net.http.HttpClient;
43import java.net.http.HttpConnectTimeoutException;
44import java.net.http.HttpRequest;
45import java.net.http.HttpResponse;
46import java.nio.charset.StandardCharsets;
47import java.nio.file.Files;
48import java.time.Duration;
49import java.util.*;
50import java.util.stream.Collectors;
51
55@SuppressWarnings({"DuplicatedCode", "resource"})
56public class OllamaAPI {
57
58 private static final Logger logger = LoggerFactory.getLogger(OllamaAPI.class);
59
60 private final String host;
61 private Auth auth;
62 private final ToolRegistry toolRegistry = new ToolRegistry();
63
71 @Setter
72 private long requestTimeoutSeconds = 10;
73
81 @Setter
82 private boolean verbose = true;
83
91 @Setter
92 private int maxChatToolCallRetries = 3;
93
103 @Setter
104 @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"})
105 private int numberOfRetriesForModelPull = 0;
106
111 public OllamaAPI() {
112 this.host = "http://localhost:11434";
113 }
114
120 public OllamaAPI(String host) {
121 if (host.endsWith("/")) {
122 this.host = host.substring(0, host.length() - 1);
123 } else {
124 this.host = host;
125 }
126 if (this.verbose) {
127 logger.info("Ollama API initialized with host: {}", this.host);
128 }
129 }
130
138 public void setBasicAuth(String username, String password) {
139 this.auth = new BasicAuth(username, password);
140 }
141
148 public void setBearerAuth(String bearerToken) {
149 this.auth = new BearerAuth(bearerToken);
150 }
151
157 public boolean ping() {
158 String url = this.host + "/api/tags";
159 HttpClient httpClient = HttpClient.newHttpClient();
160 HttpRequest httpRequest;
161 try {
162 httpRequest = getRequestBuilderDefault(new URI(url))
163 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
164 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
165 .GET()
166 .build();
167 } catch (URISyntaxException e) {
168 throw new RuntimeException(e);
169 }
170 HttpResponse<String> response;
171 try {
172 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
173 } catch (HttpConnectTimeoutException e) {
174 return false;
175 } catch (IOException | InterruptedException e) {
176 throw new RuntimeException(e);
177 }
178 int statusCode = response.statusCode();
179 return statusCode == 200;
180 }
181
191 public ModelsProcessResponse ps() throws IOException, InterruptedException, OllamaBaseException {
192 String url = this.host + "/api/ps";
193 HttpClient httpClient = HttpClient.newHttpClient();
194 HttpRequest httpRequest = null;
195 try {
196 httpRequest = getRequestBuilderDefault(new URI(url))
197 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
198 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
199 .GET().build();
200 } catch (URISyntaxException e) {
201 throw new RuntimeException(e);
202 }
203 HttpResponse<String> response = null;
204 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
205 int statusCode = response.statusCode();
206 String responseString = response.body();
207 if (statusCode == 200) {
208 return Utils.getObjectMapper().readValue(responseString, ModelsProcessResponse.class);
209 } else {
210 throw new OllamaBaseException(statusCode + " - " + responseString);
211 }
212 }
213
223 public List<Model> listModels() throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
224 String url = this.host + "/api/tags";
225 HttpClient httpClient = HttpClient.newHttpClient();
226 HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
227 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
228 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
229 .build();
230 HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
231 int statusCode = response.statusCode();
232 String responseString = response.body();
233 if (statusCode == 200) {
234 return Utils.getObjectMapper().readValue(responseString, ListModelsResponse.class).getModels();
235 } else {
236 throw new OllamaBaseException(statusCode + " - " + responseString);
237 }
238 }
239
257 public List<LibraryModel> listModelsFromLibrary()
258 throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
259 String url = "https://ollama.com/library";
260 HttpClient httpClient = HttpClient.newHttpClient();
261 HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
262 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
263 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
264 .build();
265 HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
266 int statusCode = response.statusCode();
267 String responseString = response.body();
268 List<LibraryModel> models = new ArrayList<>();
269 if (statusCode == 200) {
270 Document doc = Jsoup.parse(responseString);
271 Elements modelSections = doc.selectXpath("//*[@id='repo']/ul/li/a");
272 for (Element e : modelSections) {
273 LibraryModel model = new LibraryModel();
274 Elements names = e.select("div > h2 > div > span");
275 Elements desc = e.select("div > p");
276 Elements pullCounts = e.select("div:nth-of-type(2) > p > span:first-of-type > span:first-of-type");
277 Elements popularTags = e.select("div > div > span");
278 Elements totalTags = e.select("div:nth-of-type(2) > p > span:nth-of-type(2) > span:first-of-type");
279 Elements lastUpdatedTime = e
280 .select("div:nth-of-type(2) > p > span:nth-of-type(3) > span:nth-of-type(2)");
281
282 if (names.first() == null || names.isEmpty()) {
283 // if name cannot be extracted, skip.
284 continue;
285 }
286 Optional.ofNullable(names.first()).map(Element::text).ifPresent(model::setName);
287 model.setDescription(Optional.ofNullable(desc.first()).map(Element::text).orElse(""));
288 model.setPopularTags(Optional.of(popularTags)
289 .map(tags -> tags.stream().map(Element::text).collect(Collectors.toList()))
290 .orElse(new ArrayList<>()));
291 model.setPullCount(Optional.ofNullable(pullCounts.first()).map(Element::text).orElse(""));
292 model.setTotalTags(
293 Optional.ofNullable(totalTags.first()).map(Element::text).map(Integer::parseInt).orElse(0));
294 model.setLastUpdated(Optional.ofNullable(lastUpdatedTime.first()).map(Element::text).orElse(""));
295
296 models.add(model);
297 }
298 return models;
299 } else {
300 throw new OllamaBaseException(statusCode + " - " + responseString);
301 }
302 }
303
327 throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
328 String url = String.format("https://ollama.com/library/%s/tags", libraryModel.getName());
329 HttpClient httpClient = HttpClient.newHttpClient();
330 HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
331 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
332 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
333 .build();
334 HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
335 int statusCode = response.statusCode();
336 String responseString = response.body();
337
338 List<LibraryModelTag> libraryModelTags = new ArrayList<>();
339 if (statusCode == 200) {
340 Document doc = Jsoup.parse(responseString);
341 Elements tagSections = doc
342 .select("html > body > main > div > section > div > div > div:nth-child(n+2) > div");
343 for (Element e : tagSections) {
344 Elements tags = e.select("div > a > div");
345 Elements tagsMetas = e.select("div > span");
346
347 LibraryModelTag libraryModelTag = new LibraryModelTag();
348
349 if (tags.first() == null || tags.isEmpty()) {
350 // if tag cannot be extracted, skip.
351 continue;
352 }
353 libraryModelTag.setName(libraryModel.getName());
354 Optional.ofNullable(tags.first()).map(Element::text).ifPresent(libraryModelTag::setTag);
355 libraryModelTag.setSize(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split("•"))
356 .filter(parts -> parts.length > 1).map(parts -> parts[1].trim()).orElse(""));
357 libraryModelTag
358 .setLastUpdated(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split("•"))
359 .filter(parts -> parts.length > 1).map(parts -> parts[2].trim()).orElse(""));
360 libraryModelTags.add(libraryModelTag);
361 }
362 LibraryModelDetail libraryModelDetail = new LibraryModelDetail();
363 libraryModelDetail.setModel(libraryModel);
364 libraryModelDetail.setTags(libraryModelTags);
365 return libraryModelDetail;
366 } else {
367 throw new OllamaBaseException(statusCode + " - " + responseString);
368 }
369 }
370
403 @Deprecated
404 public LibraryModelTag findModelTagFromLibrary(String modelName, String tag)
405 throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
406 List<LibraryModel> libraryModels = this.listModelsFromLibrary();
407 LibraryModel libraryModel = libraryModels.stream().filter(model -> model.getName().equals(modelName))
408 .findFirst().orElseThrow(
409 () -> new NoSuchElementException(String.format("Model by name '%s' not found", modelName)));
410 LibraryModelDetail libraryModelDetail = this.getLibraryModelDetails(libraryModel);
411 return libraryModelDetail.getTags().stream().filter(tagName -> tagName.getTag().equals(tag)).findFirst()
412 .orElseThrow(() -> new NoSuchElementException(
413 String.format("Tag '%s' for model '%s' not found", tag, modelName)));
414 }
415
437 public void pullModel(String modelName)
438 throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
439 if (numberOfRetriesForModelPull == 0) {
440 this.doPullModel(modelName);
441 return;
442 }
443 int numberOfRetries = 0;
444 long baseDelayMillis = 3000L; // 1 second base delay
445 while (numberOfRetries < numberOfRetriesForModelPull) {
446 try {
447 this.doPullModel(modelName);
448 return;
449 } catch (OllamaBaseException e) {
450 handlePullRetry(modelName, numberOfRetries, numberOfRetriesForModelPull, baseDelayMillis);
451 numberOfRetries++;
452 }
453 }
454 throw new OllamaBaseException(
455 "Failed to pull model " + modelName + " after " + numberOfRetriesForModelPull + " retries");
456 }
457
461 private void handlePullRetry(String modelName, int currentRetry, int maxRetries, long baseDelayMillis)
462 throws InterruptedException {
463 int attempt = currentRetry + 1;
464 if (attempt < maxRetries) {
465 long backoffMillis = baseDelayMillis * (1L << currentRetry);
466 logger.error("Failed to pull model {}, retrying in {}s... (attempt {}/{})",
467 modelName, backoffMillis / 1000, attempt, maxRetries);
468 try {
469 Thread.sleep(backoffMillis);
470 } catch (InterruptedException ie) {
471 Thread.currentThread().interrupt();
472 throw ie;
473 }
474 } else {
475 logger.error("Failed to pull model {} after {} attempts, no more retries.", modelName, maxRetries);
476 }
477 }
478
479 private void doPullModel(String modelName)
480 throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
481 String url = this.host + "/api/pull";
482 String jsonData = new ModelRequest(modelName).toString();
483 HttpRequest request = getRequestBuilderDefault(new URI(url)).POST(HttpRequest.BodyPublishers.ofString(jsonData))
484 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
485 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
486 .build();
487 HttpClient client = HttpClient.newHttpClient();
488 HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
489 int statusCode = response.statusCode();
490 InputStream responseBodyStream = response.body();
491 String responseString = "";
492 boolean success = false; // Flag to check the pull success.
493 try (BufferedReader reader = new BufferedReader(
494 new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
495 String line;
496 while ((line = reader.readLine()) != null) {
497 ModelPullResponse modelPullResponse = Utils.getObjectMapper().readValue(line, ModelPullResponse.class);
498 if (modelPullResponse != null) {
499 // Check for error in response body first
500 if (modelPullResponse.getError() != null && !modelPullResponse.getError().trim().isEmpty()) {
501 throw new OllamaBaseException("Model pull failed: " + modelPullResponse.getError());
502 }
503
504 if (modelPullResponse.getStatus() != null) {
505 if (verbose) {
506 logger.info("{}: {}", modelName, modelPullResponse.getStatus());
507 }
508 // Check if status is "success" and set success flag to true.
509 if ("success".equalsIgnoreCase(modelPullResponse.getStatus())) {
510 success = true;
511 }
512 }
513 } else {
514 logger.error("Received null response for model pull.");
515 }
516 }
517 }
518 if (!success) {
519 logger.error("Model pull failed or returned invalid status.");
520 throw new OllamaBaseException("Model pull failed or returned invalid status.");
521 }
522 if (statusCode != 200) {
523 throw new OllamaBaseException(statusCode + " - " + responseString);
524 }
525 }
526
527 public String getVersion() throws URISyntaxException, IOException, InterruptedException, OllamaBaseException {
528 String url = this.host + "/api/version";
529 HttpClient httpClient = HttpClient.newHttpClient();
530 HttpRequest httpRequest = getRequestBuilderDefault(new URI(url))
531 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
532 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON).GET()
533 .build();
534 HttpResponse<String> response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
535 int statusCode = response.statusCode();
536 String responseString = response.body();
537 if (statusCode == 200) {
538 return Utils.getObjectMapper().readValue(responseString, OllamaVersion.class).getVersion();
539 } else {
540 throw new OllamaBaseException(statusCode + " - " + responseString);
541 }
542 }
543
558 public void pullModel(LibraryModelTag libraryModelTag)
559 throws OllamaBaseException, IOException, URISyntaxException, InterruptedException {
560 String tagToPull = String.format("%s:%s", libraryModelTag.getName(), libraryModelTag.getTag());
561 pullModel(tagToPull);
562 }
563
574 public ModelDetail getModelDetails(String modelName)
575 throws IOException, OllamaBaseException, InterruptedException, URISyntaxException {
576 String url = this.host + "/api/show";
577 String jsonData = new ModelRequest(modelName).toString();
578 HttpRequest request = getRequestBuilderDefault(new URI(url))
579 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
580 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
581 .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
582 HttpClient client = HttpClient.newHttpClient();
583 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
584 int statusCode = response.statusCode();
585 String responseBody = response.body();
586 if (statusCode == 200) {
587 return Utils.getObjectMapper().readValue(responseBody, ModelDetail.class);
588 } else {
589 throw new OllamaBaseException(statusCode + " - " + responseBody);
590 }
591 }
592
606 @Deprecated
607 public void createModelWithFilePath(String modelName, String modelFilePath)
608 throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
609 String url = this.host + "/api/create";
610 String jsonData = new CustomModelFilePathRequest(modelName, modelFilePath).toString();
611 HttpRequest request = getRequestBuilderDefault(new URI(url))
612 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
613 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
614 .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
615 HttpClient client = HttpClient.newHttpClient();
616 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
617 int statusCode = response.statusCode();
618 String responseString = response.body();
619 if (statusCode != 200) {
620 throw new OllamaBaseException(statusCode + " - " + responseString);
621 }
622 // FIXME: Ollama API returns HTTP status code 200 for model creation failure
623 // cases. Correct this
624 // if the issue is fixed in the Ollama API server.
625 if (responseString.contains("error")) {
626 throw new OllamaBaseException(responseString);
627 }
628 if (verbose) {
629 logger.info(responseString);
630 }
631 }
632
647 @Deprecated
648 public void createModelWithModelFileContents(String modelName, String modelFileContents)
649 throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
650 String url = this.host + "/api/create";
651 String jsonData = new CustomModelFileContentsRequest(modelName, modelFileContents).toString();
652 HttpRequest request = getRequestBuilderDefault(new URI(url))
653 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
654 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
655 .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
656 HttpClient client = HttpClient.newHttpClient();
657 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
658 int statusCode = response.statusCode();
659 String responseString = response.body();
660 if (statusCode != 200) {
661 throw new OllamaBaseException(statusCode + " - " + responseString);
662 }
663 if (responseString.contains("error")) {
664 throw new OllamaBaseException(responseString);
665 }
666 if (verbose) {
667 logger.info(responseString);
668 }
669 }
670
682 public void createModel(CustomModelRequest customModelRequest)
683 throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
684 String url = this.host + "/api/create";
685 String jsonData = customModelRequest.toString();
686 HttpRequest request = getRequestBuilderDefault(new URI(url))
687 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
688 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
689 .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
690 HttpClient client = HttpClient.newHttpClient();
691 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
692 int statusCode = response.statusCode();
693 String responseString = response.body();
694 if (statusCode != 200) {
695 throw new OllamaBaseException(statusCode + " - " + responseString);
696 }
697 if (responseString.contains("error")) {
698 throw new OllamaBaseException(responseString);
699 }
700 if (verbose) {
701 logger.info(responseString);
702 }
703 }
704
716 public void deleteModel(String modelName, boolean ignoreIfNotPresent)
717 throws IOException, InterruptedException, OllamaBaseException, URISyntaxException {
718 String url = this.host + "/api/delete";
719 String jsonData = new ModelRequest(modelName).toString();
720 HttpRequest request = getRequestBuilderDefault(new URI(url))
721 .method("DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
722 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
723 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
724 .build();
725 HttpClient client = HttpClient.newHttpClient();
726 HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
727 int statusCode = response.statusCode();
728 String responseBody = response.body();
729 if (statusCode == 404 && responseBody.contains("model") && responseBody.contains("not found")) {
730 return;
731 }
732 if (statusCode != 200) {
733 throw new OllamaBaseException(statusCode + " - " + responseBody);
734 }
735 }
736
748 @Deprecated
749 public List<Double> generateEmbeddings(String model, String prompt)
750 throws IOException, InterruptedException, OllamaBaseException {
751 return generateEmbeddings(new OllamaEmbeddingsRequestModel(model, prompt));
752 }
753
764 @Deprecated
765 public List<Double> generateEmbeddings(OllamaEmbeddingsRequestModel modelRequest)
766 throws IOException, InterruptedException, OllamaBaseException {
767 URI uri = URI.create(this.host + "/api/embeddings");
768 String jsonData = modelRequest.toString();
769 HttpClient httpClient = HttpClient.newHttpClient();
770 HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri)
771 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
772 .POST(HttpRequest.BodyPublishers.ofString(jsonData));
773 HttpRequest request = requestBuilder.build();
774 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
775 int statusCode = response.statusCode();
776 String responseBody = response.body();
777 if (statusCode == 200) {
778 OllamaEmbeddingResponseModel embeddingResponse = Utils.getObjectMapper().readValue(responseBody,
780 return embeddingResponse.getEmbedding();
781 } else {
782 throw new OllamaBaseException(statusCode + " - " + responseBody);
783 }
784 }
785
796 public OllamaEmbedResponseModel embed(String model, List<String> inputs)
797 throws IOException, InterruptedException, OllamaBaseException {
798 return embed(new OllamaEmbedRequestModel(model, inputs));
799 }
800
811 throws IOException, InterruptedException, OllamaBaseException {
812 URI uri = URI.create(this.host + "/api/embed");
813 String jsonData = Utils.getObjectMapper().writeValueAsString(modelRequest);
814 HttpClient httpClient = HttpClient.newHttpClient();
815
816 HttpRequest request = HttpRequest.newBuilder(uri)
817 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
818 .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
819
820 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
821 int statusCode = response.statusCode();
822 String responseBody = response.body();
823
824 if (statusCode == 200) {
825 return Utils.getObjectMapper().readValue(responseBody, OllamaEmbedResponseModel.class);
826 } else {
827 throw new OllamaBaseException(statusCode + " - " + responseBody);
828 }
829 }
830
857 public OllamaResult generate(String model, String prompt, boolean raw, Options options,
858 OllamaStreamHandler responseStreamHandler) throws OllamaBaseException, IOException, InterruptedException {
859 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
860 ollamaRequestModel.setRaw(raw);
861 ollamaRequestModel.setThink(false);
862 ollamaRequestModel.setOptions(options.getOptionsMap());
863 return generateSyncForOllamaRequestModel(ollamaRequestModel, null, responseStreamHandler);
864 }
865
893 public OllamaResult generate(String model, String prompt, boolean raw, Options options,
894 OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
895 throws OllamaBaseException, IOException, InterruptedException {
896 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
897 ollamaRequestModel.setRaw(raw);
898 ollamaRequestModel.setThink(true);
899 ollamaRequestModel.setOptions(options.getOptionsMap());
900 return generateSyncForOllamaRequestModel(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
901 }
902
926 public OllamaResult generate(String model, String prompt, boolean raw, boolean think, Options options)
927 throws OllamaBaseException, IOException, InterruptedException {
928 if (think) {
929 return generate(model, prompt, raw, options, null, null);
930 } else {
931 return generate(model, prompt, raw, options, null);
932 }
933 }
934
951 @SuppressWarnings("LoggingSimilarMessage")
952 public OllamaResult generate(String model, String prompt, Map<String, Object> format)
953 throws OllamaBaseException, IOException, InterruptedException {
954 URI uri = URI.create(this.host + "/api/generate");
955
956 Map<String, Object> requestBody = new HashMap<>();
957 requestBody.put("model", model);
958 requestBody.put("prompt", prompt);
959 requestBody.put("stream", false);
960 requestBody.put("format", format);
961
962 String jsonData = Utils.getObjectMapper().writeValueAsString(requestBody);
963 HttpClient httpClient = HttpClient.newHttpClient();
964
965 HttpRequest request = getRequestBuilderDefault(uri)
966 .header(Constants.HttpConstants.HEADER_KEY_ACCEPT, Constants.HttpConstants.APPLICATION_JSON)
967 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
968 .POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
969
970 if (verbose) {
971 try {
972 String prettyJson = Utils.getObjectMapper().writerWithDefaultPrettyPrinter()
973 .writeValueAsString(Utils.getObjectMapper().readValue(jsonData, Object.class));
974 logger.info("Asking model:\n{}", prettyJson);
975 } catch (Exception e) {
976 logger.info("Asking model: {}", jsonData);
977 }
978 }
979 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
980 int statusCode = response.statusCode();
981 String responseBody = response.body();
982 if (statusCode == 200) {
983 OllamaStructuredResult structuredResult = Utils.getObjectMapper().readValue(responseBody,
985 OllamaResult ollamaResult = new OllamaResult(structuredResult.getResponse(), structuredResult.getThinking(),
986 structuredResult.getResponseTime(), statusCode);
987
988 ollamaResult.setModel(structuredResult.getModel());
989 ollamaResult.setCreatedAt(structuredResult.getCreatedAt());
990 ollamaResult.setDone(structuredResult.isDone());
991 ollamaResult.setDoneReason(structuredResult.getDoneReason());
992 ollamaResult.setContext(structuredResult.getContext());
993 ollamaResult.setTotalDuration(structuredResult.getTotalDuration());
994 ollamaResult.setLoadDuration(structuredResult.getLoadDuration());
995 ollamaResult.setPromptEvalCount(structuredResult.getPromptEvalCount());
996 ollamaResult.setPromptEvalDuration(structuredResult.getPromptEvalDuration());
997 ollamaResult.setEvalCount(structuredResult.getEvalCount());
998 ollamaResult.setEvalDuration(structuredResult.getEvalDuration());
999 if (verbose) {
1000 logger.info("Model response:\n{}", ollamaResult);
1001 }
1002 return ollamaResult;
1003 } else {
1004 if (verbose) {
1005 logger.info("Model response:\n{}",
1006 Utils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(responseBody));
1007 }
1008 throw new OllamaBaseException(statusCode + " - " + responseBody);
1009 }
1010 }
1011
1029 public OllamaToolsResult generateWithTools(String model, String prompt, Options options)
1030 throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
1031 boolean raw = true;
1032 OllamaToolsResult toolResult = new OllamaToolsResult();
1033 Map<ToolFunctionCallSpec, Object> toolResults = new HashMap<>();
1034
1035 if (!prompt.startsWith("[AVAILABLE_TOOLS]")) {
1036 final Tools.PromptBuilder promptBuilder = new Tools.PromptBuilder();
1037 for (Tools.ToolSpecification spec : toolRegistry.getRegisteredSpecs()) {
1038 promptBuilder.withToolSpecification(spec);
1039 }
1040 promptBuilder.withPrompt(prompt);
1041 prompt = promptBuilder.build();
1042 }
1043
1044 OllamaResult result = generate(model, prompt, raw, options, null);
1045 toolResult.setModelResult(result);
1046
1047 String toolsResponse = result.getResponse();
1048 if (toolsResponse.contains("[TOOL_CALLS]")) {
1049 toolsResponse = toolsResponse.replace("[TOOL_CALLS]", "");
1050 }
1051
1052 List<ToolFunctionCallSpec> toolFunctionCallSpecs = new ArrayList<>();
1053 ObjectMapper objectMapper = Utils.getObjectMapper();
1054
1055 if (!toolsResponse.isEmpty()) {
1056 try {
1057 // Try to parse the string to see if it's a valid JSON
1058 JsonNode jsonNode = objectMapper.readTree(toolsResponse);
1059 } catch (JsonParseException e) {
1060 logger.warn("Response from model does not contain any tool calls. Returning the response as is.");
1061 return toolResult;
1062 }
1063 toolFunctionCallSpecs = objectMapper.readValue(toolsResponse,
1064 objectMapper.getTypeFactory().constructCollectionType(List.class, ToolFunctionCallSpec.class));
1065 }
1066 for (ToolFunctionCallSpec toolFunctionCallSpec : toolFunctionCallSpecs) {
1067 toolResults.put(toolFunctionCallSpec, invokeTool(toolFunctionCallSpec));
1068 }
1069 toolResult.setToolResults(toolResults);
1070 return toolResult;
1071 }
1072
1111 public OllamaAsyncResultStreamer generateAsync(String model, String prompt, boolean raw, boolean think) {
1112 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt);
1113 ollamaRequestModel.setRaw(raw);
1114 ollamaRequestModel.setThink(think);
1115 URI uri = URI.create(this.host + "/api/generate");
1116 OllamaAsyncResultStreamer ollamaAsyncResultStreamer = new OllamaAsyncResultStreamer(
1117 getRequestBuilderDefault(uri), ollamaRequestModel, requestTimeoutSeconds);
1118 ollamaAsyncResultStreamer.start();
1119 return ollamaAsyncResultStreamer;
1120 }
1121
1142 public OllamaResult generateWithImageFiles(String model, String prompt, List<File> imageFiles, Options options,
1143 OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException {
1144 List<String> images = new ArrayList<>();
1145 for (File imageFile : imageFiles) {
1146 images.add(encodeFileToBase64(imageFile));
1147 }
1148 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt, images);
1149 ollamaRequestModel.setOptions(options.getOptionsMap());
1150 return generateSyncForOllamaRequestModel(ollamaRequestModel, null, streamHandler);
1151 }
1152
1163 public OllamaResult generateWithImageFiles(String model, String prompt, List<File> imageFiles, Options options)
1164 throws OllamaBaseException, IOException, InterruptedException {
1165 return generateWithImageFiles(model, prompt, imageFiles, options, null);
1166 }
1167
1189 public OllamaResult generateWithImageURLs(String model, String prompt, List<String> imageURLs, Options options,
1190 OllamaStreamHandler streamHandler)
1191 throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
1192 List<String> images = new ArrayList<>();
1193 for (String imageURL : imageURLs) {
1194 images.add(encodeByteArrayToBase64(Utils.loadImageBytesFromUrl(imageURL)));
1195 }
1196 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt, images);
1197 ollamaRequestModel.setOptions(options.getOptionsMap());
1198 return generateSyncForOllamaRequestModel(ollamaRequestModel, null, streamHandler);
1199 }
1200
1212 public OllamaResult generateWithImageURLs(String model, String prompt, List<String> imageURLs, Options options)
1213 throws OllamaBaseException, IOException, InterruptedException, URISyntaxException {
1214 return generateWithImageURLs(model, prompt, imageURLs, options, null);
1215 }
1216
1237 public OllamaResult generateWithImages(String model, String prompt, List<byte[]> images, Options options,
1238 OllamaStreamHandler streamHandler) throws OllamaBaseException, IOException, InterruptedException {
1239 List<String> encodedImages = new ArrayList<>();
1240 for (byte[] image : images) {
1241 encodedImages.add(encodeByteArrayToBase64(image));
1242 }
1243 OllamaGenerateRequest ollamaRequestModel = new OllamaGenerateRequest(model, prompt, encodedImages);
1244 ollamaRequestModel.setOptions(options.getOptionsMap());
1245 return generateSyncForOllamaRequestModel(ollamaRequestModel, null, streamHandler);
1246 }
1247
1259 public OllamaResult generateWithImages(String model, String prompt, List<byte[]> images, Options options)
1260 throws OllamaBaseException, IOException, InterruptedException {
1261 return generateWithImages(model, prompt, images, options, null);
1262 }
1263
1284 public OllamaChatResult chat(String model, List<OllamaChatMessage> messages)
1285 throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
1287 return chat(builder.withMessages(messages).build());
1288 }
1289
1310 throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
1311 return chat(request, null, null);
1312 }
1313
1338 OllamaStreamHandler responseStreamHandler)
1339 throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
1340 return chatStreaming(request, new OllamaChatStreamObserver(thinkingStreamHandler, responseStreamHandler));
1341 }
1342
1363 throws OllamaBaseException, IOException, InterruptedException, ToolInvocationException {
1364 OllamaChatEndpointCaller requestCaller = new OllamaChatEndpointCaller(host, auth, requestTimeoutSeconds,
1365 verbose);
1366 OllamaChatResult result;
1367
1368 // add all registered tools to Request
1369 request.setTools(toolRegistry.getRegisteredSpecs().stream().map(Tools.ToolSpecification::getToolPrompt)
1370 .collect(Collectors.toList()));
1371
1372 if (tokenHandler != null) {
1373 request.setStream(true);
1374 result = requestCaller.call(request, tokenHandler);
1375 } else {
1376 result = requestCaller.callSync(request);
1377 }
1378
1379 // check if toolCallIsWanted
1380 List<OllamaChatToolCalls> toolCalls = result.getResponseModel().getMessage().getToolCalls();
1381 int toolCallTries = 0;
1382 while (toolCalls != null && !toolCalls.isEmpty() && toolCallTries < maxChatToolCallRetries) {
1383 for (OllamaChatToolCalls toolCall : toolCalls) {
1384 String toolName = toolCall.getFunction().getName();
1385 ToolFunction toolFunction = toolRegistry.getToolFunction(toolName);
1386 if (toolFunction == null) {
1387 throw new ToolInvocationException("Tool function not found: " + toolName);
1388 }
1389 Map<String, Object> arguments = toolCall.getFunction().getArguments();
1390 Object res = toolFunction.apply(arguments);
1391 String argumentKeys = arguments.keySet().stream()
1392 .map(Object::toString)
1393 .collect(Collectors.joining(", "));
1395 "[TOOL_RESULTS] " + toolName + "(" + argumentKeys + "): " + res + " [/TOOL_RESULTS]"));
1396 }
1397
1398 if (tokenHandler != null) {
1399 result = requestCaller.call(request, tokenHandler);
1400 } else {
1401 result = requestCaller.callSync(request);
1402 }
1403 toolCalls = result.getResponseModel().getMessage().getToolCalls();
1404 toolCallTries++;
1405 }
1406
1407 return result;
1408 }
1409
1418 public void registerTool(Tools.ToolSpecification toolSpecification) {
1419 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
1420 if (this.verbose) {
1421 logger.debug("Registered tool: {}", toolSpecification.getFunctionName());
1422 }
1423 }
1424
1435 public void registerTools(List<Tools.ToolSpecification> toolSpecifications) {
1436 for (Tools.ToolSpecification toolSpecification : toolSpecifications) {
1437 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
1438 }
1439 }
1440
1445 public void deregisterTools() {
1446 toolRegistry.clear();
1447 if (this.verbose) {
1448 logger.debug("All tools have been deregistered.");
1449 }
1450 }
1451
1465 try {
1466 Class<?> callerClass = null;
1467 try {
1468 callerClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
1469 } catch (ClassNotFoundException e) {
1470 throw new RuntimeException(e);
1471 }
1472
1473 OllamaToolService ollamaToolServiceAnnotation = callerClass.getDeclaredAnnotation(OllamaToolService.class);
1474 if (ollamaToolServiceAnnotation == null) {
1475 throw new IllegalStateException(callerClass + " is not annotated as " + OllamaToolService.class);
1476 }
1477
1478 Class<?>[] providers = ollamaToolServiceAnnotation.providers();
1479 for (Class<?> provider : providers) {
1480 registerAnnotatedTools(provider.getDeclaredConstructor().newInstance());
1481 }
1482 } catch (InstantiationException | NoSuchMethodException | IllegalAccessException
1483 | InvocationTargetException e) {
1484 throw new RuntimeException(e);
1485 }
1486 }
1487
1501 public void registerAnnotatedTools(Object object) {
1502 Class<?> objectClass = object.getClass();
1503 Method[] methods = objectClass.getMethods();
1504 for (Method m : methods) {
1505 ToolSpec toolSpec = m.getDeclaredAnnotation(ToolSpec.class);
1506 if (toolSpec == null) {
1507 continue;
1508 }
1509 String operationName = !toolSpec.name().isBlank() ? toolSpec.name() : m.getName();
1510 String operationDesc = !toolSpec.desc().isBlank() ? toolSpec.desc() : operationName;
1511
1512 final Tools.PropsBuilder propsBuilder = new Tools.PropsBuilder();
1513 LinkedHashMap<String, String> methodParams = new LinkedHashMap<>();
1514 for (Parameter parameter : m.getParameters()) {
1515 final ToolProperty toolPropertyAnn = parameter.getDeclaredAnnotation(ToolProperty.class);
1516 String propType = parameter.getType().getTypeName();
1517 if (toolPropertyAnn == null) {
1518 methodParams.put(parameter.getName(), null);
1519 continue;
1520 }
1521 String propName = !toolPropertyAnn.name().isBlank() ? toolPropertyAnn.name() : parameter.getName();
1522 methodParams.put(propName, propType);
1523 propsBuilder.withProperty(propName, Tools.PromptFuncDefinition.Property.builder().type(propType)
1524 .description(toolPropertyAnn.desc()).required(toolPropertyAnn.required()).build());
1525 }
1526 final Map<String, Tools.PromptFuncDefinition.Property> params = propsBuilder.build();
1527 List<String> reqProps = params.entrySet().stream().filter(e -> e.getValue().isRequired())
1528 .map(Map.Entry::getKey).collect(Collectors.toList());
1529
1530 Tools.ToolSpecification toolSpecification = Tools.ToolSpecification.builder().functionName(operationName)
1531 .functionDescription(operationDesc)
1532 .toolPrompt(Tools.PromptFuncDefinition.builder().type("function")
1533 .function(Tools.PromptFuncDefinition.PromptFuncSpec.builder().name(operationName)
1534 .description(operationDesc).parameters(Tools.PromptFuncDefinition.Parameters
1535 .builder().type("object").properties(params).required(reqProps).build())
1536 .build())
1537 .build())
1538 .build();
1539
1540 ReflectionalToolFunction reflectionalToolFunction = new ReflectionalToolFunction(object, m, methodParams);
1541 toolSpecification.setToolFunction(reflectionalToolFunction);
1542 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
1543 }
1544
1545 }
1546
1553 public OllamaChatMessageRole addCustomRole(String roleName) {
1554 return OllamaChatMessageRole.newCustomRole(roleName);
1555 }
1556
1562 public List<OllamaChatMessageRole> listRoles() {
1564 }
1565
1574 public OllamaChatMessageRole getRole(String roleName) throws RoleNotFoundException {
1575 return OllamaChatMessageRole.getRole(roleName);
1576 }
1577
1578 // technical private methods //
1579
1587 private static String encodeFileToBase64(File file) throws IOException {
1588 return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
1589 }
1590
1597 private static String encodeByteArrayToBase64(byte[] bytes) {
1598 return Base64.getEncoder().encodeToString(bytes);
1599 }
1600
1621 private OllamaResult generateSyncForOllamaRequestModel(OllamaGenerateRequest ollamaRequestModel,
1622 OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
1623 throws OllamaBaseException, IOException, InterruptedException {
1624 OllamaGenerateEndpointCaller requestCaller = new OllamaGenerateEndpointCaller(host, auth, requestTimeoutSeconds,
1625 verbose);
1626 OllamaResult result;
1627 if (responseStreamHandler != null) {
1628 ollamaRequestModel.setStream(true);
1629 result = requestCaller.call(ollamaRequestModel, thinkingStreamHandler, responseStreamHandler);
1630 } else {
1631 result = requestCaller.callSync(ollamaRequestModel);
1632 }
1633 return result;
1634 }
1635
1642 private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
1643 HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri)
1644 .header(Constants.HttpConstants.HEADER_KEY_CONTENT_TYPE, Constants.HttpConstants.APPLICATION_JSON)
1645 .timeout(Duration.ofSeconds(requestTimeoutSeconds));
1646 if (isBasicAuthCredentialsSet()) {
1647 requestBuilder.header("Authorization", auth.getAuthHeaderValue());
1648 }
1649 return requestBuilder;
1650 }
1651
1657 private boolean isBasicAuthCredentialsSet() {
1658 return auth != null;
1659 }
1660
1661 private Object invokeTool(ToolFunctionCallSpec toolFunctionCallSpec) throws ToolInvocationException {
1662 try {
1663 String methodName = toolFunctionCallSpec.getName();
1664 Map<String, Object> arguments = toolFunctionCallSpec.getArguments();
1665 ToolFunction function = toolRegistry.getToolFunction(methodName);
1666 if (verbose) {
1667 logger.debug("Invoking function {} with arguments {}", methodName, arguments);
1668 }
1669 if (function == null) {
1670 throw new ToolNotFoundException(
1671 "No such tool: " + methodName + ". Please register the tool before invoking it.");
1672 }
1673 return function.apply(arguments);
1674 } catch (Exception e) {
1675 throw new ToolInvocationException("Failed to invoke tool: " + toolFunctionCallSpec.getName(), e);
1676 }
1677 }
1678}
OllamaResult generateWithImageFiles(String model, String prompt, List< File > imageFiles, Options options, OllamaStreamHandler streamHandler)
OllamaChatResult chat(OllamaChatRequest request)
ModelDetail getModelDetails(String modelName)
List< Double > generateEmbeddings(OllamaEmbeddingsRequestModel modelRequest)
void setBearerAuth(String bearerToken)
OllamaResult generate(String model, String prompt, boolean raw, Options options, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
OllamaResult generateWithImages(String model, String prompt, List< byte[]> images, Options options, OllamaStreamHandler streamHandler)
OllamaChatResult chat(String model, List< OllamaChatMessage > messages)
OllamaAsyncResultStreamer generateAsync(String model, String prompt, boolean raw, boolean think)
List< Double > generateEmbeddings(String model, String prompt)
void pullModel(String modelName)
void setBasicAuth(String username, String password)
void deleteModel(String modelName, boolean ignoreIfNotPresent)
void createModelWithFilePath(String modelName, String modelFilePath)
ModelsProcessResponse ps()
LibraryModelTag findModelTagFromLibrary(String modelName, String tag)
OllamaChatMessageRole getRole(String roleName)
OllamaChatMessageRole addCustomRole(String roleName)
void pullModel(LibraryModelTag libraryModelTag)
OllamaResult generateWithImages(String model, String prompt, List< byte[]> images, Options options)
List< OllamaChatMessageRole > listRoles()
LibraryModelDetail getLibraryModelDetails(LibraryModel libraryModel)
OllamaResult generateWithImageURLs(String model, String prompt, List< String > imageURLs, Options options, OllamaStreamHandler streamHandler)
OllamaEmbedResponseModel embed(OllamaEmbedRequestModel modelRequest)
OllamaResult generate(String model, String prompt, boolean raw, boolean think, Options options)
void registerTool(Tools.ToolSpecification toolSpecification)
void registerAnnotatedTools(Object object)
OllamaResult generate(String model, String prompt, boolean raw, Options options, OllamaStreamHandler responseStreamHandler)
List< LibraryModel > listModelsFromLibrary()
void registerTools(List< Tools.ToolSpecification > toolSpecifications)
OllamaChatResult chatStreaming(OllamaChatRequest request, OllamaTokenHandler tokenHandler)
OllamaToolsResult generateWithTools(String model, String prompt, Options options)
void createModel(CustomModelRequest customModelRequest)
OllamaChatResult chat(OllamaChatRequest request, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
OllamaResult generateWithImageURLs(String model, String prompt, List< String > imageURLs, Options options)
OllamaEmbedResponseModel embed(String model, List< String > inputs)
void createModelWithModelFileContents(String modelName, String modelFileContents)
OllamaResult generateWithImageFiles(String model, String prompt, List< File > imageFiles, Options options)
static OllamaChatMessageRole newCustomRole(String roleName)
static OllamaChatMessageRole getRole(String roleName)
OllamaChatRequestBuilder withMessages(List< OllamaChatMessage > messages)
static OllamaChatRequestBuilder getInstance(String model)
OllamaChatResult call(OllamaChatRequest body, OllamaTokenHandler tokenHandler)
OllamaResult call(OllamaRequestBody body, OllamaStreamHandler thinkingStreamHandler, OllamaStreamHandler responseStreamHandler)
ToolFunction getToolFunction(String name)
static byte[] loadImageBytesFromUrl(String imageUrl)
Definition Utils.java:27
static ObjectMapper getObjectMapper()
Definition Utils.java:19
Object apply(Map< String, Object > arguments)