Skip to content

Commit 3b82fb6

Browse files
authored
Merge pull request #1072 from jpohlmeyer/fix-handle-mismatchedinputexception
Fix MismatchedInputException in Ollama streaming
2 parents 29d197e + 5c3742b commit 3b82fb6

File tree

1 file changed

+34
-30
lines changed
  • model-providers/ollama/runtime/src/main/java/io/quarkiverse/langchain4j/ollama

1 file changed

+34
-30
lines changed

model-providers/ollama/runtime/src/main/java/io/quarkiverse/langchain4j/ollama/OllamaRestApi.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import jakarta.ws.rs.Consumes;
1313
import jakarta.ws.rs.POST;
1414
import jakarta.ws.rs.Path;
15+
import jakarta.ws.rs.ProcessingException;
1516
import jakarta.ws.rs.Produces;
1617
import jakarta.ws.rs.WebApplicationException;
1718
import jakarta.ws.rs.client.ClientRequestContext;
@@ -85,40 +86,43 @@ class OllamaRestApiReaderInterceptor implements ReaderInterceptor {
8586
public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
8687
try {
8788
return context.proceed();
88-
} catch (ClientWebApplicationException e) {
89-
Throwable cause = e.getCause();
90-
if ((cause instanceof JsonParseException) || (cause instanceof MismatchedInputException)) {
91-
if (e.getResponse().getStatus() == 200) {
92-
Object invokedMethod = context.getProperty("org.eclipse.microprofile.rest.client.invokedMethod");
93-
if ((invokedMethod != null) && invokedMethod.toString().contains("OllamaRestApi.streamingChat")) {
94-
InputStream is = context.getInputStream();
95-
if (is instanceof ByteArrayInputStream bis) {
96-
bis.reset();
97-
String chunk = new String(bis.readAllBytes());
98-
final var ctx = Vertx.currentContext();
99-
if (ctx == null) {
100-
throw e;
101-
}
89+
} catch (ClientWebApplicationException | ProcessingException e) {
90+
// Depending on the Quarkus version MismatchedInputException could be wrapped in ProcessingException
91+
// or in WebApplicationException with Status 400.
92+
if ((e instanceof ProcessingException pe && pe.getCause() instanceof MismatchedInputException) ||
93+
(e instanceof WebApplicationException wae
94+
&& ((wae.getCause() instanceof JsonParseException && wae.getResponse().getStatus() == 200) ||
95+
(wae.getCause() instanceof MismatchedInputException
96+
&& wae.getResponse().getStatus() == 400)))) {
97+
Object invokedMethod = context.getProperty("org.eclipse.microprofile.rest.client.invokedMethod");
98+
if ((invokedMethod != null) && invokedMethod.toString().contains("OllamaRestApi.streamingChat")) {
99+
InputStream is = context.getInputStream();
100+
if (is instanceof ByteArrayInputStream bis) {
101+
bis.reset();
102+
String chunk = new String(bis.readAllBytes());
103+
final var ctx = Vertx.currentContext();
104+
if (ctx == null) {
105+
throw e;
106+
}
102107

103-
// This piece of code deals with is the case where a message from Ollama is not received as an entire line
104-
// but in pieces (my guess is that it is a Vertx bug).
105-
// There is nothing we can do in this case except for returning empty responses and in the meantime buffer the pieces
106-
// by storing them in the Vertx Duplicated Context
107-
String existingBuffer = ctx.getLocal("buffer");
108-
if ((existingBuffer != null) && !existingBuffer.isEmpty()) {
109-
if (chunk.endsWith("}")) {
110-
ctx.putLocal("buffer", "");
111-
String entireLine = existingBuffer + chunk;
112-
return QuarkusJsonCodecFactory.SnakeCaseObjectMapperHolder.MAPPER.readValue(entireLine,
113-
ChatResponse.class);
114-
} else {
115-
ctx.putLocal("buffer", existingBuffer + chunk);
116-
return ChatResponse.emptyNotDone();
117-
}
108+
// This piece of code deals with is the case where a message from Ollama is not received as an entire line
109+
// but in pieces (my guess is that it is a Vertx bug).
110+
// There is nothing we can do in this case except for returning empty responses and in the meantime buffer the pieces
111+
// by storing them in the Vertx Duplicated Context
112+
String existingBuffer = ctx.getLocal("buffer");
113+
if ((existingBuffer != null) && !existingBuffer.isEmpty()) {
114+
if (chunk.endsWith("}")) {
115+
ctx.putLocal("buffer", "");
116+
String entireLine = existingBuffer + chunk;
117+
return QuarkusJsonCodecFactory.SnakeCaseObjectMapperHolder.MAPPER.readValue(entireLine,
118+
ChatResponse.class);
118119
} else {
119-
ctx.putLocal("buffer", chunk);
120+
ctx.putLocal("buffer", existingBuffer + chunk);
120121
return ChatResponse.emptyNotDone();
121122
}
123+
} else {
124+
ctx.putLocal("buffer", chunk);
125+
return ChatResponse.emptyNotDone();
122126
}
123127
}
124128
}

0 commit comments

Comments
 (0)