Ollama4j
A Java library (wrapper/binding) for Ollama server.
Loading...
Searching...
No Matches
OllamaChatEndpointCaller.java
Go to the documentation of this file.
1/*
2 * Ollama4j - Java library for interacting with Ollama server.
3 * Copyright (c) 2025 Amith Koujalgi and contributors.
4 *
5 * Licensed under the MIT License (the "License");
6 * you may not use this file except in compliance with the License.
7 *
8*/
9package io.github.ollama4j.models.request;
10
11import com.fasterxml.jackson.core.JsonProcessingException;
12import com.fasterxml.jackson.core.type.TypeReference;
13import io.github.ollama4j.exceptions.OllamaException;
14import io.github.ollama4j.metrics.MetricsRecorder;
15import io.github.ollama4j.models.chat.*;
16import io.github.ollama4j.models.chat.OllamaChatTokenHandler;
17import io.github.ollama4j.models.response.OllamaErrorResponse;
18import io.github.ollama4j.utils.Utils;
19import java.io.BufferedReader;
20import java.io.IOException;
21import java.io.InputStream;
22import java.io.InputStreamReader;
23import java.net.URI;
24import java.net.http.HttpClient;
25import java.net.http.HttpRequest;
26import java.net.http.HttpResponse;
27import java.nio.charset.StandardCharsets;
28import java.util.List;
29import org.slf4j.Logger;
30import org.slf4j.LoggerFactory;
31
33@SuppressWarnings("resource")
35
36 private static final Logger LOG = LoggerFactory.getLogger(OllamaChatEndpointCaller.class);
37 public static final String endpoint = "/api/chat";
38
39 private OllamaChatTokenHandler tokenHandler;
40
41 public OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds) {
42 super(host, auth, requestTimeoutSeconds);
43 }
44
56 @Override
57 protected boolean parseResponseAndAddToBuffer(
58 String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
59 try {
60 OllamaChatResponseModel ollamaResponseModel =
61 Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
62 // It seems that under heavy load Ollama responds with an empty chat message part in the
63 // streamed response.
64 // Thus, we null check the message and hope that the next streamed response has some
65 // message content again.
66 OllamaChatMessage message = ollamaResponseModel.getMessage();
67 if (message != null) {
68 if (message.getThinking() != null) {
69 thinkingBuffer.append(message.getThinking());
70 } else {
71 responseBuffer.append(message.getResponse());
72 }
73 if (tokenHandler != null) {
74 tokenHandler.accept(ollamaResponseModel);
75 }
76 }
77 return ollamaResponseModel.isDone();
78 } catch (JsonProcessingException e) {
79 LOG.error("Error parsing the Ollama chat response!", e);
80 return true;
81 }
82 }
83
85 throws OllamaException, IOException, InterruptedException {
86 this.tokenHandler = tokenHandler;
87 return callSync(body);
88 }
89
91 throws OllamaException, IOException, InterruptedException {
92 long startTime = System.currentTimeMillis();
93 HttpClient httpClient = HttpClient.newHttpClient();
94 URI uri = URI.create(getHost() + endpoint);
95 HttpRequest.Builder requestBuilder =
96 getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
97 HttpRequest request = requestBuilder.build();
98 LOG.debug("Asking model: {}", body);
99 System.out.println("Asking model: " + Utils.toJSON(body));
100 HttpResponse<InputStream> response =
101 httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
102
103 int statusCode = response.statusCode();
104 InputStream responseBodyStream = response.body();
105 StringBuilder responseBuffer = new StringBuilder();
106 StringBuilder thinkingBuffer = new StringBuilder();
107 OllamaChatResponseModel ollamaChatResponseModel = null;
108 List<OllamaChatToolCalls> wantedToolsForStream = null;
109
110 try (BufferedReader reader =
111 new BufferedReader(
112 new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
113 String line;
114 while ((line = reader.readLine()) != null) {
115 if (handleErrorStatus(statusCode, line, responseBuffer)) {
116 continue;
117 }
118 boolean finished =
119 parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
120 ollamaChatResponseModel =
121 Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
122 if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
123 wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
124 }
125 if (finished && body.stream) {
126 ollamaChatResponseModel.getMessage().setResponse(responseBuffer.toString());
127 ollamaChatResponseModel.getMessage().setThinking(thinkingBuffer.toString());
128 break;
129 }
130 }
131 }
133 endpoint,
134 body.getModel(),
135 false,
136 body.isThink(),
137 body.isStream(),
138 body.getOptions(),
139 body.getFormat(),
140 startTime,
141 statusCode,
142 responseBuffer);
143 if (statusCode != 200) {
144 LOG.error("Status code: {}", statusCode);
145 System.out.println(responseBuffer);
146 throw new OllamaException(responseBuffer.toString());
147 }
148 if (wantedToolsForStream != null && ollamaChatResponseModel != null) {
149 ollamaChatResponseModel.getMessage().setToolCalls(wantedToolsForStream);
150 }
151 OllamaChatResult ollamaResult =
152 new OllamaChatResult(ollamaChatResponseModel, body.getMessages());
153 LOG.debug("Model response: {}", ollamaResult);
154 return ollamaResult;
155 }
156
161 private boolean handleErrorStatus(int statusCode, String line, StringBuilder responseBuffer)
162 throws IOException {
163 switch (statusCode) {
164 case 404:
165 LOG.warn("Status code: 404 (Not Found)");
166 responseBuffer.append(
168 .readValue(line, OllamaErrorResponse.class)
169 .getError());
170 return true;
171 case 401:
172 LOG.warn("Status code: 401 (Unauthorized)");
173 responseBuffer.append(
175 .readValue(
176 "{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class)
177 .getError());
178 return true;
179 case 400:
180 LOG.warn("Status code: 400 (Bad Request)");
181 responseBuffer.append(
183 .readValue(line, OllamaErrorResponse.class)
184 .getError());
185 return true;
186 case 500:
187 LOG.warn("Status code: 500 (Internal Server Error)");
188 responseBuffer.append(
190 .readValue(line, OllamaErrorResponse.class)
191 .getError());
192 return true;
193 default:
194 return false;
195 }
196 }
197}
static void record(String endpoint, String model, boolean raw, boolean thinking, boolean streaming, Map< String, Object > options, Object format, long startTime, int responseHttpStatus, Object response)
OllamaChatResult call(OllamaChatRequest body, OllamaChatTokenHandler tokenHandler)
OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds)
boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer)
static ObjectMapper getObjectMapper()
Definition Utils.java:32
static String toJSON(Object object)
Definition Utils.java:84