Ollama4j
A Java library (wrapper/binding) for Ollama server.
Loading...
Searching...
No Matches
OllamaChatEndpointCaller.java
Go to the documentation of this file.
1package io.github.ollama4j.models.request;
2
3import com.fasterxml.jackson.core.JsonProcessingException;
4import com.fasterxml.jackson.core.type.TypeReference;
5import io.github.ollama4j.exceptions.OllamaBaseException;
6import io.github.ollama4j.models.chat.*;
7import io.github.ollama4j.models.generate.OllamaTokenHandler;
8import io.github.ollama4j.models.response.OllamaErrorResponse;
9import io.github.ollama4j.utils.Utils;
10import org.slf4j.Logger;
11import org.slf4j.LoggerFactory;
12
13import java.io.BufferedReader;
14import java.io.IOException;
15import java.io.InputStream;
16import java.io.InputStreamReader;
17import java.net.URI;
18import java.net.http.HttpClient;
19import java.net.http.HttpRequest;
20import java.net.http.HttpResponse;
21import java.nio.charset.StandardCharsets;
22import java.util.List;
23
27@SuppressWarnings("resource")
29
30 private static final Logger LOG = LoggerFactory.getLogger(OllamaChatEndpointCaller.class);
31
32 private OllamaTokenHandler tokenHandler;
33
34 public OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds, boolean verbose) {
35 super(host, auth, requestTimeoutSeconds, verbose);
36 }
37
38 @Override
39 protected String getEndpointSuffix() {
40 return "/api/chat";
41 }
42
54 @Override
55 protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer) {
56 try {
57 OllamaChatResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
58 // it seems that under heavy load ollama responds with an empty chat message part in the streamed response
59 // thus, we null check the message and hope that the next streamed response has some message content again
60 OllamaChatMessage message = ollamaResponseModel.getMessage();
61 if (message != null) {
62 if (message.getThinking() != null) {
63 thinkingBuffer.append(message.getThinking());
64 }
65 else {
66 responseBuffer.append(message.getContent());
67 }
68 if (tokenHandler != null) {
69 tokenHandler.accept(ollamaResponseModel);
70 }
71 }
72 return ollamaResponseModel.isDone();
73 } catch (JsonProcessingException e) {
74 LOG.error("Error parsing the Ollama chat response!", e);
75 return true;
76 }
77 }
78
80 throws OllamaBaseException, IOException, InterruptedException {
81 this.tokenHandler = tokenHandler;
82 return callSync(body);
83 }
84
85 public OllamaChatResult callSync(OllamaChatRequest body) throws OllamaBaseException, IOException, InterruptedException {
86 // Create Request
87 HttpClient httpClient = HttpClient.newHttpClient();
88 URI uri = URI.create(getHost() + getEndpointSuffix());
89 HttpRequest.Builder requestBuilder =
91 .POST(
92 body.getBodyPublisher());
93 HttpRequest request = requestBuilder.build();
94 if (isVerbose()) LOG.info("Asking model: {}", body);
95 HttpResponse<InputStream> response =
96 httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
97
98 int statusCode = response.statusCode();
99 InputStream responseBodyStream = response.body();
100 StringBuilder responseBuffer = new StringBuilder();
101 StringBuilder thinkingBuffer = new StringBuilder();
102 OllamaChatResponseModel ollamaChatResponseModel = null;
103 List<OllamaChatToolCalls> wantedToolsForStream = null;
104 try (BufferedReader reader =
105 new BufferedReader(new InputStreamReader(responseBodyStream, StandardCharsets.UTF_8))) {
106
107 String line;
108 while ((line = reader.readLine()) != null) {
109 if (statusCode == 404) {
110 LOG.warn("Status code: 404 (Not Found)");
111 OllamaErrorResponse ollamaResponseModel =
112 Utils.getObjectMapper().readValue(line, OllamaErrorResponse.class);
113 responseBuffer.append(ollamaResponseModel.getError());
114 } else if (statusCode == 401) {
115 LOG.warn("Status code: 401 (Unauthorized)");
116 OllamaErrorResponse ollamaResponseModel =
118 .readValue("{\"error\":\"Unauthorized\"}", OllamaErrorResponse.class);
119 responseBuffer.append(ollamaResponseModel.getError());
120 } else if (statusCode == 400) {
121 LOG.warn("Status code: 400 (Bad Request)");
122 OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
123 OllamaErrorResponse.class);
124 responseBuffer.append(ollamaResponseModel.getError());
125 } else if (statusCode == 500) {
126 LOG.warn("Status code: 500 (Internal Server Error)");
127 OllamaErrorResponse ollamaResponseModel = Utils.getObjectMapper().readValue(line,
128 OllamaErrorResponse.class);
129 responseBuffer.append(ollamaResponseModel.getError());
130 } else {
131 boolean finished = parseResponseAndAddToBuffer(line, responseBuffer, thinkingBuffer);
132 ollamaChatResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class);
133 if (body.stream && ollamaChatResponseModel.getMessage().getToolCalls() != null) {
134 wantedToolsForStream = ollamaChatResponseModel.getMessage().getToolCalls();
135 }
136 if (finished && body.stream) {
137 ollamaChatResponseModel.getMessage().setContent(responseBuffer.toString());
138 ollamaChatResponseModel.getMessage().setThinking(thinkingBuffer.toString());
139 break;
140 }
141 }
142 }
143 }
144 if (statusCode != 200) {
145 LOG.error("Status code " + statusCode);
146 throw new OllamaBaseException(responseBuffer.toString());
147 } else {
148 if (wantedToolsForStream != null) {
149 ollamaChatResponseModel.getMessage().setToolCalls(wantedToolsForStream);
150 }
151 OllamaChatResult ollamaResult =
152 new OllamaChatResult(ollamaChatResponseModel, body.getMessages());
153 if (isVerbose()) LOG.info("Model response: " + ollamaResult);
154 return ollamaResult;
155 }
156 }
157}
OllamaChatResult call(OllamaChatRequest body, OllamaTokenHandler tokenHandler)
OllamaChatEndpointCaller(String host, Auth auth, long requestTimeoutSeconds, boolean verbose)
boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer, StringBuilder thinkingBuffer)
OllamaEndpointCaller(String host, Auth auth, long requestTimeoutSeconds, boolean verbose)
static ObjectMapper getObjectMapper()
Definition Utils.java:19