diff --git a/src/main/java/io/github/ollama4j/OllamaAPI.java b/src/main/java/io/github/ollama4j/OllamaAPI.java index e504d7e..0c89888 100644 --- a/src/main/java/io/github/ollama4j/OllamaAPI.java +++ b/src/main/java/io/github/ollama4j/OllamaAPI.java @@ -193,7 +193,7 @@ public class OllamaAPI { Elements modelSections = doc.selectXpath("//*[@id='repo']/ul/li/a"); for (Element e : modelSections) { LibraryModel model = new LibraryModel(); - Elements names = e.select("div > h2 > span"); + Elements names = e.select("div > h2 > div > span"); Elements desc = e.select("div > p"); Elements pullCounts = e.select("div:nth-of-type(2) > p > span:first-of-type > span:first-of-type"); Elements popularTags = e.select("div > div > span"); diff --git a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java index 7cdf879..c9882d0 100644 --- a/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/chat/OllamaChatRequestBuilder.java @@ -45,7 +45,7 @@ public class OllamaChatRequestBuilder { try { return Files.readAllBytes(file.toPath()); } catch (IOException e) { - LOG.warn(String.format("File '%s' could not be accessed, will not add to message!", file.toPath()), e); + LOG.warn("File '{}' could not be accessed, will not add to message!", file.toPath(), e); return new byte[0]; } }).collect(Collectors.toList()); @@ -63,9 +63,9 @@ public class OllamaChatRequestBuilder { try { binaryImages.add(Utils.loadImageBytesFromUrl(imageUrl)); } catch (URISyntaxException e) { - LOG.warn(String.format("URL '%s' could not be accessed, will not add to message!", imageUrl), e); + LOG.warn("URL '{}' could not be accessed, will not add to message!", imageUrl, e); } catch (IOException e) { - LOG.warn(String.format("Content of URL '%s' could not be read, will not add to message!", imageUrl), e); + LOG.warn("Content of URL '{}' could not be read, will not add to message!", imageUrl, e); } } } diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java new file mode 100644 index 0000000..7b85789 --- /dev/null +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbedRequestBuilder.java @@ -0,0 +1,40 @@ +package io.github.ollama4j.models.embeddings; + +import io.github.ollama4j.utils.Options; + +import java.util.List; + +/** + * Builderclass to easily create Requests for Embedding models using ollama. + */ +public class OllamaEmbedRequestBuilder { + + private final OllamaEmbedRequestModel request; + + private OllamaEmbedRequestBuilder(String model, List input) { + this.request = new OllamaEmbedRequestModel(model,input); + } + + public static OllamaEmbedRequestBuilder getInstance(String model, String... input){ + return new OllamaEmbedRequestBuilder(model, List.of(input)); + } + + public OllamaEmbedRequestBuilder withOptions(Options options){ + this.request.setOptions(options.getOptionsMap()); + return this; + } + + public OllamaEmbedRequestBuilder withKeepAlive(String keepAlive){ + this.request.setKeepAlive(keepAlive); + return this; + } + + public OllamaEmbedRequestBuilder withoutTruncate(){ + this.request.setTruncate(false); + return this; + } + + public OllamaEmbedRequestModel build() { + return this.request; + } +} diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java index 24d95bc..dcf7b47 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingResponseModel.java @@ -7,6 +7,7 @@ import lombok.Data; @SuppressWarnings("unused") @Data +@Deprecated(since="1.0.90") public class OllamaEmbeddingResponseModel { @JsonProperty("embedding") private List embedding; diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java index b542931..47daf75 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestBuilder.java @@ -2,6 +2,7 @@ package io.github.ollama4j.models.embeddings; import io.github.ollama4j.utils.Options; +@Deprecated(since="1.0.90") public class OllamaEmbeddingsRequestBuilder { private OllamaEmbeddingsRequestBuilder(String model, String prompt){ diff --git a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java index d700b91..d68624c 100644 --- a/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java +++ b/src/main/java/io/github/ollama4j/models/embeddings/OllamaEmbeddingsRequestModel.java @@ -12,6 +12,7 @@ import lombok.RequiredArgsConstructor; @Data @RequiredArgsConstructor @NoArgsConstructor +@Deprecated(since="1.0.90") public class OllamaEmbeddingsRequestModel { @NonNull private String model; diff --git a/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java b/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java index b875bf8..e3d3fc1 100644 --- a/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java +++ b/src/main/java/io/github/ollama4j/models/request/OllamaChatEndpointCaller.java @@ -1,7 +1,9 @@ package io.github.ollama4j.models.request; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; import io.github.ollama4j.exceptions.OllamaBaseException; +import io.github.ollama4j.models.chat.OllamaChatMessage; import io.github.ollama4j.models.response.OllamaResult; import io.github.ollama4j.models.chat.OllamaChatResponseModel; import io.github.ollama4j.models.chat.OllamaChatStreamObserver; @@ -31,13 +33,29 @@ public class OllamaChatEndpointCaller extends OllamaEndpointCaller { return "/api/chat"; } + /** + * Parses streamed Response line from ollama chat. + * Using {@link com.fasterxml.jackson.databind.ObjectMapper#readValue(String, TypeReference)} should throw + * {@link IllegalArgumentException} in case of null line or {@link com.fasterxml.jackson.core.JsonParseException} + * in case the JSON Object cannot be parsed to a {@link OllamaChatResponseModel}. Thus, the ResponseModel should + * never be null. + * + * @param line streamed line of ollama stream response + * @param responseBuffer Stringbuffer to add latest response message part to + * @return TRUE, if ollama-Response has 'done' state + */ @Override protected boolean parseResponseAndAddToBuffer(String line, StringBuilder responseBuffer) { try { OllamaChatResponseModel ollamaResponseModel = Utils.getObjectMapper().readValue(line, OllamaChatResponseModel.class); - responseBuffer.append(ollamaResponseModel.getMessage().getContent()); - if (streamObserver != null) { - streamObserver.notify(ollamaResponseModel); + // it seems that under heavy load ollama responds with an empty chat message part in the streamed response + // thus, we null check the message and hope that the next streamed response has some message content again + OllamaChatMessage message = ollamaResponseModel.getMessage(); + if(message != null) { + responseBuffer.append(message.getContent()); + if (streamObserver != null) { + streamObserver.notify(ollamaResponseModel); + } } return ollamaResponseModel.isDone(); } catch (JsonProcessingException e) { diff --git a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java b/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java index d584747..0a1da61 100644 --- a/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java +++ b/src/test/java/io/github/ollama4j/integrationtests/TestRealAPIs.java @@ -80,6 +80,18 @@ class TestRealAPIs { } } + @Test + @Order(2) + void testListModelsFromLibrary() { + testEndpointReachability(); + try { + assertNotNull(ollamaAPI.listModelsFromLibrary()); + ollamaAPI.listModelsFromLibrary().forEach(System.out::println); + } catch (IOException | OllamaBaseException | InterruptedException | URISyntaxException e) { + fail(e); + } + } + @Test @Order(2) void testPullModel() { diff --git a/src/test/java/io/github/ollama4j/unittests/jackson/TestEmbeddingsRequestSerialization.java b/src/test/java/io/github/ollama4j/unittests/jackson/TestEmbedRequestSerialization.java similarity index 55% rename from src/test/java/io/github/ollama4j/unittests/jackson/TestEmbeddingsRequestSerialization.java rename to src/test/java/io/github/ollama4j/unittests/jackson/TestEmbedRequestSerialization.java index 7cb0297..534b204 100644 --- a/src/test/java/io/github/ollama4j/unittests/jackson/TestEmbeddingsRequestSerialization.java +++ b/src/test/java/io/github/ollama4j/unittests/jackson/TestEmbedRequestSerialization.java @@ -1,36 +1,37 @@ package io.github.ollama4j.unittests.jackson; import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.github.ollama4j.models.embeddings.OllamaEmbedRequestBuilder; +import io.github.ollama4j.models.embeddings.OllamaEmbedRequestModel; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestModel; -import io.github.ollama4j.models.embeddings.OllamaEmbeddingsRequestBuilder; import io.github.ollama4j.utils.OptionsBuilder; -public class TestEmbeddingsRequestSerialization extends AbstractSerializationTest { +public class TestEmbedRequestSerialization extends AbstractSerializationTest { - private OllamaEmbeddingsRequestBuilder builder; + private OllamaEmbedRequestBuilder builder; @BeforeEach public void init() { - builder = OllamaEmbeddingsRequestBuilder.getInstance("DummyModel","DummyPrompt"); + builder = OllamaEmbedRequestBuilder.getInstance("DummyModel","DummyPrompt"); } @Test public void testRequestOnlyMandatoryFields() { - OllamaEmbeddingsRequestModel req = builder.build(); + OllamaEmbedRequestModel req = builder.build(); String jsonRequest = serialize(req); - assertEqualsAfterUnmarshalling(deserialize(jsonRequest,OllamaEmbeddingsRequestModel.class), req); + assertEqualsAfterUnmarshalling(deserialize(jsonRequest,OllamaEmbedRequestModel.class), req); } @Test public void testRequestWithOptions() { OptionsBuilder b = new OptionsBuilder(); - OllamaEmbeddingsRequestModel req = builder + OllamaEmbedRequestModel req = builder .withOptions(b.setMirostat(1).build()).build(); String jsonRequest = serialize(req); - OllamaEmbeddingsRequestModel deserializeRequest = deserialize(jsonRequest,OllamaEmbeddingsRequestModel.class); + OllamaEmbedRequestModel deserializeRequest = deserialize(jsonRequest,OllamaEmbedRequestModel.class); assertEqualsAfterUnmarshalling(deserializeRequest, req); assertEquals(1, deserializeRequest.getOptions().get("mirostat")); }