1package io.github.ollama4j;
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.Options;
26import io.github.ollama4j.utils.Utils;
28import org.jsoup.Jsoup;
29import org.jsoup.nodes.Document;
30import org.jsoup.nodes.Element;
31import org.jsoup.select.Elements;
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
36import java.lang.reflect.InvocationTargetException;
37import java.lang.reflect.Method;
38import java.lang.reflect.Parameter;
40import java.net.URISyntaxException;
41import java.net.http.HttpClient;
42import java.net.http.HttpConnectTimeoutException;
43import java.net.http.HttpRequest;
44import java.net.http.HttpResponse;
45import java.nio.charset.StandardCharsets;
46import java.nio.file.Files;
47import java.time.Duration;
49import java.util.stream.Collectors;
54@SuppressWarnings({
"DuplicatedCode",
"resource"})
57 private static final Logger logger = LoggerFactory.getLogger(
OllamaAPI.class);
58 private final String host;
64 private long requestTimeoutSeconds = 10;
70 private boolean verbose =
true;
73 private int maxChatToolCallRetries = 3;
83 this.host =
"http://localhost:11434";
92 if (host.endsWith(
"/")) {
93 this.host = host.substring(0, host.length() - 1);
98 logger.info(
"Ollama API initialized with host: " + this.host);
109 this.basicAuth =
new BasicAuth(username, password);
118 String url = this.host +
"/api/tags";
119 HttpClient httpClient = HttpClient.newHttpClient();
120 HttpRequest httpRequest =
null;
122 httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
123 }
catch (URISyntaxException e) {
124 throw new RuntimeException(e);
126 HttpResponse<String>
response =
null;
128 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
129 }
catch (HttpConnectTimeoutException e) {
131 }
catch (IOException | InterruptedException e) {
132 throw new RuntimeException(e);
134 int statusCode =
response.statusCode();
135 return statusCode == 200;
147 String url = this.host +
"/api/ps";
148 HttpClient httpClient = HttpClient.newHttpClient();
149 HttpRequest httpRequest =
null;
151 httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
152 }
catch (URISyntaxException e) {
153 throw new RuntimeException(e);
155 HttpResponse<String>
response =
null;
156 response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
157 int statusCode =
response.statusCode();
158 String responseString =
response.body();
159 if (statusCode == 200) {
176 String url = this.host +
"/api/tags";
177 HttpClient httpClient = HttpClient.newHttpClient();
178 HttpRequest httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
179 HttpResponse<String>
response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
180 int statusCode =
response.statusCode();
181 String responseString =
response.body();
182 if (statusCode == 200) {
200 String url =
"https://ollama.com/library";
201 HttpClient httpClient = HttpClient.newHttpClient();
202 HttpRequest httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
203 HttpResponse<String>
response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
204 int statusCode =
response.statusCode();
205 String responseString =
response.body();
206 List<LibraryModel> models =
new ArrayList<>();
207 if (statusCode == 200) {
208 Document doc = Jsoup.parse(responseString);
209 Elements modelSections = doc.selectXpath(
"//*[@id='repo']/ul/li/a");
210 for (Element e : modelSections) {
212 Elements names = e.select(
"div > h2 > div > span");
213 Elements desc = e.select(
"div > p");
214 Elements pullCounts = e.select(
"div:nth-of-type(2) > p > span:first-of-type > span:first-of-type");
215 Elements popularTags = e.select(
"div > div > span");
216 Elements totalTags = e.select(
"div:nth-of-type(2) > p > span:nth-of-type(2) > span:first-of-type");
217 Elements lastUpdatedTime = e.select(
"div:nth-of-type(2) > p > span:nth-of-type(3) > span:nth-of-type(2)");
219 if (names.first() ==
null || names.isEmpty()) {
223 Optional.ofNullable(names.first()).map(Element::text).ifPresent(model::setName);
224 model.setDescription(Optional.ofNullable(desc.first()).map(Element::text).orElse(
""));
225 model.setPopularTags(Optional.of(popularTags).map(tags -> tags.stream().map(Element::text).collect(Collectors.toList())).orElse(
new ArrayList<>()));
226 model.setPullCount(Optional.ofNullable(pullCounts.first()).map(Element::text).orElse(
""));
227 model.setTotalTags(Optional.ofNullable(totalTags.first()).map(Element::text).map(Integer::parseInt).orElse(0));
228 model.setLastUpdated(Optional.ofNullable(lastUpdatedTime.first()).map(Element::text).orElse(
""));
253 String url = String.format(
"https://ollama.com/library/%s/tags", libraryModel.getName());
254 HttpClient httpClient = HttpClient.newHttpClient();
255 HttpRequest httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
256 HttpResponse<String>
response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
257 int statusCode =
response.statusCode();
258 String responseString =
response.body();
260 List<LibraryModelTag> libraryModelTags =
new ArrayList<>();
261 if (statusCode == 200) {
262 Document doc = Jsoup.parse(responseString);
263 Elements tagSections = doc.select(
"html > body > main > div > section > div > div > div:nth-child(n+2) > div");
264 for (Element e : tagSections) {
265 Elements tags = e.select(
"div > a > div");
266 Elements tagsMetas = e.select(
"div > span");
270 if (tags.first() ==
null || tags.isEmpty()) {
274 libraryModelTag.setName(libraryModel.getName());
275 Optional.ofNullable(tags.first()).map(Element::text).ifPresent(libraryModelTag::setTag);
276 libraryModelTag.setSize(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split(
"•")).filter(parts -> parts.length > 1).map(parts -> parts[1].trim()).orElse(
""));
277 libraryModelTag.setLastUpdated(Optional.ofNullable(tagsMetas.first()).map(element -> element.text().split(
"•")).filter(parts -> parts.length > 1).map(parts -> parts[2].trim()).orElse(
""));
278 libraryModelTags.add(libraryModelTag);
281 libraryModelDetail.setModel(libraryModel);
282 libraryModelDetail.setTags(libraryModelTags);
283 return libraryModelDetail;
307 LibraryModel libraryModel = libraryModels.stream().filter(model -> model.getName().equals(modelName)).findFirst().orElseThrow(() ->
new NoSuchElementException(String.format(
"Model by name '%s' not found", modelName)));
309 LibraryModelTag libraryModelTag = libraryModelDetail.getTags().stream().filter(tagName -> tagName.getTag().equals(tag)).findFirst().orElseThrow(() ->
new NoSuchElementException(String.format(
"Tag '%s' for model '%s' not found", tag, modelName)));
310 return libraryModelTag;
324 String url = this.host +
"/api/pull";
326 HttpRequest
request = getRequestBuilderDefault(
new URI(url))
327 .POST(HttpRequest.BodyPublishers.ofString(jsonData))
328 .header(
"Accept",
"application/json")
329 .header(
"Content-type",
"application/json")
331 HttpClient client = HttpClient.newHttpClient();
332 HttpResponse<InputStream>
response = client.send(
request, HttpResponse.BodyHandlers.ofInputStream());
333 int statusCode =
response.statusCode();
334 InputStream responseBodyStream =
response.body();
335 String responseString =
"";
336 boolean success =
false;
337 try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
339 while ((line = reader.readLine()) !=
null) {
341 if (modelPullResponse !=
null && modelPullResponse.getStatus() !=
null) {
343 logger.info(modelName +
": " + modelPullResponse.getStatus());
346 if (
"success".equalsIgnoreCase(modelPullResponse.getStatus())) {
350 logger.error(
"Received null or invalid status for model pull.");
355 logger.error(
"Model pull failed or returned invalid status.");
358 if (statusCode != 200) {
365 String url = this.host +
"/api/version";
366 HttpClient httpClient = HttpClient.newHttpClient();
367 HttpRequest httpRequest = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").GET().build();
368 HttpResponse<String>
response = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
369 int statusCode =
response.statusCode();
370 String responseString =
response.body();
371 if (statusCode == 200) {
391 String tagToPull = String.format(
"%s:%s", libraryModelTag.getName(), libraryModelTag.getTag());
406 String url = this.host +
"/api/show";
408 HttpRequest
request = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
409 HttpClient client = HttpClient.newHttpClient();
410 HttpResponse<String>
response = client.send(
request, HttpResponse.BodyHandlers.ofString());
411 int statusCode =
response.statusCode();
412 String responseBody =
response.body();
413 if (statusCode == 200) {
433 String url = this.host +
"/api/create";
435 HttpRequest
request = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-Type",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
436 HttpClient client = HttpClient.newHttpClient();
437 HttpResponse<String>
response = client.send(
request, HttpResponse.BodyHandlers.ofString());
438 int statusCode =
response.statusCode();
439 String responseString =
response.body();
440 if (statusCode != 200) {
445 if (responseString.contains(
"error")) {
449 logger.info(responseString);
466 String url = this.host +
"/api/create";
468 HttpRequest
request = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-Type",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
469 HttpClient client = HttpClient.newHttpClient();
470 HttpResponse<String>
response = client.send(
request, HttpResponse.BodyHandlers.ofString());
471 int statusCode =
response.statusCode();
472 String responseString =
response.body();
473 if (statusCode != 200) {
476 if (responseString.contains(
"error")) {
480 logger.info(responseString);
495 String url = this.host +
"/api/create";
496 String jsonData = customModelRequest.toString();
497 HttpRequest
request = getRequestBuilderDefault(
new URI(url)).header(
"Accept",
"application/json").header(
"Content-Type",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).build();
498 HttpClient client = HttpClient.newHttpClient();
499 HttpResponse<String>
response = client.send(
request, HttpResponse.BodyHandlers.ofString());
500 int statusCode =
response.statusCode();
501 String responseString =
response.body();
502 if (statusCode != 200) {
505 if (responseString.contains(
"error")) {
509 logger.info(responseString);
524 String url = this.host +
"/api/delete";
526 HttpRequest
request = getRequestBuilderDefault(
new URI(url)).method(
"DELETE", HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8)).header(
"Accept",
"application/json").header(
"Content-type",
"application/json").build();
527 HttpClient client = HttpClient.newHttpClient();
528 HttpResponse<String>
response = client.send(
request, HttpResponse.BodyHandlers.ofString());
529 int statusCode =
response.statusCode();
530 String responseBody =
response.body();
531 if (statusCode == 404 && responseBody.contains(
"model") && responseBody.contains(
"not found")) {
534 if (statusCode != 200) {
567 URI uri = URI.create(this.host +
"/api/embeddings");
568 String jsonData = modelRequest.toString();
569 HttpClient httpClient = HttpClient.newHttpClient();
570 HttpRequest.Builder requestBuilder = getRequestBuilderDefault(uri).header(
"Accept",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData));
571 HttpRequest
request = requestBuilder.build();
572 HttpResponse<String>
response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString());
573 int statusCode =
response.statusCode();
574 String responseBody =
response.body();
575 if (statusCode == 200) {
577 return embeddingResponse.getEmbedding();
607 URI uri = URI.create(this.host +
"/api/embed");
609 HttpClient httpClient = HttpClient.newHttpClient();
611 HttpRequest
request = HttpRequest.newBuilder(uri).header(
"Accept",
"application/json").POST(HttpRequest.BodyPublishers.ofString(jsonData)).build();
613 HttpResponse<String>
response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString());
614 int statusCode =
response.statusCode();
615 String responseBody =
response.body();
617 if (statusCode == 200) {
641 ollamaRequestModel.setRaw(raw);
642 ollamaRequestModel.setOptions(options.getOptionsMap());
643 return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler);
661 return generate(model, prompt, raw, options,
null);
679 Map<ToolFunctionCallSpec, Object> toolResults =
new HashMap<>();
681 if (!prompt.startsWith(
"[AVAILABLE_TOOLS]")) {
684 promptBuilder.withToolSpecification(spec);
686 promptBuilder.withPrompt(prompt);
687 prompt = promptBuilder.build();
691 toolResult.setModelResult(result);
693 String toolsResponse = result.getResponse();
694 if (toolsResponse.contains(
"[TOOL_CALLS]")) {
695 toolsResponse = toolsResponse.replace(
"[TOOL_CALLS]",
"");
698 List<ToolFunctionCallSpec> toolFunctionCallSpecs =
new ArrayList<>();
701 if (!toolsResponse.isEmpty()) {
704 JsonNode jsonNode = objectMapper.readTree(toolsResponse);
705 }
catch (JsonParseException e) {
706 logger.warn(
"Response from model does not contain any tool calls. Returning the response as is.");
709 toolFunctionCallSpecs = objectMapper.readValue(
715 toolResults.put(toolFunctionCallSpec, invokeTool(toolFunctionCallSpec));
717 toolResult.setToolResults(toolResults);
732 ollamaRequestModel.setRaw(raw);
733 URI uri = URI.create(this.host +
"/api/generate");
735 ollamaAsyncResultStreamer.start();
736 return ollamaAsyncResultStreamer;
756 List<String> images =
new ArrayList<>();
757 for (File imageFile : imageFiles) {
758 images.add(encodeFileToBase64(imageFile));
761 ollamaRequestModel.setOptions(options.getOptionsMap());
762 return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler);
796 List<String> images =
new ArrayList<>();
797 for (String imageURL : imageURLs) {
801 ollamaRequestModel.setOptions(options.getOptionsMap());
802 return generateSyncForOllamaRequestModel(ollamaRequestModel, streamHandler);
895 request.setTools(toolRegistry.getRegisteredSpecs().stream().map(
Tools.ToolSpecification::getToolPrompt).collect(Collectors.toList()));
897 if (tokenHandler !=
null) {
899 result = requestCaller.
call(
request, tokenHandler);
905 List<OllamaChatToolCalls> toolCalls = result.getResponseModel().getMessage().getToolCalls();
906 int toolCallTries = 0;
907 while (toolCalls !=
null && !toolCalls.isEmpty() && toolCallTries < maxChatToolCallRetries) {
909 String toolName = toolCall.getFunction().getName();
910 ToolFunction toolFunction = toolRegistry.getToolFunction(toolName);
911 Map<String, Object> arguments = toolCall.getFunction().getArguments();
912 Object res = toolFunction.
apply(arguments);
916 if (tokenHandler !=
null) {
917 result = requestCaller.
call(
request, tokenHandler);
921 toolCalls = result.getResponseModel().getMessage().getToolCalls();
935 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
937 logger.debug(
"Registered tool: {}", toolSpecification.getFunctionName());
948 public void registerTools(List<Tools.ToolSpecification> toolSpecifications) {
950 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
964 Class<?> callerClass =
null;
966 callerClass = Class.forName(Thread.currentThread().getStackTrace()[2].getClassName());
967 }
catch (ClassNotFoundException e) {
968 throw new RuntimeException(e);
972 if (ollamaToolServiceAnnotation ==
null) {
973 throw new IllegalStateException(callerClass +
" is not annotated as " +
OllamaToolService.class);
976 Class<?>[] providers = ollamaToolServiceAnnotation.
providers();
977 for (Class<?> provider : providers) {
980 }
catch (InstantiationException | NoSuchMethodException | IllegalAccessException |
981 InvocationTargetException e) {
982 throw new RuntimeException(e);
995 Class<?> objectClass =
object.getClass();
996 Method[] methods = objectClass.getMethods();
997 for (Method m : methods) {
999 if (toolSpec ==
null) {
1002 String operationName = !toolSpec.
name().isBlank() ? toolSpec.
name() : m.getName();
1003 String operationDesc = !toolSpec.
desc().isBlank() ? toolSpec.
desc() : operationName;
1006 LinkedHashMap<String, String> methodParams =
new LinkedHashMap<>();
1007 for (Parameter parameter : m.getParameters()) {
1009 String propType = parameter.getType().getTypeName();
1010 if (toolPropertyAnn ==
null) {
1011 methodParams.put(parameter.getName(),
null);
1014 String propName = !toolPropertyAnn.
name().isBlank() ? toolPropertyAnn.
name() : parameter.getName();
1015 methodParams.put(propName, propType);
1019 List<String> reqProps = params.entrySet().stream().filter(e -> e.getValue().isRequired()).map(Map.Entry::getKey).collect(Collectors.toList());
1024 toolSpecification.setToolFunction(reflectionalToolFunction);
1025 toolRegistry.addTool(toolSpecification.getFunctionName(), toolSpecification);
1070 private static String encodeFileToBase64(File file)
throws IOException {
1071 return Base64.getEncoder().encodeToString(Files.readAllBytes(file.toPath()));
1080 private static String encodeByteArrayToBase64(
byte[] bytes) {
1081 return Base64.getEncoder().encodeToString(bytes);
1099 if (streamHandler !=
null) {
1100 ollamaRequestModel.setStream(
true);
1101 result = requestCaller.
call(ollamaRequestModel, streamHandler);
1103 result = requestCaller.
callSync(ollamaRequestModel);
1115 private HttpRequest.Builder getRequestBuilderDefault(URI uri) {
1116 HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(uri).header(
"Content-Type",
"application/json").timeout(Duration.ofSeconds(requestTimeoutSeconds));
1117 if (isBasicAuthCredentialsSet()) {
1118 requestBuilder.header(
"Authorization", getBasicAuthHeaderValue());
1120 return requestBuilder;
1128 private String getBasicAuthHeaderValue() {
1129 String credentialsToEncode = basicAuth.getUsername() +
":" + basicAuth.getPassword();
1130 return "Basic " + Base64.getEncoder().encodeToString(credentialsToEncode.getBytes());
1138 private boolean isBasicAuthCredentialsSet() {
1139 return basicAuth !=
null;
1144 String methodName = toolFunctionCallSpec.getName();
1145 Map<String, Object> arguments = toolFunctionCallSpec.getArguments();
1148 logger.debug(
"Invoking function {} with arguments {}", methodName, arguments);
1150 if (
function ==
null) {
1151 throw new ToolNotFoundException(
"No such tool: " + methodName +
". Please register the tool before invoking it.");
1153 return function.
apply(arguments);
1154 }
catch (Exception e) {
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)
List< Model > listModels()
OllamaAsyncResultStreamer generateAsync(String model, String prompt, boolean raw)
OllamaChatResult chat(String model, List< OllamaChatMessage > messages)
List< Double > generateEmbeddings(String model, String prompt)
void pullModel(String modelName)
void setBasicAuth(String username, String password)
OllamaResult generate(String model, String prompt, boolean raw, Options options, OllamaStreamHandler streamHandler)
OllamaChatResult chat(OllamaChatRequest request, OllamaStreamHandler streamHandler)
void deleteModel(String modelName, boolean ignoreIfNotPresent)
void createModelWithFilePath(String modelName, String modelFilePath)
OllamaResult generate(String model, String prompt, boolean raw, Options options)
ModelsProcessResponse ps()
LibraryModelTag findModelTagFromLibrary(String modelName, String tag)
OllamaChatMessageRole getRole(String roleName)
OllamaChatMessageRole addCustomRole(String roleName)
void pullModel(LibraryModelTag libraryModelTag)
List< OllamaChatMessageRole > listRoles()
LibraryModelDetail getLibraryModelDetails(LibraryModel libraryModel)
OllamaResult generateWithImageURLs(String model, String prompt, List< String > imageURLs, Options options, OllamaStreamHandler streamHandler)
OllamaEmbedResponseModel embed(OllamaEmbedRequestModel modelRequest)
void registerTool(Tools.ToolSpecification toolSpecification)
void registerAnnotatedTools(Object object)
void registerAnnotatedTools()
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)
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 List< OllamaChatMessageRole > getRoles()
static OllamaChatMessageRole newCustomRole(String roleName)
static OllamaChatMessageRole getRole(String roleName)
static final OllamaChatMessageRole TOOL
OllamaChatRequestBuilder withMessages(List< OllamaChatMessage > messages)
OllamaChatRequest build()
static OllamaChatRequestBuilder getInstance(String model)
OllamaChatResult call(OllamaChatRequest body, OllamaTokenHandler tokenHandler)
OllamaChatResult callSync(OllamaChatRequest body)
OllamaResult call(OllamaRequestBody body, OllamaStreamHandler streamHandler)
OllamaResult callSync(OllamaRequestBody body)
static byte[] loadImageBytesFromUrl(String imageUrl)
static ObjectMapper getObjectMapper()