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
59 @Override
60 protected boolean parseResponseAndAddToBuffer(
61 String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
62 try {
63 OllamaChatResponseModel ollamaResponseModel =
64 Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
65 // It seems that under heavy load Ollama responds with an empty chat message
66 // part in the
67 // streamed response.
68 // Thus, we null check the message and hope that the next streamed response has
69 // some
70 // message content again.
71 OllamaChatMessage message = ollamaResponseModel.getMessage();
72 if (message != null) {
73 if (message.getThinking() != null) {
74 thinkingBuffer.append(message.getThinking());
75 } else {
76 responseBuffer.append(message.getResponse());
77 }
78 if (tokenHandler != null) {
79 tokenHandler.accept(ollamaResponseModel);
80 }
81 }
82 return ollamaResponseModel.isDone();
83 } catch (JsonProcessingException e) {
84 LOG.error("Error parsing the Ollama chat response!", e);
85 return true;
86 }
87 }
88
90 throws OllamaException, IOException, InterruptedException {
91 this.tokenHandler = tokenHandler;
92 return callSync(body);
93 }
94
96 throws OllamaException, IOException, InterruptedException {
97 long startTime = System.currentTimeMillis();
98 HttpClient httpClient = HttpClient.newHttpClient();
99 URI uri = URI.create(getHost() + endpoint);
100 HttpRequest.Builder requestBuilder =
101 getRequestBuilderDefault(uri).POST(body.getBodyPublisher());
102 HttpRequest request = requestBuilder.build();
103 LOG.debug("Asking model: {}", body);
104 HttpResponse<InputStream> response =
105 httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
106
107 int statusCode = response.statusCode();
108 InputStream responseBodyStream = response.body();
109 StringBuilder responseBuffer = new StringBuilder();
110 StringBuilder thinkingBuffer = new StringBuilder();
111 OllamaChatResponseModel ollamaChatResponseModel = null;
112 List<OllamaChatToolCalls> wantedToolsForStream = null;
113
114 try (BufferedReader reader =
115 new BufferedReader(
116 new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
117 String line;
118 while ((line = reader.readLine()) != null) {
119 if (handleErrorStatus(statusCode, line, responseBuffer)) {
120 continue;
121 }
122 boolean finished =
123 parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
124 ollamaChatResponseModel =
125 Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
126 if (body.stream
127 && ollamaChatResponseModel.getMessage() != null
128 && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
129 wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
130 }
131 if (finished && body.stream) {
132 ollamaChatResponseModel.getMessage().setResponse(responseBuffer.toString());
133 ollamaChatResponseModel.getMessage().setThinking(thinkingBuffer.toString());
134 break;
135 }
136 }
137 }
139 endpoint,
140 body.getModel(),
141 false,
142 body.getThink(),
143 body.isStream(),
144 body.getOptions(),
145 body.getFormat(),
146 startTime,
147 statusCode,
148 responseBuffer);
149 if (statusCode != 200) {
150 LOG.error("Status code: {}", statusCode);
151 throw new OllamaException(responseBuffer.toString());
152 }
153 if (wantedToolsForStream != null && ollamaChatResponseModel != null) {
154 ollamaChatResponseModel.getMessage().setToolCalls(wantedToolsForStream);
155 }
156 OllamaChatResult ollamaResult =
157 new OllamaChatResult(ollamaChatResponseModel, body.getMessages());
158 LOG.debug("Model response: {}", ollamaResult);
159 return ollamaResult;
160 }
161
167 private boolean handleErrorStatus(int statusCode, String line, StringBuilder responseBuffer)
168 throws IOException {
169 switch (statusCode) {
170 case 404:
171 LOG.warn("Status code: 404 (Not Found)");
172 responseBuffer.append(
174 .readValue(line, OllamaErrorResponse.class)
175 .getError());
176 return true;
177 case 401:
178 LOG.warn("Status code: 401 (Unauthorized)");
179 responseBuffer.append(
181 .readValue(
182 "{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class)
183 .getError());
184 return true;
185 case 400:
186 LOG.warn("Status code: 400 (Bad Request)");
187 responseBuffer.append(
189 .readValue(line, OllamaErrorResponse.class)
190 .getError());
191 return true;
192 case 500:
193 LOG.warn("Status code: 500 (Internal Server Error)");
194 responseBuffer.append(
196 .readValue(line, OllamaErrorResponse.class)
197 .getError());
198 return true;
199 default:
200 return false;
201 }
202 }
203}
static void record(String endpoint, String model, boolean raw, ThinkMode thinkMode, 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