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 HttpResponse<InputStream> response =
100 httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
101
102 int statusCode = response.statusCode();
103 InputStream responseBodyStream = response.body();
104 StringBuilder responseBuffer = new StringBuilder();
105 StringBuilder thinkingBuffer = new StringBuilder();
106 OllamaChatResponseModel ollamaChatResponseModel = null;
107 List<OllamaChatToolCalls> wantedToolsForStream = null;
108
109 try (BufferedReader reader =
110 new BufferedReader(
111 new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
112 String line;
113 while ((line = reader.readLine()) != null) {
114 if (handleErrorStatus(statusCode, line, responseBuffer)) {
115 continue;
116 }
117 boolean finished =
118 parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
119 ollamaChatResponseModel =
120 Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
121 if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
122 wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
123 }
124 if (finished && body.stream) {
125 ollamaChatResponseModel.getMessage().setResponse(responseBuffer.toString());
126 ollamaChatResponseModel.getMessage().setThinking(thinkingBuffer.toString());
127 break;
128 }
129 }
130 }
132 endpoint,
133 body.getModel(),
134 false,
135 body.isThink(),
136 body.isStream(),
137 body.getOptions(),
138 body.getFormat(),
139 startTime,
140 statusCode,
141 responseBuffer);
142 if (statusCode != 200) {
143 LOG.error("Status code: {}", statusCode);
144 throw new OllamaException(responseBuffer.toString());
145 }
146 if (wantedToolsForStream != null && ollamaChatResponseModel != null) {
147 ollamaChatResponseModel.getMessage().setToolCalls(wantedToolsForStream);
148 }
149 OllamaChatResult ollamaResult =
150 new OllamaChatResult(ollamaChatResponseModel, body.getMessages());
151 LOG.debug("Model response: {}", ollamaResult);
152 return ollamaResult;
153 }
154
159 private boolean handleErrorStatus(int statusCode, String line, StringBuilder responseBuffer)
160 throws IOException {
161 switch (statusCode) {
162 case 404:
163 LOG.warn("Status code: 404 (Not Found)");
164 responseBuffer.append(
166 .readValue(line, OllamaErrorResponse.class)
167 .getError());
168 return true;
169 case 401:
170 LOG.warn("Status code: 401 (Unauthorized)");
171 responseBuffer.append(
173 .readValue(
174 "{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class)
175 .getError());
176 return true;
177 case 400:
178 LOG.warn("Status code: 400 (Bad Request)");
179 responseBuffer.append(
181 .readValue(line, OllamaErrorResponse.class)
182 .getError());
183 return true;
184 case 500:
185 LOG.warn("Status code: 500 (Internal Server Error)");
186 responseBuffer.append(
188 .readValue(line, OllamaErrorResponse.class)
189 .getError());
190 return true;
191 default:
192 return false;
193 }
194 }
195}
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